00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <map>
00027 #include <vector>
00028
00029 #include "stdpacs.h"
00030
00031 #include "pacs/collision_mesh_build.h"
00032 #include "pacs/local_retriever.h"
00033 #include "pacs/exterior_mesh.h"
00034
00035 #include "build_indoor.h"
00036
00037 using namespace std;
00038 using namespace NLMISC;
00039
00040 namespace NLPACS
00041 {
00042
00049 class CInteriorSurface
00050 {
00051 public:
00053 CCollisionMeshBuild *CollisionMeshBuild;
00054
00056 std::vector<uint32> Faces;
00057
00059 sint32 Id;
00060
00062 NLMISC::CVector Center;
00063
00065 sint32 Material;
00066
00067 public:
00068 CCollisionFace &getFace(uint face) { return CollisionMeshBuild->Faces[Faces[face]]; }
00069 CCollisionFace &getNeighbor(uint face, uint edge)
00070 {
00071 return CollisionMeshBuild->Faces[getFace(face).Edge[edge]];
00072 }
00073 };
00074
00075
00082 class CInteriorBorder
00083 {
00084 public:
00086 std::vector<NLMISC::CVector> Vertices;
00087
00089 sint32 Left, Right;
00090
00091 public:
00092 };
00093
00094
00095
00096 void buildSnapping(CCollisionMeshBuild &cmb, CLocalRetriever &lr);
00097
00098
00099
00100 void buildSurfaces(CCollisionMeshBuild &cmb, CLocalRetriever &lr);
00101
00102
00103
00104
00105
00106
00107
00108
00109 void floodFillSurfaces(CCollisionMeshBuild &cmb, vector<CInteriorSurface> &surfaces)
00110 {
00111 sint32 currentId = 0;
00112
00113 uint i;
00114
00115 for (i=0; i<cmb.Faces.size(); ++i)
00116 cmb.Faces[i].InternalSurface = -1;
00117
00118 for (i=0; i<cmb.Faces.size(); ++i)
00119 {
00120 CCollisionFace &face = cmb.Faces[i];
00121 if (face.Surface == CCollisionFace::ExteriorSurface || face.InternalSurface != -1)
00122 continue;
00123
00124 vector<uint> stack;
00125 stack.push_back(i);
00126 face.InternalSurface = currentId;
00127
00128 surfaces.resize(surfaces.size()+1);
00129 surfaces.back().Id = currentId;
00130 surfaces.back().CollisionMeshBuild = &cmb;
00131 surfaces.back().Material = face.Material;
00132
00133 while (!stack.empty())
00134 {
00135 uint pop = stack.back();
00136 stack.pop_back();
00137
00138 surfaces.back().Faces.push_back(pop);
00139 CCollisionFace &popFace = cmb.Faces[pop];
00140
00141 uint edge, neighb;
00142 for (edge=0; edge<3; ++edge)
00143 {
00144 if ((neighb = popFace.Edge[edge]) != -1 &&
00145 cmb.Faces[neighb].InternalSurface == -1 &&
00146 cmb.Faces[neighb].Surface == popFace.Surface)
00147 {
00148 cmb.Faces[neighb].InternalSurface = currentId;
00149 stack.push_back(neighb);
00150 }
00151 }
00152 }
00153
00154 ++currentId;
00155 }
00156 }
00157
00158
00159
00160 void resetEdgeFlags(CCollisionMeshBuild &cmb)
00161 {
00162 uint face, edge;
00163
00164 for (face=0; face<cmb.Faces.size(); ++face)
00165 for (edge=0; edge<3; ++edge)
00166 cmb.Faces[face].EdgeFlags[edge] = false;
00167 }
00168
00169
00170
00171
00172
00173 void followBorder(CInteriorSurface &surface, uint first, uint edge, uint sens, vector<CVector> &vstore, bool &loop)
00174 {
00175 CCollisionFace *current = &surface.getFace(first);
00176 CCollisionFace *next = (current->Edge[edge] == -1) ? NULL : &surface.CollisionMeshBuild->Faces[current->Edge[edge]];
00177 current->EdgeFlags[edge] = true;
00178 sint32 currentFace = surface.Faces[first];
00179
00180 const sint32 currentSurfId = current->InternalSurface;
00181 const sint32 oppositeSurfId = (next != NULL) ? next->InternalSurface : (current->Visibility[edge] ? -1 : -2);
00182 sint oedge;
00183
00184 sint pivot = (edge+sens)%3;
00185 sint nextEdge = edge;
00186
00187 bool allowThis = true;
00188
00189
00190 vstore.push_back(surface.CollisionMeshBuild->Vertices[current->V[pivot]]);
00191
00192 while (true)
00193 {
00194 loop = false;
00195
00196 sint32 thisOpposite = (next != NULL) ? next->InternalSurface : (current->Visibility[nextEdge] ? -1 : -2);
00197 if (thisOpposite != currentSurfId && thisOpposite != oppositeSurfId ||
00198 (loop = (current->EdgeFlags[nextEdge] && !allowThis)))
00199 {
00200
00201 break;
00202 }
00203 else if (thisOpposite == oppositeSurfId)
00204 {
00205
00206 current->EdgeFlags[nextEdge] = true;
00207 if (oppositeSurfId >= 0)
00208 {
00209 for (oedge=0; oedge<3 && next->Edge[oedge]!=currentFace; ++oedge)
00210 ;
00211 nlassert(oedge != 3);
00212 nlassert(allowThis || !next->EdgeFlags[oedge]);
00213 next->EdgeFlags[oedge] = true;
00214 }
00215 pivot = (pivot+sens)%3;
00216 nextEdge = (nextEdge+sens)%3;
00217 next = (current->Edge[nextEdge] == -1) ? NULL : &surface.CollisionMeshBuild->Faces[current->Edge[nextEdge]];
00218 vstore.push_back(surface.CollisionMeshBuild->Vertices[current->V[pivot]]);
00219 }
00220 else
00221 {
00222
00223 nlassert(next->InternalSurface == currentSurfId);
00224
00225 for (oedge=0; oedge<3 && next->Edge[oedge]!=currentFace; ++oedge)
00226 ;
00227 nlassert(oedge != 3);
00228 currentFace = current->Edge[nextEdge];
00229 current = next;
00230 pivot = (oedge+3-sens)%3;
00231 nextEdge = (oedge+sens)%3;
00232 next = (current->Edge[nextEdge] == -1) ? NULL : &surface.CollisionMeshBuild->Faces[current->Edge[nextEdge]];
00233 }
00234
00235 allowThis = false;
00236 }
00237 }
00238
00239
00240 void computeSurfaceBorders(CInteriorSurface &surface, vector<CInteriorBorder> &borders)
00241 {
00242 uint face, edge;
00243
00244 for (face=0; face<surface.Faces.size(); ++face)
00245 {
00246
00247
00248 CCollisionFace &cf = surface.getFace(face);
00249
00250 for (edge=0; edge<3; ++edge)
00251 {
00252 if ((cf.Edge[edge] == -1 || surface.getNeighbor(face, edge).InternalSurface != surface.Id) &&
00253 !cf.EdgeFlags[edge])
00254 {
00255 borders.resize(borders.size()+1);
00256 CInteriorBorder &border = borders.back();
00257
00258 border.Left = cf.InternalSurface;
00259
00260 if (cf.Edge[edge] == -1)
00261 {
00262
00263 border.Right = cf.Visibility[edge] ? -1 : -2;
00264 }
00265 else
00266 {
00267
00268 border.Right = surface.CollisionMeshBuild->Faces[cf.Edge[edge]].InternalSurface;
00269 }
00270
00271 nldebug("generate border %d (%d-%d)", borders.size()-1, border.Left, border.Right);
00272
00273 bool loop;
00274 vector<CVector> bwdVerts;
00275 vector<CVector> &fwdVerts = border.Vertices;
00276
00277 followBorder(surface, face, edge, 2, bwdVerts, loop);
00278
00279 sint i;
00280
00281 fwdVerts.reserve(bwdVerts.size());
00282 fwdVerts.clear();
00283
00284 for (i=(sint)(bwdVerts.size()-1); i>=0; --i)
00285 {
00286 fwdVerts.push_back(bwdVerts[i]);
00287 }
00288
00289 if (loop)
00290 {
00291 fwdVerts.push_back(fwdVerts.front());
00292 }
00293 else
00294 {
00295 fwdVerts.resize(fwdVerts.size()-2);
00296 followBorder(surface, face, edge, 1, fwdVerts, loop);
00297 }
00298 }
00299 }
00300 }
00301 }
00302
00303
00304 void computeSurfaceCenter(CInteriorSurface &surface)
00305 {
00306 CCollisionMeshBuild &cmb = *(surface.CollisionMeshBuild);
00307
00308 CVector center = CVector::Null;
00309 float totalWeight = 0.0f;
00310
00311 uint i, j;
00312
00313 for (i=0; i<surface.Faces.size(); ++i)
00314 {
00315 CCollisionFace &face = surface.getFace(i);
00316 CVector v[3];
00317
00318 for (j=0; j<3; ++j)
00319 v[j] = cmb.Vertices[face.V[j]];
00320
00321 float weight = ((v[2]-v[0])^(v[1]-v[0])).norm();
00322
00323 center += (v[0]+v[1]+v[2])*(weight/3.0f);
00324 totalWeight += weight;
00325 }
00326
00327 surface.Center = center/totalWeight;
00328 }
00329
00330
00331 void computeSurfaceQuadTree(CInteriorSurface &surface, CSurfaceQuadTree &quad)
00332 {
00333 uint i, j;
00334
00335 CAABBox box;
00336 bool first = true;
00337 for (i=0; i<surface.Faces.size(); ++i)
00338 {
00339 for (j=0; j<3; ++j)
00340 {
00341 const CVector &v = surface.CollisionMeshBuild->Vertices[surface.CollisionMeshBuild->Faces[surface.Faces[i]].V[j]];
00342 if (first)
00343 box.setCenter(v), first=false;
00344 else
00345 box.extend(v);
00346 }
00347 }
00348
00349 quad.clear();
00350 quad.init(4.0f, 6, box.getCenter(), std::max(box.getHalfSize().x, box.getHalfSize().y));
00351
00352 for (i=0; i<surface.Faces.size(); ++i)
00353 {
00354 for (j=0; j<3; ++j)
00355 {
00356 const CVector &v = surface.CollisionMeshBuild->Vertices[surface.CollisionMeshBuild->Faces[surface.Faces[i]].V[j]];
00357 quad.addVertex(v);
00358 }
00359 }
00360
00361 quad.compile();
00362 }
00363
00364
00365 void buildSurfaces(CCollisionMeshBuild &cmb, CLocalRetriever &lr)
00366 {
00367 vector<CInteriorSurface> surfaces;
00368 vector<CInteriorBorder> borders;
00369
00370 floodFillSurfaces(cmb, surfaces);
00371
00372 resetEdgeFlags(cmb);
00373
00374 uint surf, bord;
00375
00377 for (surf=0; surf<surfaces.size(); ++surf)
00378 {
00379 CSurfaceQuadTree quad;
00380 computeSurfaceBorders(surfaces[surf], borders);
00381 computeSurfaceCenter(surfaces[surf]);
00382 computeSurfaceQuadTree(surfaces[surf], quad);
00383 lr.addSurface(0, 0, (uint8)surfaces[surf].Material, 0, 0, false, 0.0f, surfaces[surf].Center, quad);
00384 }
00385
00386 sint numBorderChains = 0;
00387
00388 for (bord=0; bord<borders.size(); ++bord)
00389 {
00390 sint32 left = borders[bord].Left;
00391 sint32 right = (borders[bord].Right == -2) ? CChain::convertBorderChainId(numBorderChains++) : borders[bord].Right;
00392
00393 if (left<0 || left>=(sint)surfaces.size() ||
00394 right>(sint)surfaces.size())
00395 nlstop;
00396
00397 lr.addChain(borders[bord].Vertices, left, right);
00398 }
00399 }
00400
00401
00402
00403
00404 void buildSnapping(CCollisionMeshBuild &cmb, CLocalRetriever &lr)
00405 {
00406
00407 lr.getInteriorVertices() = cmb.Vertices;
00408
00409
00410 uint i;
00411 vector<CLocalRetriever::CInteriorFace> &faces = lr.getInteriorFaces();
00412 for (i=0; i<cmb.Faces.size(); ++i)
00413 {
00414 faces.push_back(CLocalRetriever::CInteriorFace());
00415 faces.back().Verts[0] = cmb.Faces[i].V[0];
00416 faces.back().Verts[1] = cmb.Faces[i].V[1];
00417 faces.back().Verts[2] = cmb.Faces[i].V[2];
00418 faces.back().Surface = cmb.Faces[i].InternalSurface;
00419 }
00420
00421
00422 lr.initFaceGrid();
00423 }
00424
00425
00426
00427
00428
00429
00430 void buildExteriorMesh(CCollisionMeshBuild &cmb, CExteriorMesh &em)
00431 {
00432
00433 uint i, edge;
00434 bool found = false;
00435 for (i=0; i<cmb.Faces.size() && !found; ++i)
00436 {
00437 if (cmb.Faces[i].Surface != CCollisionFace::ExteriorSurface)
00438 continue;
00439
00440 for (edge=0; edge<3 && !found; ++edge)
00441 if (cmb.Faces[i].Edge[edge] == -1)
00442 {
00443 found = true;
00444 break;
00445 }
00446
00447 if (found)
00448 break;
00449 }
00450
00451
00452 if (!found)
00453 return;
00454
00455 sint32 current = i;
00456 sint32 next = cmb.Faces[current].Edge[edge];
00457 for (i=0; i<cmb.Faces.size(); ++i)
00458 {
00459 cmb.Faces[i].EdgeFlags[0] = false;
00460 cmb.Faces[i].EdgeFlags[1] = false;
00461 cmb.Faces[i].EdgeFlags[2] = false;
00462 }
00463
00464 sint oedge;
00465 sint pivot = (edge+1)%3;
00466 sint nextEdge = edge;
00467
00468 bool allowThis = true;
00469
00470 vector<CExteriorMesh::CEdge> edges;
00471 uint numLink = 0;
00472
00473 while (true)
00474 {
00475 if (cmb.Faces[current].EdgeFlags[nextEdge])
00476 {
00477
00478 break;
00479 }
00480 else if (next == -1)
00481 {
00482
00483 cmb.Faces[current].EdgeFlags[nextEdge] = true;
00485 sint link = (cmb.Faces[current].Visibility[nextEdge]) ? -1 : (numLink++);
00486 edges.push_back(CExteriorMesh::CEdge(cmb.Vertices[cmb.Faces[current].V[pivot]], link));
00487 nldebug("border: vertex=%d (%.2f,%.2f,%.2f) link=%d", cmb.Faces[current].V[pivot], cmb.Vertices[cmb.Faces[current].V[pivot]].x, cmb.Vertices[cmb.Faces[current].V[pivot]].y, cmb.Vertices[cmb.Faces[current].V[pivot]].z, link);
00488 pivot = (pivot+1)%3;
00489 nextEdge = (nextEdge+1)%3;
00490 next = cmb.Faces[current].Edge[nextEdge];
00491 }
00492 else
00493 {
00494
00495 for (oedge=0; oedge<3 && cmb.Faces[next].Edge[oedge]!=current; ++oedge)
00496 ;
00497 nlassert(oedge != 3);
00498 current = next;
00499 pivot = (oedge+2)%3;
00500 nextEdge = (oedge+1)%3;
00501 next = cmb.Faces[current].Edge[nextEdge];
00502 }
00503 }
00504
00505 edges.push_back(edges.front());
00506 edges.back().Link = -1;
00507
00508 em.setEdges(edges);
00509 }
00510
00511
00512
00513 void linkExteriorToInterior(CLocalRetriever &lr)
00514 {
00515 CExteriorMesh em = lr.getExteriorMesh();
00516 vector<CExteriorMesh::CEdge> edges = em.getEdges();
00517 vector<CExteriorMesh::CLink> links;
00518 const vector<CChain> &chains = lr.getChains();
00519 const vector<COrderedChain3f> &ochains = lr.getFullOrderedChains();
00520 const vector<uint16> &bchains = lr.getBorderChains();
00521
00522 {
00523 uint i;
00524
00525 for (i=0; i<bchains.size(); ++i)
00526 {
00527 static char buf[512], w[256];
00528 const CChain &chain = chains[bchains[i]];
00529 sprintf(buf, "chain=%d ", bchains[i]);
00530 uint och;
00531 for (och=0; och<chain.getSubChains().size(); ++och)
00532 {
00533 const COrderedChain3f &ochain = ochains[chain.getSubChain(och)];
00534 sprintf(w, "subchain=%d", chain.getSubChain(och));
00535 strcat(buf, w);
00536 uint v;
00537 for (v=0; v<ochain.getVertices().size(); ++v)
00538 {
00539 sprintf(w, " (%.2f,%.2f)", ochain[v].x, ochain[v].y);
00540 strcat(buf, w);
00541 }
00542 }
00543
00544 nlinfo("%s", buf);
00545 }
00546 }
00547
00548 uint edge, ch;
00549 for (edge=0; edge+1<edges.size(); ++edge)
00550 {
00551 if (edges[edge].Link == -1)
00552 continue;
00553
00554 CVector start = edges[edge].Start, stop = edges[edge+1].Start;
00555 bool found = false;
00556
00557 for (ch=0; ch<bchains.size() && !found; ++ch)
00558 {
00559
00560
00561
00562 const CVector &cstart = lr.getStartVector(bchains[ch]),
00563 &cstop = lr.getStopVector(bchains[ch]);
00564
00565 float d = (start-cstart).norm()+(stop-cstop).norm();
00566 if (d < 1.0e-1f)
00567 {
00568 found = true;
00569 break;
00570 }
00571 }
00572
00573
00574 CExteriorMesh::CLink link;
00575
00576 if (!found)
00577 {
00578 nlwarning("in linkInteriorToExterior():");
00579 nlwarning("couldn't find any link to the exterior edge %d!!", edge);
00580 }
00581 else
00582 {
00583
00584 link.BorderChainId = ch;
00585 link.ChainId = bchains[ch];
00586 link.SurfaceId = (uint16)chains[link.ChainId].getLeft();
00587 }
00588
00589
00590 if (edges[edge].Link >= (sint)links.size())
00591 links.resize(edges[edge].Link+1);
00592
00593
00594 if (links[edges[edge].Link].BorderChainId != 0xFFFF ||
00595 links[edges[edge].Link].ChainId != 0xFFFF ||
00596 links[edges[edge].Link].SurfaceId != 0xFFFF)
00597 {
00598 nlwarning("in linkInteriorToExterior():");
00599 nlwarning("link %d already set!!", edges[edge].Link);
00600 }
00601
00602
00603 links[edges[edge].Link] = link;
00604 }
00605
00606 em.setEdges(edges);
00607 em.setLinks(links);
00608 lr.setExteriorMesh(em);
00609 }
00610
00611
00612
00613
00614
00615
00616 bool computeRetriever(CCollisionMeshBuild &cmb, CLocalRetriever &lr, CVector &translation, string &error, bool useCmbTrivialTranslation)
00617 {
00618
00619 lr.setType(CLocalRetriever::Interior);
00620
00621
00622 if (useCmbTrivialTranslation)
00623 {
00624 translation = cmb.computeTrivialTranslation();
00625
00626 translation.x = (float)ceil(translation.x);
00627 translation.y = (float)ceil(translation.y);
00628 translation.z = 0.0f;
00629 }
00630
00631 vector<string> errors;
00632
00633 cmb.link(false, errors);
00634 cmb.link(true, errors);
00635
00636 if (!errors.empty())
00637 {
00638 nlwarning("Edge issues reported !!");
00639 uint i;
00640 error = "";
00641 for (i=0; i<errors.size(); ++i)
00642 error += errors[i]+"\n";
00643 return false;
00644 }
00645
00646
00647 cmb.translate(translation);
00648
00649
00650 CExteriorMesh extMesh;
00651 buildExteriorMesh(cmb, extMesh);
00652 lr.setExteriorMesh(extMesh);
00653
00654
00655 buildSurfaces(cmb, lr);
00656
00657
00658
00659 buildSnapping(cmb, lr);
00660
00661
00662 lr.computeLoopsAndTips();
00663
00664 lr.findBorderChains();
00665 lr.updateChainIds();
00666 lr.computeTopologies();
00667
00668 lr.unify();
00669
00670 lr.computeCollisionChainQuad();
00671
00672
00673
00674
00675
00676
00677 linkExteriorToInterior(lr);
00678
00679
00680 uint i, j;
00681 CAABBox bbox;
00682 bool first = true;
00683
00684 for (i=0; i<extMesh.getEdges().size(); ++i)
00685 if (!first)
00686 bbox.extend(extMesh.getEdge(i).Start);
00687 else
00688 bbox.setCenter(extMesh.getEdge(i).Start), first=false;
00689
00690 for (i=0; i<lr.getOrderedChains().size(); ++i)
00691 for (j=0; j<lr.getOrderedChain(i).getVertices().size(); ++j)
00692 if (!first)
00693 bbox.extend(lr.getOrderedChain(i)[j].unpack3f());
00694 else
00695 bbox.setCenter(lr.getOrderedChain(i)[j].unpack3f()), first=false;
00696
00697 CVector bboxhs = bbox.getHalfSize();
00698 bboxhs.z = 10000.0f;
00699 bbox.setHalfSize(bboxhs);
00700
00701 lr.setBBox(bbox);
00702
00703 return true;
00704 }
00705
00706 }