build_indoor.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
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 // how to build interior snapping data
00094 void    buildSnapping(CCollisionMeshBuild &cmb, CLocalRetriever &lr);
00095 
00096 
00097 // how to build surfaces
00098 void    buildSurfaces(CCollisionMeshBuild &cmb, CLocalRetriever &lr);
00099 
00100 
00101 
00102 //
00103 // functions to build interior surfaces and borders from mesh
00104 //
00105 
00106 // how to generate connex surfaces
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 // reset the edge flags of the whole collision mesh build
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 // how to generate the borders of a given surface
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     // adds the pivot to the border and its normal
00188     vstore.push_back(surface.CollisionMeshBuild->Vertices[current->V[pivot]]);
00189 
00190     for(;;)
00191     {
00192         loop = false;
00193         // -1 means no neighbor at all, -2 means a neighbor that is not available yet
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             // if reaches the end of the border, then quits.
00199             break;
00200         }
00201         else if (thisOpposite == oppositeSurfId)
00202         {
00203             // if the next edge belongs to the border, then go on the same element
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             // if the next element is inside the surface, then go to the next element
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         // for each element,
00245         // scan for a edge that points to a different surface
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                     // link on a neighbor retriever or not at all
00261                     border.Right = cf.Visibility[edge] ? -1 : -2;
00262                 }
00263                 else
00264                 {
00265                     // link on the neighbor surface
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         //lr.addSurface(0, 0, (uint8)surfaces[surf].Material, 0, 0, false, 0.0f, /*false,*/ surfaces[surf].Center, quad);
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     // copy the vertices
00405     lr.getInteriorVertices() = cmb.Vertices;
00406 
00407     // create the faces
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     // create the face grid
00420     lr.initFaceGrid();
00421 }
00422 
00423 
00424 //
00425 // functions to build local retrievers
00426 //
00427 
00428 void    buildExteriorMesh(CCollisionMeshBuild &cmb, CExteriorMesh &em)
00429 {
00430     // find the first non interior face
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                 // if reaches the end of the border, then quits.
00483                 break;
00484             }
00485             else if (next == -1)
00486             {
00487                 // if the next edge belongs to the border, then go on the same element
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                 // if the next element is inside the surface, then go to the next element
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             // get the border chain.
00565             //const CChain  &chain = chains[bchains[ch]];
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         // create a link
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             // set it up to point on the chain and surface
00589             link.BorderChainId = uint16(ch);
00590             link.ChainId = bchains[ch];
00591             link.SurfaceId = (uint16)chains[link.ChainId].getLeft();
00592         }
00593 
00594         // enlarge the links
00595         if (edges[edge].Link >= (sint)links.size())
00596             links.resize(edges[edge].Link+1);
00597 
00598         // if the link already exists, warning
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         // setup the link
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     // set the retriever
00624     lr.setType(CLocalRetriever::Interior);
00625 
00626     // if should use the own cmb bbox, then compute it
00627     if (useCmbTrivialTranslation)
00628     {
00629         translation = cmb.computeTrivialTranslation();
00630         // snap the translation vector to a meter wide grid
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     // translate the meshbuild to the local axis
00652     cmb.translate(translation);
00653 
00654     // find the exterior mesh border
00655     CExteriorMesh   extMesh;
00656     buildExteriorMesh(cmb, extMesh);
00657     lr.setExteriorMesh(extMesh);
00658 
00659     // build the surfaces in the local retriever
00660     buildSurfaces(cmb, lr);
00661 
00662     // create the snapping faces and vertices
00663     // after the build surfaces because the InternalSurfaceId is filled within buildSurfaces()...
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     for (i=0; i<lr.getSurfaces().size(); ++i)
00679         lr.dumpSurface(i);
00680 */
00681     //
00682     linkExteriorToInterior(lr);
00683 
00684     // compute the bbox of the retriever
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 } // NLPACS
00712 

Generated on Thu Jan 7 08:26:36 2010 for NeL by  doxygen 1.6.1