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