global_retriever.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 "stdpacs.h"
00025 
00026 #include "nel/misc/path.h"
00027 #include "nel/misc/line.h"
00028 #include "nel/misc/async_file_manager.h"
00029 #include "nel/misc/common.h"
00030 #include "nel/misc/variable.h"
00031 
00032 #include "nel/misc/hierarchical_timer.h"
00033 
00034 #include "global_retriever.h"
00035 #include "retriever_bank.h"
00036 
00037 #include <set>
00038 
00039 
00040 #include "nel/misc/time_nl.h"
00041 NLMISC::TTicks          AStarTicks;
00042 NLMISC::TTicks          PathTicks;
00043 NLMISC::TTicks          ChainTicks;
00044 NLMISC::TTicks          SurfTicks;
00045 NLMISC::TTicks          ThisAStarTicks;
00046 NLMISC::TTicks          ThisPathTicks;
00047 NLMISC::TTicks          ThisChainTicks;
00048 NLMISC::TTicks          ThisSurfTicks;
00049 
00050 uint                    PacsRetrieveVerbose = 0;
00051 
00052 using namespace std;
00053 using namespace NLMISC;
00054 
00055 const float     InsureSurfaceThreshold = 0.5f;  // the threshold distance between 2 surfaces below which we insure the retrieved position to be inside the surface
00056 
00057 H_AUTO_DECL ( NLPACS_Refresh_LR_Around )
00058 H_AUTO_DECL ( NLPACS_Retrieve_Position )
00059 
00060 #define NLPACS_HAUTO_REFRESH_LR_AROUND  H_AUTO_USE ( NLPACS_Refresh_LR_Around )
00061 #define NLPACS_HAUTO_RETRIEVE_POSITION  H_AUTO_USE ( NLPACS_Retrieve_Position )
00062 
00063 // CGlobalRetriever methods implementation
00064 
00065 NLPACS::CGlobalRetriever::~CGlobalRetriever()
00066 {
00067     // must be sure all current async loading is ended
00068     waitEndOfAsyncLoading();
00069 }
00070 
00071 //
00072 void    NLPACS::CGlobalRetriever::init()
00073 {
00074     _BBox.setCenter(CVector::Null);
00075     _BBox.setHalfSize(CVector::Null);
00076 
00077     _InstanceGrid.create(128, 160.0f);
00078 }
00079 
00080 void    NLPACS::CGlobalRetriever::initQuadGrid()
00081 {
00082     _InstanceGrid.clear();
00083     _InstanceGrid.create(128, 160.0f);
00084 
00085     uint    i;
00086     for (i=0; i<_Instances.size(); ++i)
00087         _InstanceGrid.insert(_Instances[i].getBBox().getMin(), _Instances[i].getBBox().getMax(), i);
00088 }
00089 
00090 void    NLPACS::CGlobalRetriever::initRetrieveTable()
00091 {
00092     uint    i;
00093     uint    size = 0;
00094 
00095     for (i=0; i<_Instances.size(); ++i)
00096     {
00097         if (_Instances[i].getInstanceId() != -1 && _Instances[i].getRetrieverId() != -1)
00098         {
00099             const CLocalRetriever   &retriever = getRetriever(_Instances[i].getRetrieverId());
00100             size =  std::max((uint)retriever.getSurfaces().size(), size);
00101         }
00102     }
00103 
00104     _RetrieveTable.resize(size);
00105     for (i=0; i<size; ++i)
00106         _RetrieveTable[i] = 0;
00107 }
00108 
00109 //
00110 
00111 bool    NLPACS::CGlobalRetriever::selectInstances(const NLMISC::CAABBox &bbox, CCollisionSurfaceTemp &cst, UGlobalPosition::TType type) const
00112 {
00113     _InstanceGrid.select(bbox.getMin(), bbox.getMax());
00114     cst.CollisionInstances.clear();
00115 
00116     bool    allLoaded = true;
00117 
00118     NLPACS::CQuadGrid<uint32>::CIterator    it;
00119     for (it=_InstanceGrid.begin(); it!=_InstanceGrid.end(); ++it)
00120     {
00121         if ((type == UGlobalPosition::Landscape && _Instances[*it].getType() == CLocalRetriever::Interior) ||
00122             (type == UGlobalPosition::Interior && _Instances[*it].getType() == CLocalRetriever::Landscape))
00123             continue;
00124 
00125         if (_Instances[*it].getBBox().intersect(bbox))
00126         {
00127             if (!_RetrieverBank->isLoaded(_Instances[*it].getRetrieverId()))
00128                 allLoaded = false;
00129             cst.CollisionInstances.push_back(*it);
00130         }
00131     }
00132 
00133     return allLoaded;
00134 }
00135 
00136 //
00137 
00138 void    NLPACS::CGlobalRetriever::serial(NLMISC::IStream &f)
00139 {
00140     /*
00141     Version 0:
00142         - base version.
00143     */
00144     (void)f.serialVersion(0);
00145 
00146     f.serialCont(_Instances);
00147     f.serial(_BBox);
00148 
00149     if (f.isReading())
00150         initAll(false);
00151 }
00152 
00153 //
00154 
00155 void    NLPACS::CGlobalRetriever::check() const
00156 {
00157     uint    i, j, k;
00158 
00159     for (i=0; i<_Instances.size(); ++i)
00160     {
00161         if (_Instances[i].getInstanceId() == -1)
00162         {
00163             nlwarning("Uninitialized instance %d", i);
00164             continue;
00165         }
00166 
00167         if (_Instances[i].getInstanceId() != (sint)i)
00168             nlwarning("InstanceId for instance %d is not correctly initialized", i);
00169 
00170         if (_Instances[i].getRetrieverId() == -1)
00171         {
00172             nlwarning("No retriever at instance %d", i);
00173             continue;
00174         }
00175 
00176         const CRetrieverInstance    &instance = _Instances[i];
00177 
00178         if (instance.getRetrieverId()<0 || instance.getRetrieverId()>=(sint)_RetrieverBank->getRetrievers().size())
00179         {
00180             nlwarning("Instance %d has wrong retriever reference", i);
00181             continue;
00182         }
00183 
00184         const CLocalRetriever       &retriever = _RetrieverBank->getRetriever(instance.getRetrieverId());
00185 
00186         for (j=0; j<retriever.getChains().size(); ++j)
00187         {
00188             const CChain    &chain = retriever.getChain(j);
00189             for (k=0; k<chain.getSubChains().size(); ++k)
00190             {
00191                 if (chain.getSubChain(k) >= retriever.getOrderedChains().size())
00192                 {
00193                     nlwarning("retriever %d, chain %d: subchain %d reference is not valid", instance.getRetrieverId(), j, k);
00194                     continue;
00195                 }
00196 
00197                 if (retriever.getOrderedChain(chain.getSubChain(k)).getParentId() != j)
00198                 {
00199                     nlwarning("retriever %d, ochain %d: reference on parent is not valid", instance.getRetrieverId(), chain.getSubChain(k));
00200                     continue;
00201                 }
00202 
00203                 if (retriever.getOrderedChain(chain.getSubChain(k)).getIndexInParent() != k)
00204                 {
00205                     nlwarning("retriever %d, ochain %d: index on parent is not valid", instance.getRetrieverId(), chain.getSubChain(k));
00206                     continue;
00207                 }
00208             }
00209 
00210             if (chain.getLeft()<0 || chain.getLeft()>=(sint)retriever.getSurfaces().size())
00211             {
00212                 nlwarning("retriever %d, chain %d: reference on left surface is not valid", instance.getRetrieverId(), j);
00213             }
00214 
00215             if (chain.getRight()>=(sint)retriever.getSurfaces().size() ||
00216                 chain.getRight()<=CChain::getDummyBorderChainId() && !CChain::isBorderChainId(chain.getRight()))
00217             {
00218                 nlwarning("retriever %d, chain %d: reference on right surface is not valid", instance.getRetrieverId(), j);
00219             }
00220 
00221             if (CChain::isBorderChainId(chain.getRight()))
00222             {
00223                 sint    link = chain.getBorderChainIndex();
00224 
00225                 if (link<0 || link>=(sint)instance.getBorderChainLinks().size())
00226                 {
00227                     nlwarning("retriever %d, instance %d, chain %d: reference on right link is not valid", instance.getRetrieverId(), instance.getInstanceId(), j);
00228                 }
00229                 else
00230                 {
00231                     CRetrieverInstance::CLink   lnk = instance.getBorderChainLink(link);
00232 
00233                     if (lnk.Instance != 0xFFFF || lnk.SurfaceId != 0xFFFF ||
00234                         lnk.ChainId != 0xFFFF || lnk.BorderChainId != 0xFFFF)
00235                     {
00236                         if (lnk.Instance >= _Instances.size() ||
00237                             _Instances[lnk.Instance].getRetrieverId()<0 ||
00238                             _Instances[lnk.Instance].getRetrieverId()>(sint)_RetrieverBank->getRetrievers().size() ||
00239                             lnk.SurfaceId >= getRetriever(_Instances[lnk.Instance].getRetrieverId()).getSurfaces().size() ||
00240                             ((lnk.ChainId >= getRetriever(_Instances[lnk.Instance].getRetrieverId()).getChains().size() ||
00241                             lnk.BorderChainId >= getRetriever(_Instances[lnk.Instance].getRetrieverId()).getBorderChains().size()) && instance.getType() != CLocalRetriever::Interior ))
00242                         {
00243                             nlwarning("retriever %d, instance %d, link %d: reference on instance may be not valid [Inst=%d, Surf=%d, Chain=%d, BorderChain=%d]", instance.getRetrieverId(), instance.getInstanceId(), link, lnk.Instance, lnk.SurfaceId, lnk.ChainId, lnk.BorderChainId);
00244                         }
00245                     }
00246                 }
00247             }
00248         }
00249     }
00250 }
00251 
00252 //
00253 
00254 float   NLPACS::CGlobalRetriever::distanceToBorder(const UGlobalPosition &pos) const
00255 {
00256     if (pos.InstanceId < 0 || pos.InstanceId > (sint)_Instances.size())
00257         return 0.0f;
00258 
00259     return getRetriever(_Instances[pos.InstanceId].getRetrieverId()).distanceToBorder(pos.LocalPosition);
00260 }
00261 
00262 void    NLPACS::CGlobalRetriever::getBorders(const UGlobalPosition &pos, std::vector<std::pair<NLMISC::CLine, uint8> > &edges)
00263 {
00264     edges.clear();
00265 
00266     if (pos.InstanceId < 0)
00267         return;
00268 
00269     CVectorD        gpos = getDoubleGlobalPosition(pos);
00270     CAABBox         sbox;
00271     sbox.setCenter(gpos);
00272     sbox.setHalfSize(CVector(50.0f, 50.0f, 100.0f));
00273 
00274     getBorders(sbox, edges);
00275 }
00276 
00277 void    NLPACS::CGlobalRetriever::getBorders(const CAABBox &sbox, std::vector<std::pair<NLMISC::CLine, uint8> > &edges)
00278 {
00279     edges.clear();
00280 
00281     selectInstances(sbox, _InternalCST);
00282 
00283     uint    inst;
00284     for (inst=0; inst<_InternalCST.CollisionInstances.size(); ++inst)
00285     {
00286         CRetrieverInstance  &instance = _Instances[_InternalCST.CollisionInstances[inst]];
00287         CLocalRetriever     &retriever = const_cast<CLocalRetriever &>(getRetriever(instance.getRetrieverId()));
00288         if (!retriever.isLoaded())
00289             continue;
00290 
00291         CChainQuad          &chainquad = retriever.getChainQuad();
00292 
00293         CAABBox             box;
00294         CVector             origin = instance.getOrigin();
00295         box.setCenter(sbox.getCenter()-origin);
00296         box.setHalfSize(sbox.getHalfSize());
00297         chainquad.selectEdges(box, _InternalCST);
00298 
00299         uint        ece;
00300 
00301         CVector     dz(0.0f, 0.0f, 0.5f);
00302         float       zp = (float)sbox.getCenter().z;
00303         for (ece=0; ece<_InternalCST.EdgeChainEntries.size(); ++ece)
00304         {
00305             CEdgeChainEntry     &entry = _InternalCST.EdgeChainEntries[ece];
00306 
00307             //
00308             const CChain    &fchain = retriever.getChain(retriever.getOrderedChain(entry.OChainId).getParentId());
00309             uint8           chainType = (fchain.getRight() >= 0 ? 1 : (fchain.isBorderChain() ? 2 : 0));
00310 
00311             //
00312             if (chainType == 1)
00313             {
00314                 uint    left = fchain.getLeft();
00315                 uint    right = fchain.getRight();
00316 
00317                 const CRetrievableSurface   &lsurface = retriever.getSurface(left);
00318                 const CRetrievableSurface   &rsurface = retriever.getSurface(right);
00319 
00320                 bool    luw = (lsurface.getFlags() & (1 << CRetrievableSurface::IsUnderWaterBit)) != 0;
00321                 bool    ruw = (rsurface.getFlags() & (1 << CRetrievableSurface::IsUnderWaterBit)) != 0;
00322 
00323                 if (luw && !ruw || !luw && ruw)
00324                     chainType = 3;
00325             }
00326 
00327             if (retriever.getFullOrderedChains().size() > 0)
00328             {
00329                 const COrderedChain3f   &ochain = retriever.getFullOrderedChain(entry.OChainId);
00330 
00331                 uint    edge;
00332                 for (edge=entry.EdgeStart; edge<entry.EdgeEnd; ++edge)
00333                 {
00334                     edges.push_back(make_pair(CLine(), chainType));
00335                     edges.back().first.V0 = ochain[edge] + origin;
00336                     edges.back().first.V1 = ochain[edge+1] + origin;
00337 /*
00338                     edges.push_back(make_pair(CLine(), chainType));
00339                     edges.back().first.V0 = ochain[edge] + origin;
00340                     edges.back().first.V1 = ochain[edge] + origin +dz;
00341 
00342                     edges.push_back(make_pair(CLine(), chainType));
00343                     edges.back().first.V0 = ochain[edge+1] + origin;
00344                     edges.back().first.V1 = ochain[edge+1] + origin +dz;
00345 */
00346                 }
00347             }
00348             else
00349             {
00350                 const COrderedChain &ochain = retriever.getOrderedChain(entry.OChainId);
00351 
00352                 uint    edge;
00353                 for (edge=entry.EdgeStart; edge<entry.EdgeEnd; ++edge)
00354                 {
00355                     edges.push_back(make_pair(CLine(), chainType));
00356                     edges.back().first.V0 = ochain[edge].unpack3f() + origin;
00357                     edges.back().first.V0.z = zp;
00358                     edges.back().first.V1 = ochain[edge+1].unpack3f() + origin;
00359                     edges.back().first.V1.z = zp;
00360                 }
00361             }
00362         }
00363         // Bind edges for exterior mesh
00364         const CExteriorMesh &em = retriever.getExteriorMesh();
00365         const CExteriorMesh::CEdge *previousEdge = NULL;
00366         for(uint k = 0; k < em.getEdges().size(); ++k)
00367         {
00368             if (previousEdge)
00369             {
00370                 edges.push_back(make_pair(CLine(), previousEdge->Link < 0 ? 4 : 5));
00371                 edges.back().first.V0 = previousEdge->Start + origin;
00372                 edges.back().first.V1 = em.getEdges()[k].Start + origin;
00373             }
00374             previousEdge = em.getEdges()[k].Link != -2 ? &em.getEdges()[k] : NULL;
00375         }
00376     }
00377 }
00378 
00379 
00380 //
00381 
00382 void    NLPACS::CGlobalRetriever::makeLinks(uint n)
00383 {
00384     CRetrieverInstance  &instance = _Instances[n];
00385 
00386     selectInstances(instance.getBBox(), _InternalCST);
00387 
00388     uint    i;
00389     for (i=0; i<_InternalCST.CollisionInstances.size(); ++i)
00390     {
00391         CRetrieverInstance  &neighbor = _Instances[_InternalCST.CollisionInstances[i]];
00392 
00393         if (neighbor.getInstanceId() == instance.getInstanceId())
00394             continue;
00395 
00396         try
00397         {
00398             instance.link(neighbor, _RetrieverBank->getRetrievers());
00399             neighbor.link(instance, _RetrieverBank->getRetrievers());
00400         }
00401         catch (Exception &e)
00402         {
00403             nlwarning("in NLPACS::CGlobalRetriever::makeLinks()");
00404             nlwarning("caught an exception during linkage of %d and %d: %s", instance.getInstanceId(), neighbor.getInstanceId(), e.what());
00405         }
00406     }
00407 
00408     if (getRetriever(instance.getRetrieverId()).getType() == CLocalRetriever::Interior)
00409         instance.linkEdgeQuad(*this);
00410 }
00411 
00412 void    NLPACS::CGlobalRetriever::resetAllLinks()
00413 {
00414     uint    n;
00415     for (n=0; n<_Instances.size(); ++n)
00416         _Instances[n].unlink(_Instances);
00417 }
00418 
00419 
00420 void    NLPACS::CGlobalRetriever::makeAllLinks()
00421 {
00422     resetAllLinks();
00423 
00424     uint    n;
00425     for (n=0; n<_Instances.size(); ++n)
00426         makeLinks(n);
00427 }
00428 
00429 void    NLPACS::CGlobalRetriever::initAll(bool initInstances)
00430 {
00431     if (initInstances)
00432     {
00433         uint    n;
00434         for (n=0; n<_Instances.size(); ++n)
00435             if (_Instances[n].getInstanceId() != -1 && _Instances[n].getRetrieverId() != -1)
00436                 _Instances[n].init(_RetrieverBank->getRetriever(_Instances[n].getRetrieverId()));
00437     }
00438 
00439     initQuadGrid();
00440     initRetrieveTable();
00441 }
00442 
00443 //
00444 
00445 const NLPACS::CRetrieverInstance    &NLPACS::CGlobalRetriever::makeInstance(uint32 retrieverId, uint8 orientation, const CVector &origin)
00446 {
00447     uint    id;
00448     for (id=0; id<_Instances.size() && _Instances[id].getInstanceId()!=-1; ++id)
00449         ;
00450 
00451     if (id == _Instances.size())
00452         _Instances.resize(id+1);
00453 
00454     CRetrieverInstance      &instance = _Instances[id];
00455     const CLocalRetriever   &retriever = getRetriever(retrieverId);
00456 
00457     if (_RetrieveTable.size() < retriever.getSurfaces().size())
00458         _RetrieveTable.resize(retriever.getSurfaces().size(), 0);
00459 
00460     instance.make(id, retrieverId, retriever, orientation, origin);
00461 
00462     CVector hsize = instance.getBBox().getHalfSize();
00463     hsize.z = 0.0f;
00464     if (hsize != CVector::Null)
00465     {
00466         if (_BBox.getHalfSize() == CVector::Null)
00467         {
00468             _BBox = instance.getBBox();
00469         }
00470         else
00471         {
00472             _BBox.extend(instance.getBBox().getMin());
00473             _BBox.extend(instance.getBBox().getMax());
00474         }
00475 
00476         if (getRetriever(instance.getRetrieverId()).getType() == CLocalRetriever::Interior)
00477             instance.initEdgeQuad(*this);
00478 
00479         _InstanceGrid.insert(instance.getBBox().getMin(), instance.getBBox().getMax(), instance.getInstanceId());
00480     }
00481 
00482     return instance;
00483 }
00484 
00485 //
00486 
00487 NLPACS::UGlobalPosition NLPACS::CGlobalRetriever::retrievePosition(const CVector &estimated, float threshold) const
00488 {
00489     return retrievePosition(CVectorD(estimated), (double)threshold, UGlobalPosition::Unspecified);
00490 }
00491 
00492 NLPACS::UGlobalPosition NLPACS::CGlobalRetriever::retrievePosition(const CVectorD &estimated, double threshold) const
00493 {
00494     return retrievePosition(estimated, threshold, UGlobalPosition::Unspecified);
00495 }
00496 
00497 NLPACS::UGlobalPosition NLPACS::CGlobalRetriever::retrievePosition(const CVector &estimated) const
00498 {
00499     return retrievePosition(estimated, 1.0e10f, UGlobalPosition::Unspecified);
00500 }
00501 
00502 NLPACS::UGlobalPosition NLPACS::CGlobalRetriever::retrievePosition(const CVectorD &estimated) const
00503 {
00504     return retrievePosition(estimated, 1.0e10, UGlobalPosition::Unspecified);
00505 }
00506 
00507 // Retrieves the position of an estimated point in the global retriever (double instead.)
00508 NLPACS::UGlobalPosition NLPACS::CGlobalRetriever::retrievePosition(const CVectorD &estimated, double /* threshold */, NLPACS::UGlobalPosition::TType retrieveSpec) const
00509 {
00510     NLPACS_HAUTO_RETRIEVE_POSITION
00511 
00512     // the retrieved position
00513     CGlobalPosition             result = CGlobalPosition(-1, CLocalRetriever::CLocalPosition(-1, estimated));
00514 
00515     if (!_BBox.include(CVector((float)estimated.x, (float)estimated.y, (float)estimated.z)))
00516     {
00517         _ForbiddenInstances.clear();
00518         return result;
00519     }
00520 
00521 
00522     // get the best matching instances
00523     CAABBox bbpos;
00524     bbpos.setCenter(estimated);
00525     bbpos.setHalfSize(CVector(0.5f, 0.5f, 0.5f));
00526     if (!selectInstances(bbpos, _InternalCST, retrieveSpec))
00527     {
00528         return result;
00529     }
00530 
00531     uint    i;
00532 
00533     _InternalCST.SortedSurfaces.clear();
00534 
00535     // for each instance, try to retrieve the position
00536     for (i=0; i<_InternalCST.CollisionInstances.size(); ++i)
00537     {
00538         uint32                          id = _InternalCST.CollisionInstances[i];
00539         const CRetrieverInstance        &instance = _Instances[id];
00540         const CLocalRetriever           &retriever = _RetrieverBank->getRetriever(instance.getRetrieverId());
00541 
00542         uint    j;
00543         for (j=0; j<_ForbiddenInstances.size(); ++j)
00544             if (_ForbiddenInstances[j] == (sint32)id)
00545                 break;
00546 
00547         if (j<_ForbiddenInstances.size() || !retriever.isLoaded())
00548             continue;
00549 
00550         instance.retrievePosition(estimated, retriever, _InternalCST);
00551     }
00552 
00553     _ForbiddenInstances.clear();
00554 
00555     if (!_InternalCST.SortedSurfaces.empty())
00556     {
00557         // if there are some selected surfaces, sort them
00558         std::sort(_InternalCST.SortedSurfaces.begin(), _InternalCST.SortedSurfaces.end(), CCollisionSurfaceTemp::CDistanceSurface());
00559 
00560         uint    selInstance;
00561         float   bestDist = 1.0e10f;
00562         for (selInstance=0; selInstance<_InternalCST.SortedSurfaces.size(); ++selInstance)
00563         {
00564             uint32                      id = _InternalCST.SortedSurfaces[selInstance].Instance;
00565             const CRetrieverInstance    &instance = _Instances[id];
00566 
00567             if (instance.getType() == CLocalRetriever::Interior && _InternalCST.SortedSurfaces[selInstance].Distance < bestDist+6.0f)
00568                 break;
00569 
00570             if (selInstance == 0)
00571                 bestDist = _InternalCST.SortedSurfaces[0].Distance;
00572         }
00573 
00574         if (selInstance >= _InternalCST.SortedSurfaces.size())
00575             selInstance = 0;
00576 
00577         uint32                          id = _InternalCST.SortedSurfaces[selInstance].Instance;
00578         const CRetrieverInstance        &instance = _Instances[id];
00579         const CLocalRetriever           &retriever = _RetrieverBank->getRetriever(instance.getRetrieverId());
00580 
00581         // get the UGlobalPosition of the estimation for this surface
00582         result.InstanceId = id;
00583         result.LocalPosition.Surface = _InternalCST.SortedSurfaces[selInstance].Surface;
00584         result.LocalPosition.Estimation = instance.getLocalPosition(estimated);
00585 
00586         CRetrieverInstance::snapVector(result.LocalPosition.Estimation);
00587 
00588         // if there are more than 1 one possible (and best matching) surface, insure the position within the surface (by moving the point)
00589 //      if (_InternalCST.SortedSurfaces.size() >= 2 &&
00590 //          _InternalCST.SortedSurfaces[1].Distance-_InternalCST.SortedSurfaces[0].Distance < InsureSurfaceThreshold)
00591         if (_InternalCST.SortedSurfaces[selInstance].FoundCloseEdge)
00592         {
00593             bool    moved;
00594             uint    numMove = 0;
00595             do
00596             {
00597                 moved = retriever.insurePosition(result.LocalPosition);
00598                 ++numMove;
00599             }
00600             while (moved && numMove < 100);
00601             // the algo won't loop infinitely
00602 
00603             if (numMove > 1)
00604             {
00605                 nldebug("PACS: insured position inside surface (%d,%d)-(%f,%f,%f), %d moves needed", result.InstanceId, result.LocalPosition.Surface, estimated.x, estimated.y, estimated.z, numMove-1);
00606             }
00607 
00608             if (moved)
00609             {
00610                 nlwarning ("PACS: couldn't insure position (%.f,%.f) within the surface (surf=%d,inst=%d) after 100 retries", result.LocalPosition.Estimation.x, result.LocalPosition.Estimation.y, result.LocalPosition.Surface, result.InstanceId);
00611             }
00612         }
00613 
00614         // and after selecting the best surface (and some replacement) snap the point to the surface
00615         instance.snap(result.LocalPosition, retriever);
00616 
00617 
00618         if (PacsRetrieveVerbose)
00619             nlinfo("retrievePosition(%f,%f,%f) -> %d/%d/(%f,%f,%f) - %s/%s",
00620                     estimated.x, estimated.y, estimated.z,
00621                     result.InstanceId, result.LocalPosition.Surface,
00622                     result.LocalPosition.Estimation.x, result.LocalPosition.Estimation.y, result.LocalPosition.Estimation.z,
00623                     retriever.getIdentifier().c_str(),
00624                     retriever.getType() == CLocalRetriever::Interior ? "Interior" : "Landscape");
00625     }
00626     else
00627     {
00628         if (PacsRetrieveVerbose)
00629             nlwarning("PACS: unable to retrieve correct position (%f,%f,%f)", estimated.x, estimated.y, estimated.z);
00630 //      nlSleep(1);
00631     }
00632 
00633     return result;
00634 }
00635 
00636 //
00637 
00638 // Retrieves the position of an estimated point in the global retriever using layer hint
00639 NLPACS::UGlobalPosition NLPACS::CGlobalRetriever::retrievePosition(const CVectorD &estimated, uint h, sint &res) const
00640 {
00641     // the retrieved position
00642     CGlobalPosition             result = CGlobalPosition(-1, CLocalRetriever::CLocalPosition(-1, estimated));
00643 
00644     if (!_BBox.include(CVector((float)estimated.x, (float)estimated.y, (float)estimated.z)))
00645     {
00646         _ForbiddenInstances.clear();
00647         res = Failed;
00648         return result;
00649     }
00650 
00651 
00652     // get the best matching instances
00653     CAABBox bbpos;
00654     bbpos.setCenter(estimated);
00655     bbpos.setHalfSize(CVector(0.5f, 0.5f, 0.5f));
00656     bool    canGet = selectInstances(bbpos, _InternalCST);
00657 
00658     if (!canGet)
00659     {
00660         res = MissingLr;
00661         return result;
00662     }
00663 
00664     uint    i;
00665 
00666     _InternalCST.SortedSurfaces.clear();
00667 
00668     // for each instance, try to retrieve the position
00669     for (i=0; i<_InternalCST.CollisionInstances.size(); ++i)
00670     {
00671         uint32                          id = _InternalCST.CollisionInstances[i];
00672         const CRetrieverInstance        &instance = _Instances[id];
00673         const CLocalRetriever           &retriever = _RetrieverBank->getRetriever(instance.getRetrieverId());
00674 
00675         uint    j;
00676         for (j=0; j<_ForbiddenInstances.size(); ++j)
00677             if (_ForbiddenInstances[j] == (sint32)id)
00678                 break;
00679 
00680         if (j<_ForbiddenInstances.size() || !retriever.isLoaded())
00681             continue;
00682 
00683         instance.retrievePosition(estimated, retriever, _InternalCST, false);
00684     }
00685 
00686     _ForbiddenInstances.clear();
00687 
00688     if (!_InternalCST.SortedSurfaces.empty())
00689     {
00690         // if there are some selected surfaces, sort them
00691         std::sort(_InternalCST.SortedSurfaces.begin(), _InternalCST.SortedSurfaces.end(), CCollisionSurfaceTemp::CDistanceSurface());
00692 
00693         if (h >= _InternalCST.SortedSurfaces.size())
00694         {
00695             // found less surfaces than expected, abort
00696             res = Failed;
00697             return result;
00698         }
00699 
00700         uint32                          id = _InternalCST.SortedSurfaces[h].Instance;
00701         const CRetrieverInstance        &instance = _Instances[id];
00702         const CLocalRetriever           &retriever = _RetrieverBank->getRetriever(instance.getRetrieverId());
00703 
00704         // get the UGlobalPosition of the estimation for this surface
00705         result.InstanceId = id;
00706         result.LocalPosition.Surface = _InternalCST.SortedSurfaces[h].Surface;
00707         result.LocalPosition.Estimation = instance.getLocalPosition(estimated);
00708 
00709         CRetrieverInstance::snapVector(result.LocalPosition.Estimation);
00710 
00711         // if there are more than 1 one possible (and best matching) surface, insure the position within the surface (by moving the point)
00712 //      if (_InternalCST.SortedSurfaces.size() >= 2 &&
00713 //          _InternalCST.SortedSurfaces[1].Distance-_InternalCST.SortedSurfaces[0].Distance < InsureSurfaceThreshold)
00714         if (_InternalCST.SortedSurfaces[h].FoundCloseEdge)
00715         {
00716             bool    moved;
00717             uint    numMove = 0;
00718             do
00719             {
00720                 moved = retriever.insurePosition(result.LocalPosition);
00721                 ++numMove;
00722             }
00723             while (moved && numMove < 100);
00724             // the algo won't loop infinitely
00725 
00726             if (numMove > 1)
00727             {
00728                 nldebug("PACS: insured position inside surface (%d,%d)-(%f,%f,%f), %d moves needed", result.InstanceId, result.LocalPosition.Surface, estimated.x, estimated.y, estimated.z, numMove-1);
00729             }
00730 
00731             if (moved)
00732             {
00733                 nlwarning ("PACS: couldn't insure position (%.f,%.f) within the surface (surf=%d,inst=%d) after 100 retries", result.LocalPosition.Estimation.x, result.LocalPosition.Estimation.y, result.LocalPosition.Surface, result.InstanceId);
00734             }
00735         }
00736 
00737         // and after selecting the best surface (and some replacement) snap the point to the surface
00738         instance.snap(result.LocalPosition, retriever);
00739     }
00740     else
00741     {
00742         res = Failed;
00743 //      nlwarning("PACS: unable to retrieve correct position (%f,%f,%f)", estimated.x, estimated.y, estimated.z);
00744 //      nlSleep(1);
00745     }
00746 
00747     res = Success;
00748     return result;
00749 }
00750 
00751 
00752 //
00753 
00754 sint32          NLPACS::CGlobalRetriever::getIdentifier(const string &id) const
00755 {
00756     sint32  i;
00757     for (i=0; i<(sint32)(_RetrieverBank->getRetrievers().size()); ++i)
00758         if (getRetriever(i).getIdentifier() == id)
00759             return i;
00760 
00761     return -1;
00762 }
00763 
00764 const string    &NLPACS::CGlobalRetriever::getIdentifier(const NLPACS::UGlobalPosition &position) const
00765 {
00766     static const string     nullString = string("");
00767 
00768     if (position.InstanceId == -1)
00769         return nullString;
00770 
00771     return getRetriever(_Instances[position.InstanceId].getRetrieverId()).getIdentifier();
00772 }
00773 
00774 sint32  NLPACS::CGlobalRetriever::getLocalRetrieverId(const NLPACS::UGlobalPosition &position) const
00775 {
00776     if (position.InstanceId == -1)
00777         return -1;
00778 
00779     return _Instances[position.InstanceId].getRetrieverId();
00780 }
00781 
00782 //
00783 
00784 bool            NLPACS::CGlobalRetriever::buildInstance(const string &id, const NLMISC::CVectorD &position, sint32 &instanceId)
00785 {
00786 
00787     sint32  retrieverId = getIdentifier(id);
00788 
00789     instanceId = -1;
00790 
00791     // check retriever exists
00792     if (retrieverId < 0)
00793         return false;
00794 
00795     const CRetrieverInstance    &instance = makeInstance(retrieverId, 0, CVector(position));
00796 
00797     // check make instance success
00798     if (&instance == NULL || instance.getInstanceId() == -1 || instance.getRetrieverId() != retrieverId)
00799         return false;
00800 
00801     // links new instance to its neighbors
00802     makeLinks(instance.getInstanceId());
00803 
00804     instanceId = instance.getInstanceId();
00805 
00806     return true;
00807 }
00808 
00809 //
00810 
00811 void        NLPACS::CGlobalRetriever::removeInstance(sint32 instanceId)
00812 {
00813     if (instanceId < 0 || instanceId >= (sint32)_Instances.size() || _Instances[instanceId].getInstanceId() < 0)
00814     {
00815         nlwarning("CGlobalRetriever::removeInstance(): Can't unlink instance %d, doesn't exist", instanceId);
00816         return;
00817     }
00818 
00819     // get instance
00820     CRetrieverInstance  &instance = _Instances[instanceId];
00821 
00822     // unlink it from others
00823     instance.unlink(_Instances);
00824 
00825 
00826 }
00827 
00828 //
00829 
00830 //
00831 /*
00832 void        NLPACS::CGlobalRetriever::snapToInteriorGround(UGlobalPosition &position) const
00833 {
00834     const CRetrieverInstance    &instance = _Instances[position.InstanceId];
00835     if (instance.getType() != CLocalRetriever::Interior)
00836         return;
00837 
00838     const CLocalRetriever       &retriever = getRetriever(instance.getRetrieverId());
00839     instance.snapToInteriorGround(position.LocalPosition, retriever);
00840 }
00841 */
00842 
00843 //
00844 CVector     NLPACS::CGlobalRetriever::getGlobalPosition(const UGlobalPosition &global) const
00845 {
00846     if (global.InstanceId >= 0)
00847     {
00848         return _Instances[global.InstanceId].getGlobalPosition(global.LocalPosition.Estimation);
00849     }
00850     else
00851     {
00852         // it should be an error here
00853         return global.LocalPosition.Estimation;
00854     }
00855 }
00856 
00857 CVectorD    NLPACS::CGlobalRetriever::getDoubleGlobalPosition(const NLPACS::UGlobalPosition &global) const
00858 {
00859     if (global.InstanceId >= 0)
00860     {
00861         return _Instances[global.InstanceId].getDoubleGlobalPosition(global.LocalPosition.Estimation);
00862     }
00863     else
00864     {
00865         // it should be an error here
00866         return CVectorD(global.LocalPosition.Estimation);
00867     }
00868 }
00869 
00870 //
00871 
00872 void        NLPACS::CGlobalRetriever::findAStarPath(const NLPACS::UGlobalPosition &begin,
00873                                                     const NLPACS::UGlobalPosition &end,
00874                                                     vector<NLPACS::CRetrieverInstance::CAStarNodeAccess> &path,
00875                                                     uint32 forbidFlags) const
00876 {
00877     TTicks  astarStart;
00878     ThisAStarTicks = 0;
00879     astarStart = CTime::getPerformanceTime();
00880 
00881     // open and close lists
00882     // TODO: Use a smart allocator to avoid huge alloc/free and memory fragmentation
00883     // open is a priority queue (implemented as a stl multimap)
00884     multimap<float, CRetrieverInstance::CAStarNodeAccess>   open;
00885     // close is a simple stl vector
00886     vector<CRetrieverInstance::CAStarNodeAccess>            close;
00887 
00888     // inits start node and info
00889     CRetrieverInstance::CAStarNodeAccess                    beginNode;
00890     beginNode.InstanceId = begin.InstanceId;
00891     beginNode.NodeId = (uint16)begin.LocalPosition.Surface;
00892     CRetrieverInstance::CAStarNodeInfo                      &beginInfo = getNode(beginNode);
00893 
00894     // inits end node and info.
00895     CRetrieverInstance::CAStarNodeAccess                    endNode;
00896     endNode.InstanceId = end.InstanceId;
00897     endNode.NodeId = (uint16)end.LocalPosition.Surface;
00898     CRetrieverInstance::CAStarNodeInfo                      &endInfo = getNode(endNode);
00899 
00900     // set up first node...
00901     CRetrieverInstance::CAStarNodeAccess                    node = beginNode;
00902     beginInfo.Parent.InstanceId = -1;
00903     beginInfo.Parent.NodeId = 0;
00904     beginInfo.Parent.ThroughChain = 0;
00905     beginInfo.Cost = 0;
00906     beginInfo.F = (endInfo.Position-beginInfo.Position).norm();
00907 
00908     // ... and inserts it in the open list.
00909     open.insert(make_pair(beginInfo.F, node));
00910 
00911     // TO DO: use a CVector2f instead
00912     CVector2f                                               endPosition = CVector2f(getGlobalPosition(end));
00913 
00914     uint    i;
00915 
00916     path.clear();
00917 
00918     for(;;)
00919     {
00920         if (open.empty())
00921         {
00922             // couldn't find a path
00923             return;
00924         }
00925 
00926         multimap<float, CRetrieverInstance::CAStarNodeAccess>::iterator it;
00927 
00928         it = open.begin();
00929         node = it->second;
00930         open.erase(it);
00931 
00932         if (node == endNode)
00933         {
00934             // found a path
00935             CRetrieverInstance::CAStarNodeAccess            pathNode = node;
00936             uint                                            numNodes = 0;
00937             while (pathNode.InstanceId != -1)
00938             {
00939                 ++numNodes;
00940                 CRetrieverInstance                          &instance = _Instances[pathNode.InstanceId];
00941                 CRetrieverInstance::CAStarNodeInfo          &pathInfo = instance._NodesInformation[pathNode.NodeId];
00942                 pathNode = pathInfo.Parent;
00943             }
00944 
00945             path.resize(numNodes);
00946             pathNode = node;
00947             while (pathNode.InstanceId != -1)
00948             {
00949                 path[--numNodes] = pathNode;
00950                 CRetrieverInstance                          &instance = _Instances[pathNode.InstanceId];
00951                 CRetrieverInstance::CAStarNodeInfo          &pathInfo = instance._NodesInformation[pathNode.NodeId];
00952                 pathNode = pathInfo.Parent;
00953             }
00954 
00955             ThisAStarTicks += (CTime::getPerformanceTime()-astarStart);
00956 
00957             nlinfo("found a path");
00958             for (i=0; i<path.size(); ++i)
00959             {
00960                 CRetrieverInstance                          &instance = _Instances[path[i].InstanceId];
00961                 const CLocalRetriever                       &retriever = _RetrieverBank->getRetriever(instance.getRetrieverId());
00962                 nlinfo("pathNode %d = (Inst=%d, Node=%d, Through=%d)", i, path[i].InstanceId, path[i].NodeId, path[i].ThroughChain);
00963                 if (path[i].ThroughChain != 0xffff)
00964                 {
00965                     const CChain                                &chain = retriever.getChain(path[i].ThroughChain);
00966                     nlinfo("   chain: left=%d right=%d", chain.getLeft(), chain.getRight());
00967                     if (CChain::isBorderChainId(chain.getRight()))
00968                     {
00969                         CRetrieverInstance::CLink   lnk = instance.getBorderChainLink(CChain::convertBorderChainId(chain.getRight()));
00970                         sint    instanceid = lnk.Instance;
00971                         sint    id = lnk.SurfaceId;
00972                         nlinfo("      right: instance=%d surf=%d", instanceid, id);
00973                     }
00974                 }
00975             }
00976             nlinfo("open.size()=%d", open.size());
00977             nlinfo("close.size()=%d", close.size());
00978 
00979             return;
00980         }
00981 
00982         // push successors of the current node
00983         CRetrieverInstance                              &inst = _Instances[node.InstanceId];
00984         const CLocalRetriever                           &retriever = _RetrieverBank->getRetriever(inst.getRetrieverId());
00985         const CRetrievableSurface                       &surf = retriever.getSurface(node.NodeId);
00986         const vector<CRetrievableSurface::CSurfaceLink> &chains = surf.getChains();
00987 
00988         CRetrieverInstance                              *nextInstance;
00989         const CLocalRetriever                           *nextRetriever;
00990         const CRetrievableSurface                       *nextSurface;
00991 
00992         nlinfo("examine node (instance=%d,surf=%d,cost=%g)", node.InstanceId, node.NodeId, inst._NodesInformation[node.NodeId].Cost);
00993 
00994         for (i=0; i<chains.size(); ++i)
00995         {
00996             sint32  nextNodeId = chains[i].Surface;
00997             CRetrieverInstance::CAStarNodeAccess        nextNode;
00998 
00999             if (CChain::isBorderChainId(nextNodeId))
01000             {
01001                 // if the chain points to another retriever
01002 
01003                 // first get the edge on the retriever
01004                 CRetrieverInstance::CLink   lnk = inst.getBorderChainLink(CChain::convertBorderChainId(nextNodeId));
01005                 nextNode.InstanceId = lnk.Instance;
01006 
01007                 if (nextNode.InstanceId < 0)
01008                     continue;
01009 
01010                 nextInstance = &_Instances[nextNode.InstanceId];
01011                 nextRetriever = &(_RetrieverBank->getRetriever(nextInstance->getRetrieverId()));
01012 
01013                 sint    nodeId = lnk.SurfaceId;
01014                 nlassert(nodeId >= 0);
01015                 nextNode.NodeId = (uint16)nodeId;
01016             }
01017             else if (nextNodeId >= 0)
01018             {
01019                 // if the chain points to the same instance
01020                 nextNode.InstanceId = node.InstanceId;
01021                 nextNode.NodeId = (uint16) nextNodeId;
01022                 nextInstance = &inst;
01023                 nextRetriever = &retriever;
01024             }
01025             else
01026             {
01027                 // if the chain cannot be crossed
01028                 continue;
01029             }
01030 
01031             nextSurface = &(nextRetriever->getSurface(nextNode.NodeId));
01032 
01033             if (nextSurface->getFlags() & forbidFlags)
01034                 continue;
01035 
01036             // compute new node value (heuristic and cost)
01037 
01038             CRetrieverInstance::CAStarNodeInfo  &nextInfo = nextInstance->_NodesInformation[nextNode.NodeId];
01039             float   stepCost = (nextInfo.Position-inst._NodesInformation[node.NodeId].Position).norm();
01040             float   nextCost = inst._NodesInformation[node.NodeId].Cost+stepCost;
01041             float   nextHeuristic = (nextInfo.Position-endPosition).norm();
01042             float   nextF = nextCost+nextHeuristic;
01043 
01044             vector<CRetrieverInstance::CAStarNodeAccess>::iterator          closeIt;
01045             for (closeIt=close.begin(); closeIt!=close.end() && *closeIt!=nextNode; ++closeIt)
01046                 ;
01047 
01048             if (closeIt != close.end() && nextInfo.F < nextF)
01049                 continue;
01050 
01051             multimap<float, CRetrieverInstance::CAStarNodeAccess>::iterator openIt;
01052             for (openIt=open.begin(); openIt!=open.end() && openIt->second!=nextNode; ++openIt)
01053                 ;
01054 
01055             if (openIt != open.end() && nextInfo.F < nextF)
01056                 continue;
01057 
01058             if (openIt != open.end())
01059                 open.erase(openIt);
01060 
01061             if (closeIt != close.end())
01062                 close.erase(closeIt);
01063 
01064             nextInfo.Parent = node;
01065             nextInfo.Parent.ThroughChain = (uint16)(chains[i].Chain);
01066             nextInfo.Cost = nextCost;
01067             nextInfo.F = nextF;
01068 
01069             nlinfo("  adding node (instance=%d,surf=%d) f=%g, through=%d", nextNode.InstanceId, nextNode.NodeId, nextInfo.F, i);
01070 
01071             open.insert(make_pair(nextInfo.F, nextNode));
01072         }
01073         close.push_back(node);
01074     }
01075 }
01076 
01077 
01078 
01079 void    NLPACS::CGlobalRetriever::findPath(const NLPACS::UGlobalPosition &begin,
01080                                            const NLPACS::UGlobalPosition &end,
01081                                            NLPACS::CGlobalRetriever::CGlobalPath &path,
01082                                            uint32 forbidFlags) const
01083 {
01084 
01085     vector<CRetrieverInstance::CAStarNodeAccess>    astarPath;
01086     findAStarPath(begin, end, astarPath, forbidFlags);
01087 
01088     TTicks  surfStart;
01089     TTicks  chainStart;
01090 
01091     ThisChainTicks = 0;
01092     ThisSurfTicks = 0;
01093     ThisPathTicks = 0;
01094 
01095     path.clear();
01096     path.resize(astarPath.size());
01097 
01098     uint    i, j;
01099     for (i=0; i<astarPath.size(); ++i)
01100     {
01101         chainStart = CTime::getPerformanceTime();
01102         CLocalPath      &surf = path[i];
01103         surf.InstanceId = astarPath[i].InstanceId;
01104         const CLocalRetriever   &retriever = _RetrieverBank->getRetriever(_Instances[surf.InstanceId].getRetrieverId());
01105 
01106         // computes start point
01107         if (i == 0)
01108         {
01109             // if it is the first point, just copy the begin
01110             surf.Start.ULocalPosition::operator= (begin.LocalPosition);
01111         }
01112         else
01113         {
01114             // else, take the previous value and convert it in the current instance axis
01115             // TODO: avoid this if the instances are the same
01116             CVector prev = _Instances[path[i-1].InstanceId].getGlobalPosition(path[i-1].End.Estimation);
01117             CVector current = _Instances[surf.InstanceId].getLocalPosition(prev);
01118             surf.Start.Surface = astarPath[i].NodeId;
01119             surf.Start.Estimation = current;
01120         }
01121 
01122         // computes end point
01123         if (i == astarPath.size()-1)
01124         {
01125             surf.End.ULocalPosition::operator= (end.LocalPosition);
01126         }
01127         else
01128         {
01129             // get to the middle of the chain
01130             // first get the chain between the 2 surfaces
01131             const CChain            &chain = retriever.getChain(astarPath[i].ThroughChain);
01132             float                   cumulLength = 0.0f, midLength=chain.getLength()*0.5f;
01133             for (j=0; j<chain.getSubChains().size() && cumulLength<=midLength; ++j)
01134                 cumulLength += retriever.getOrderedChain(chain.getSubChain(j)).getLength();
01135             --j;
01136             const COrderedChain     &ochain = retriever.getOrderedChain(chain.getSubChain(j));
01137             surf.End.Surface = astarPath[i].NodeId;
01138             {
01139                 if (ochain.getVertices().size() & 1)
01140                 {
01141                     surf.End.Estimation = ochain[ochain.getVertices().size()/2].unpack3f();
01142                 }
01143                 else
01144                 {
01145                     surf.End.Estimation = (ochain[ochain.getVertices().size()/2].unpack3f()+
01146                                           ochain[ochain.getVertices().size()/2-1].unpack3f())*0.5f;
01147                 }
01148             }
01149         }
01150         ThisChainTicks += (CTime::getPerformanceTime()-chainStart);
01151 
01152         surfStart = CTime::getPerformanceTime();
01153         retriever.findPath(surf.Start, surf.End, surf.Path, _InternalCST);
01154         ThisSurfTicks += (CTime::getPerformanceTime()-surfStart);
01155     }
01156 
01157     ThisPathTicks = ThisAStarTicks+ThisChainTicks+ThisSurfTicks;
01158     PathTicks += ThisPathTicks;
01159     SurfTicks += ThisSurfTicks;
01160     AStarTicks += ThisAStarTicks;
01161     ChainTicks += ThisChainTicks;
01162 }
01163 
01164 
01165 // ***************************************************************************
01166 
01167 // ***************************************************************************
01168 // ***************************************************************************
01169 // Collisions part.
01170 // ***************************************************************************
01171 // ***************************************************************************
01172 
01173 
01174 
01175 // ***************************************************************************
01176 const NLPACS::CRetrievableSurface   *NLPACS::CGlobalRetriever::getSurfaceById(const NLPACS::CSurfaceIdent &surfId) const
01177 {
01178     if(surfId.RetrieverInstanceId>=0 && surfId.SurfaceId>=0)
01179     {
01180         sint32  locRetId= this->getInstance(surfId.RetrieverInstanceId).getRetrieverId();
01181         const CLocalRetriever       &retr = _RetrieverBank->getRetriever(locRetId);
01182         if (!retr.isLoaded() || surfId.SurfaceId >= (sint)retr.getSurfaces().size())
01183             return NULL;
01184         const CRetrievableSurface   &surf= retr.getSurface(surfId.SurfaceId);
01185         return &surf;
01186     }
01187     else
01188         return NULL;
01189 }
01190 
01191 
01192 
01193 // ***************************************************************************
01194 void    NLPACS::CGlobalRetriever::findCollisionChains(CCollisionSurfaceTemp &cst, const NLMISC::CAABBox &bboxMove, const NLMISC::CVector &origin) const
01195 {
01196 //  H_AUTO(PACS_GR_findCollisionChains);
01197 
01198     sint    i,j;
01199 
01200     // 0. reset.
01201     //===========
01202     // reset possible chains.
01203 //  H_BEFORE(PACS_GR_findCC_reset);
01204     cst.CollisionChains.clear();
01205     cst.resetEdgeCollideNodes();
01206 //  H_AFTER(PACS_GR_findCC_reset);
01207 
01208     // 1. Find Instances which may hit this movement.
01209     //===========
01210 //  H_BEFORE(PACS_GR_findCC_selectInstances);
01211     CAABBox     bboxMoveGlobal= bboxMove;
01212     bboxMoveGlobal.setCenter(bboxMoveGlobal.getCenter()+origin);
01213     selectInstances(bboxMoveGlobal, cst);
01214 //  H_AFTER(PACS_GR_findCC_selectInstances);
01215 
01216     // 2. Fill CollisionChains.
01217     //===========
01218     // For each possible surface mesh, test collision.
01219     for(i=0 ; i<(sint)cst.CollisionInstances.size(); i++)
01220     {
01221 //      H_BEFORE(PACS_GR_findCC_getAndComputeMove);
01222         // get retrieverInstance.
01223         sint32  curInstance= cst.CollisionInstances[i];
01224         const CRetrieverInstance    &retrieverInstance= getInstance(curInstance);
01225 
01226         // Retrieve the localRetriever of this instance.
01227         sint32  localRetrieverId= retrieverInstance.getRetrieverId();
01228         // If invalid one (hole), continue.
01229         if(localRetrieverId<0)
01230             continue;
01231         const CLocalRetriever       &localRetriever= _RetrieverBank->getRetriever(localRetrieverId);
01232 
01233         if (!localRetriever.isLoaded())
01234         {
01235             nlwarning("local retriever %d in %s not loaded, findCollisionChains in this retriever aborted", localRetrieverId, _RetrieverBank->getNamePrefix().c_str());
01236             continue;
01237         }
01238 
01239         // get delta between startPos.instance and curInstance.
01240         CVector     deltaOrigin;
01241         deltaOrigin= origin - retrieverInstance.getOrigin();
01242 
01243         // compute movement relative to this localRetriever.
01244         CAABBox     bboxMoveLocal= bboxMove;
01245         bboxMoveLocal.setCenter(bboxMoveLocal.getCenter()+deltaOrigin);
01246 
01247         // add possible collision chains with movement.
01248         //================
01249         sint        firstCollisionChain= cst.CollisionChains.size();
01250         CVector2f   transBase(-deltaOrigin.x, -deltaOrigin.y);
01251 //      H_AFTER(PACS_GR_findCC_getAndComputeMove);
01252 
01253 //      H_BEFORE(PACS_GR_findCC_testCollision);
01254         // Go! fill collision chains that this movement intersect.
01255         localRetriever.testCollision(cst, bboxMoveLocal, transBase);
01256         // if an interior, also test for external collisions
01257         if (retrieverInstance.getType() == CLocalRetriever::Interior)
01258             retrieverInstance.testExteriorCollision(cst, bboxMoveLocal, transBase, localRetriever);
01259 
01260         // how many collision chains added?  : nCollisionChain-firstCollisionChain.
01261         sint        nCollisionChain= cst.CollisionChains.size();
01262 //      H_AFTER(PACS_GR_findCC_testCollision);
01263 
01264 
01265         // For all collision chains added, fill good SurfaceIdent info.
01266         //================
01267 //      H_BEFORE(PACS_GR_findCC_fillSurfIdent);
01268         for(j=firstCollisionChain; j<nCollisionChain; j++)
01269         {
01270             CCollisionChain     &cc= cst.CollisionChains[j];
01271 
01272             // info are already filled for exterior chains.
01273             if (cc.ExteriorEdge)
01274                 continue;
01275 
01276             // LeftSurface retrieverInstance is always curInstance.
01277             cc.LeftSurface.RetrieverInstanceId= curInstance;
01278 
01279             // If RightSurface is not an "edgeId" ie a pointer on a neighbor surface on an other retrieverInstance.
01280             const   CChain      &originalChain= localRetriever.getChain(cc.ChainId);
01281             if( !originalChain.isBorderChainId(cc.RightSurface.SurfaceId) )
01282             {
01283                 cc.RightSurface.RetrieverInstanceId= curInstance;
01284             }
01285             else
01286             {
01287                 // we must find the surfaceIdent of the neighbor.
01288 
01289                 CRetrieverInstance::CLink   link;
01290                 // get the link to the next surface from the instance
01291                 link = retrieverInstance.getBorderChainLink(CChain::convertBorderChainId(cc.RightSurface.SurfaceId));
01292 
01293                 // get the neighbor instanceId.
01294                 sint    neighborInstanceId= (sint16)link.Instance;
01295                 // store in the current collisionChain Right.
01296                 cc.RightSurface.RetrieverInstanceId= neighborInstanceId;
01297 
01298                 // If no instance near us, this is a WALL.
01299                 if(neighborInstanceId<0)
01300                 {
01301                     // mark as a Wall.
01302                     cc.RightSurface.SurfaceId= -1;
01303                 }
01304                 else
01305                 {
01306                     // Get the good neighbor surfaceId.
01307                     cc.RightSurface.SurfaceId= (sint16)link.SurfaceId;
01308                 }
01309             }
01310 
01311             nlassert(cc.LeftSurface.RetrieverInstanceId < (sint)_Instances.size());
01312             nlassert(cc.RightSurface.RetrieverInstanceId < (sint)_Instances.size());
01313         }
01314 //      H_AFTER(PACS_GR_findCC_fillSurfIdent);
01315 
01316 
01317         // For all collision chains added, look if they are a copy of preceding collsion chain (same Left/Right). Then delete them.
01318         //================
01319 //      H_BEFORE(PACS_GR_findCC_removeDouble);
01320         for(j=firstCollisionChain; j<nCollisionChain; j++)
01321         {
01322             const CCollisionChain   &cj = cst.CollisionChains[j];
01323 
01324             if (cj.ExteriorEdge && cj.LeftSurface.RetrieverInstanceId!=-1)
01325                 continue;
01326 
01327             // test for all collisionChain inserted before.
01328             for(sint k=0; k<firstCollisionChain; k++)
01329             {
01330                 const CCollisionChain   &ck = cst.CollisionChains[k];
01331 
01332                 if (cj.LeftSurface.RetrieverInstanceId != cj.RightSurface.RetrieverInstanceId &&
01333                     cj.LeftSurface == ck.RightSurface && cj.RightSurface == ck.LeftSurface)
01334                 {
01335                     const CRetrieverInstance    &instj = getInstance(cj.LeftSurface.RetrieverInstanceId),
01336                                                 &instk = getInstance(ck.LeftSurface.RetrieverInstanceId);
01337                     const CLocalRetriever       &retrj = getRetriever(instj.getRetrieverId()),
01338                                                 &retrk = getRetriever(instk.getRetrieverId());
01339 
01340                     if (!retrj.isLoaded() || !retrk.isLoaded())
01341                     {
01342                         nlwarning("using not loaded retriever %d or %d in bank '%s', aborted", instj.getRetrieverId(), instk.getRetrieverId(), _RetrieverBank->getNamePrefix().c_str());
01343                         continue;
01344                     }
01345 
01346                     nlassert(retrj.getChain(cj.ChainId).isBorderChain() && retrk.getChain(ck.ChainId).isBorderChain());
01347 
01348                     if (instj.getBorderChainLink(retrj.getChain(cj.ChainId).getBorderChainIndex()).ChainId != ck.ChainId ||
01349                         instk.getBorderChainLink(retrk.getChain(ck.ChainId).getBorderChainIndex()).ChainId != cj.ChainId)
01350                     {
01351                         continue;
01352                     }
01353 
01354                     // remove this jth entry.
01355                     // by swapping with last entry. Only if not already last.
01356                     if(j<nCollisionChain-1)
01357                     {
01358                         swap(cst.CollisionChains[j], cst.CollisionChains[nCollisionChain-1]);
01359                         // NB: some holes remain in cst._EdgeCollideNodes, but do not matters since reseted at
01360                         // each collision test.
01361                     }
01362 
01363                     // pop last entry.
01364                     nCollisionChain--;
01365                     cst.CollisionChains.resize(nCollisionChain);
01366 
01367                     // next entry??
01368                     j--;
01369                     break;
01370                 }
01371 /*
01372                 // if same surface Ident Left/Right==Left/Right or swapped Left/Right==Right/Left
01373                 if( cst.CollisionChains[j].sameSurfacesThan(cst.CollisionChains[k]) )
01374                 {
01375                     // remove this jth entry.
01376                     // by swapping with last entry. Only if not already last.
01377                     if(j<nCollisionChain-1)
01378                     {
01379                         swap(cst.CollisionChains[j], cst.CollisionChains[nCollisionChain-1]);
01380                         // NB: some holes remain in cst._EdgeCollideNodes, but do not matters since reseted at
01381                         // each collision test.
01382                     }
01383 
01384                     // pop last entry.
01385                     nCollisionChain--;
01386                     cst.CollisionChains.resize(nCollisionChain);
01387 
01388                     // next entry??
01389                     j--;
01390                     break;
01391                 }
01392 */
01393             }
01394 
01395         }
01396 //      H_AFTER(PACS_GR_findCC_removeDouble);
01397     }
01398 
01399 }
01400 
01401 
01402 // ***************************************************************************
01403 void    NLPACS::CGlobalRetriever::testCollisionWithCollisionChains(CCollisionSurfaceTemp &cst, const CVector2f &startCol, const CVector2f &deltaCol,
01404         CSurfaceIdent startSurface, float radius, const CVector2f bboxStart[4], TCollisionType colType) const
01405 {
01406 //  H_AUTO(PACS_GR_testCollisionWithCollisionChains);
01407 
01408     // start currentSurface with surface start.
01409     CSurfaceIdent   currentSurface= startSurface;
01410     uint            nextCollisionSurfaceTested=0;
01411     sint            i;
01412 
01413     // reset result.
01414     cst.CollisionDescs.clear();
01415     // reset all collisionChain to not tested.
01416     for(i=0; i<(sint)cst.CollisionChains.size(); i++)
01417     {
01418         CCollisionChain     &colChain= cst.CollisionChains[i];
01419         colChain.Tested= false;
01420     }
01421 
01422     vector<pair<sint32, bool> > checkedExtEdges;
01423 
01424 
01425     /*
01426         To manage recovery, we must use such an algorithm, so we are sure to trace the way across all surfaces really
01427         collided, and discard any other (such as other floor or ceiling).
01428     */
01429     for(;;)
01430     {
01431         // run all collisionChain.
01432         //========================
01433         for(i=0; i<(sint)cst.CollisionChains.size(); i++)
01434         {
01435             CCollisionChain     &colChain= cst.CollisionChains[i];
01436 
01438             nlassert(colChain.LeftSurface.RetrieverInstanceId < (sint)_Instances.size());
01439             nlassert(colChain.RightSurface.RetrieverInstanceId < (sint)_Instances.size());
01440 
01441             // test only currentSurface/X. And don't test chains already tested before.
01442             if(colChain.hasSurface(currentSurface) && !colChain.Tested)
01443             {
01444                 // we are testing this chain.
01445                 colChain.Tested= true;
01446 
01447                 // avoid checking twice a door
01448                 if (colChain.ExteriorEdge && colChain.LeftSurface.RetrieverInstanceId != -1)
01449                 {
01450                     bool    enterInterior = (currentSurface.RetrieverInstanceId == colChain.RightSurface.RetrieverInstanceId);
01451 
01452                     uint    j;
01453                     sint32  cmp = (colChain.LeftSurface.RetrieverInstanceId<<16) + colChain.ChainId;
01454                     for (j=0; j<checkedExtEdges.size() && (checkedExtEdges[j].first != cmp); ++j)
01455                         ;
01456                     // if already crossed this edge, abort
01457                     // this a door that is crossing a surface frontier
01458                     if (j < checkedExtEdges.size())
01459                     {
01460                         if (checkedExtEdges[j].second != enterInterior)
01461                             continue;
01462                     }
01463                     else
01464                         checkedExtEdges.push_back(make_pair(cmp, enterInterior));
01465                 }
01466 
01467                 // test all edges of this chain, and get tmin
01468                 //========================
01469 
01470                 float       t=0.0, tMin=1;
01471                 CVector2f   normal, normalMin;
01472                 // run list of edge.
01473                 sint32      curEdge= colChain.FirstEdgeCollide;
01474                 while(curEdge!=(sint32)0xFFFFFFFF)
01475                 {
01476                     // get the edge.
01477                     CEdgeCollideNode    &colEdge= cst.getEdgeCollideNode(curEdge);
01478 
01479                     // test collision with this edge.
01480                     if(colType==CGlobalRetriever::Circle)
01481                         t= colEdge.testCircleMove(startCol, deltaCol, radius, normal);
01482                     else if(colType==CGlobalRetriever::BBox)
01483                         t= colEdge.testBBoxMove(startCol, deltaCol, bboxStart, normal);
01484 
01485                     // earlier collision??
01486                     if(t<tMin)
01487                     {
01488                         tMin= t;
01489                         normalMin= normal;
01490                     }
01491 
01492                     // next edge.
01493                     curEdge= colEdge.Next;
01494                 }
01495 
01496 
01497                 // If collision with this chain, must insert it in the array of collision.
01498                 //========================
01499                 if(tMin<1)
01500                 {
01501                     CSurfaceIdent   collidedSurface= colChain.getOtherSurface(currentSurface);
01502 
01503                     // if flag as an interior/landscape interface and leave interior surf, retrieve correct surface
01504                     if (colChain.ExteriorEdge && currentSurface == colChain.LeftSurface)
01505                     {
01506                         // p= position until the bounding object collide the exterior edge
01507                         CVector2f       p = startCol + deltaCol*tMin;
01508                         // get the interior origin
01509                         CVector         ori = getInstance(startSurface.RetrieverInstanceId).getOrigin();
01510                         ori.z = 0.0f;
01511 
01512                         // Estimate current Z
01513                         UGlobalPosition rp;
01514                         rp.InstanceId = currentSurface.RetrieverInstanceId;
01515                         rp.LocalPosition.Surface = currentSurface.SurfaceId;
01516                         rp.LocalPosition.Estimation = p;
01517                         // NB: getMeanHeight() should work here since we are still deep in the interior surface (edge collided with bounding volume)
01518                         float   estimatedZ= getMeanHeight(rp);
01519 
01520                         // retrieve the position, with the estimated Z
01521                         CVectorD        zp = CVectorD(p.x, p.y, estimatedZ) + CVectorD(ori);
01522                         // Do not allow the current interior instance
01523                         _ForbiddenInstances.clear();
01524                         _ForbiddenInstances.push_back(currentSurface.RetrieverInstanceId);
01525                         UGlobalPosition gp = retrievePosition(zp);
01526 
01527                         collidedSurface.RetrieverInstanceId = gp.InstanceId;
01528                         collidedSurface.SurfaceId = gp.LocalPosition.Surface;
01529                     }
01530 
01532                     nlassert(collidedSurface.RetrieverInstanceId < (sint)_Instances.size());
01533 
01534                     // insert or replace this collision in collisionDescs.
01535                     // NB: yes this looks like a N algorithm (so N²). But not so many collisions may arise, so don't bother.
01536                     sint    indexInsert= cst.CollisionDescs.size();
01537                     sint    colFound= -1;
01538 
01539                     // start to search with nextCollisionSurfaceTested, because can't insert before.
01540                     for(sint j= nextCollisionSurfaceTested; j<(sint)cst.CollisionDescs.size(); j++)
01541                     {
01542                         // we must keep time order.
01543                         if(tMin < cst.CollisionDescs[j].ContactTime)
01544                         {
01545                             indexInsert= min(j, indexInsert);
01546                         }
01547                         // Does the collision with this surface already exist??
01548                         if(cst.CollisionDescs[j].ContactSurface==collidedSurface)
01549                         {
01550                             colFound= j;
01551                             // if we have found our old collision, stop, there is no need to search more.
01552                             break;
01553                         }
01554                     }
01555 
01556                     // Insert only if the surface was not already collided, or that new collision arise before old.
01557                     if(colFound==-1 || indexInsert<=colFound)
01558                     {
01559                         CCollisionSurfaceDesc   newCol;
01560                         newCol.ContactSurface= collidedSurface;
01561                         newCol.ContactTime= tMin;
01562                         newCol.ContactNormal.set(normalMin.x, normalMin.y, 0);
01563 
01564                         // if, by chance, indexInsert==colFound, just replace old collision descriptor.
01565                         if(colFound==indexInsert)
01566                         {
01567                             cst.CollisionDescs[indexInsert]= newCol;
01568                         }
01569                         else
01570                         {
01571                             // if any, erase old collision against this surface. NB: here, colFound>indexInsert.
01572                             if(colFound!=-1)
01573                                 cst.CollisionDescs.erase(cst.CollisionDescs.begin() + colFound);
01574 
01575                             // must insert the collision.
01576                             cst.CollisionDescs.insert(cst.CollisionDescs.begin() + indexInsert, newCol);
01577                         }
01578                     }
01579                 }
01580             }
01581         }
01582 
01583         // Find next surface to test.
01584         //========================
01585         // No more?? so this is the end.
01586         if(nextCollisionSurfaceTested>=cst.CollisionDescs.size())
01587             break;
01588         // else next one.
01589         else
01590         {
01591             // NB: with this algorithm, we are sure that no more collisions will arise before currentCollisionSurfaceTested.
01592             // so just continue with following surface.
01593             currentSurface= cst.CollisionDescs[nextCollisionSurfaceTested].ContactSurface;
01594 
01595             // Do we touch a wall??
01596             bool    isWall;
01597             if(currentSurface.SurfaceId<0)
01598                 isWall= true;
01599             else
01600             {
01601                 // test if it is a walkable wall.
01602                 sint32  locRetId= this->getInstance(currentSurface.RetrieverInstanceId).getRetrieverId();
01603 
01604                 if (!_RetrieverBank->getRetriever(locRetId).isLoaded())
01605                 {
01606                     nextCollisionSurfaceTested++;
01607                     continue;
01608                 }
01609 
01610                 const CLocalRetriever       &retr = _RetrieverBank->getRetriever(locRetId);
01611                 if (currentSurface.SurfaceId < (sint)retr.getSurfaces().size())
01612                 {
01613                     const CRetrievableSurface   &surf= _RetrieverBank->getRetriever(locRetId).getSurface(currentSurface.SurfaceId);
01614                     isWall= !(surf.isFloor() || surf.isCeiling());
01615                 }
01616                 else
01617                 {
01618                     isWall = true;
01619                 }
01620             }
01621 
01622             // If we touch a wall, this is the end of search.
01623             if(isWall)
01624             {
01625                 // There can be no more collision after this one.
01626                 cst.CollisionDescs.resize(nextCollisionSurfaceTested+1);
01627                 break;
01628             }
01629             else
01630             {
01631                 // Next time, we will test the following (NB: the array may grow during next pass, or reorder,
01632                 // but only after nextCollisionSurfaceTested).
01633                 nextCollisionSurfaceTested++;
01634             }
01635         }
01636     }
01637 
01638 }
01639 
01640 
01641 // ***************************************************************************
01642 bool            NLPACS::CGlobalRetriever::verticalChain(const CCollisionChain &colChain) const
01643 {
01644     // retrieve surfaces.
01645     const CRetrievableSurface   *left= getSurfaceById(colChain.LeftSurface);
01646     const CRetrievableSurface   *right= getSurfaceById(colChain.RightSurface);
01647 
01648     // test if left surface is a wall.
01649     bool                        leftWall;
01650     if(!left)
01651         leftWall= true;
01652     else
01653         leftWall= !(left->isFloor() || left->isCeiling());
01654 
01655     // test if right surface is a wall.
01656     bool                        rightWall;
01657     if(!right)
01658         rightWall= true;
01659     else
01660         rightWall= !(right->isFloor() || right->isCeiling());
01661 
01662     // true if both are a wall.
01663     return leftWall && rightWall;
01664 }
01665 
01666 
01667 // ***************************************************************************
01668 NLPACS::CSurfaceIdent   NLPACS::CGlobalRetriever::testMovementWithCollisionChains(CCollisionSurfaceTemp &cst, const CVector2f &startCol, const CVector2f &endCol,
01669         CSurfaceIdent startSurface, UGlobalPosition &restart) const
01670 {
01671 //  H_AUTO(PACS_GR_testMovementWithCollisionChains);
01672 
01673     // start currentSurface with surface start.
01674     CSurfaceIdent   currentSurface= startSurface;
01675     sint            i;
01676 
01677     // reset result.
01678     cst.MoveDescs.clear();
01679 
01680 
01681     static vector<pair<sint32, bool> >  checkedExtEdges;
01682 
01683     /*
01684         To manage recovery, we must use such an algorithm, so we are sure to trace the way across all surfaces really
01685         collided, and discard any other (such as other floor or ceiling).
01686 
01687         This function is quite different from testCollisionWithCollisionChains() because she must detect all collisions
01688         with all edges of any chains (and not the minimum collision with a chain).
01689         This is done in 3 parts:
01690             - detect collisions with all edges.
01691             - sort.
01692             - leave only real collisions.
01693     */
01694     // run all collisionChain.
01695     //========================
01696     for(i=0; i<(sint)cst.CollisionChains.size(); i++)
01697     {
01698         CCollisionChain     &colChain= cst.CollisionChains[i];
01699 
01700         if (colChain.ExteriorEdge)
01701         {
01702             sint32  cmp = (colChain.LeftSurface.RetrieverInstanceId<<16) + colChain.ChainId;
01703 
01704             uint    j;
01705             for (j=0; j<checkedExtEdges.size() && (checkedExtEdges[j].first != cmp); ++j)
01706                 ;
01707             // if already crossed this edge, abort
01708             // this a door that is crossing a surface frontier
01709             if (j < checkedExtEdges.size())
01710                 continue;
01711         }
01712 
01713         // test all edges of this chain, and insert if necessary.
01714         //========================
01715         CRational64     t;
01716         // run list of edge.
01717         sint32      curEdge= colChain.FirstEdgeCollide;
01718         while(curEdge!=(sint32)0xFFFFFFFF)
01719         {
01720             // get the edge.
01721             CEdgeCollideNode    &colEdge= cst.getEdgeCollideNode(curEdge);
01722 
01723             // test collision with this edge.
01724             CEdgeCollide::TPointMoveProblem     pmpb;
01725             t= colEdge.testPointMove(startCol, endCol, pmpb);
01726             // manage multiple problems of precision.
01727             if(t== -1)
01728             {
01729                 static const string errs[CEdgeCollide::PointMoveProblemCount]= {
01730                     "ParallelEdges", "StartOnEdge", "StopOnEdge", "TraverseEndPoint", "EdgeNull"};
01731                 // return a "Precision Problem" ident. movement is invalid.
01732                 // BUT if startOnEdge, which should never arrive.
01733                 if(pmpb==CEdgeCollide::StartOnEdge)
01734                 {
01735                     nlinfo("COL: Precision Problem: %s", errs[pmpb].c_str());
01736                     checkedExtEdges.clear();
01737                     return CSurfaceIdent(-1, -1);   // so in this case, block....
01738                 }
01739                 else if(pmpb==CEdgeCollide::EdgeNull)
01740                 {
01741                     /*
01742                     // verify if it is an edge which separate 2 walls. in this case, ignore it. else, error.
01743                     if(verticalChain(colChain))
01744                     {
01745                         t=1;    // no collision with this edge.
01746                     }
01747                     else
01748                     {
01749                         nlinfo("COL: Precision Problem: %s", errs[pmpb]);
01750                         nlstop;     // this should not append.
01751                         return CSurfaceIdent(-1, -1);
01752                     }*/
01753                     /* Actually, this is never a problem: we never get through this edge.
01754                         Instead, we'll get through the neighbors edge.
01755                         So just disable this edge.
01756                     */
01757                     t= 1;
01758                 }
01759                 else
01760                     return  CSurfaceIdent(-2, -2);
01761             }
01762 
01763             // collision??
01764             if(t<1)
01765             {
01766                 // insert in list.
01767                 cst.MoveDescs.push_back(CMoveSurfaceDesc(t, colChain.LeftSurface, colChain.RightSurface));
01768                 cst.MoveDescs.back().ExteriorEdge = colChain.ExteriorEdge;
01769                 cst.MoveDescs.back().ChainId = (uint16)colChain.ChainId;
01770                 cst.MoveDescs.back().MovementSens= colEdge.Norm*(endCol-startCol)>=0;
01771             }
01772 
01773             // next edge.
01774             curEdge= colEdge.Next;
01775         }
01776     }
01777 
01778 
01779     // sort.
01780     //================
01781     // sort the collisions in ascending time order.
01782     sort(cst.MoveDescs.begin(), cst.MoveDescs.end());
01783 
01784 
01785     // Traverse the array of collisions.
01786     //========================
01787     for(i=0;i<(sint)cst.MoveDescs.size();i++)
01788     {
01789         CMoveSurfaceDesc    &msd = cst.MoveDescs[i];
01790 
01791         // Do we collide with this chain??
01792         if(msd.hasSurface(currentSurface))
01793         {
01794             // if flag as an interior/landscape interface and leave interior surf, retrieve correct surface
01795             if (msd.ExteriorEdge && msd.LeftSurface.RetrieverInstanceId != -1)
01796             {
01797                 bool    enterInterior = (currentSurface.RetrieverInstanceId == msd.RightSurface.RetrieverInstanceId);
01798 
01799                 // msd.MovementSens is true if we "geometrically" leave the interior.
01800                 // If logic and geometric disagree, discard
01801                 if(enterInterior == msd.MovementSens)
01802                     continue;
01803 
01804                 uint    j;
01805                 sint32  cmp = (msd.LeftSurface.RetrieverInstanceId<<16) + msd.ChainId;
01806                 for (j=0; j<checkedExtEdges.size() && (checkedExtEdges[j].first != cmp); ++j)
01807                     ;
01808                 // if already crossed this edge, abort
01809                 // this a door that is crossing a surface frontier
01810                 if (j < checkedExtEdges.size())
01811                 {
01812                     if (checkedExtEdges[j].second != enterInterior)
01813                         continue;
01814                 }
01815                 else
01816                     checkedExtEdges.push_back(make_pair(cmp, enterInterior));
01817 
01818                 // if leave interior, retrieve good position
01819                 if (!enterInterior)
01820                 {
01821                     // p= position until the object center point collide the exterior edge
01822                     float           ctime = (float)((double)(msd.ContactTime.Numerator)/(double)(msd.ContactTime.Denominator));
01823                     CVector2f       p = startCol*(1.0f-ctime) + endCol*ctime;
01824                     // get the interior origin
01825                     CVector         ori = getInstance(startSurface.RetrieverInstanceId).getOrigin();
01826                     ori.z = 0.0f;
01827 
01828                     // Estimate current Z
01829                     UGlobalPosition rp;
01830                     rp.InstanceId = currentSurface.RetrieverInstanceId;
01831                     rp.LocalPosition.Surface = currentSurface.SurfaceId;
01832                     rp.LocalPosition.Estimation = p;
01833                     /* WE HAVE A PRECISION PROBLEM HERE (yoyo 12/04/2006)
01834                         Since the point p has moved close to the exterior edge, because of precision, it may be actually
01835                         OUT the interior surface!!
01836                         thus getMeanHeight() will return 0!!
01837                         Then the chosen landscape position can be completly false. eg:
01838                             actual InteriorHeight: -84
01839                             new possibles landscape surfaces heights: -84 and -16
01840                             if we estimate by error InteriorHeight= 0, then we will
01841                                 have Best Landscape Surface == the one which has height=-16 !
01842 
01843                         Hence we use a specific method that look a bit outisde the triangles
01844                     */
01845                     float estimatedZ = getInteriorHeightAround(rp, 0.1f);
01846 
01847                     // retrieve the position, with the estimated Z
01848                     CVectorD        zp = CVectorD(p.x, p.y, estimatedZ) + CVectorD(ori);
01849                     // Do not allow the current interior instance
01850                     _ForbiddenInstances.clear();
01851                     _ForbiddenInstances.push_back(currentSurface.RetrieverInstanceId);
01852                     restart = retrievePosition(zp);
01853 
01854                     return CSurfaceIdent(-3, -3);
01855                 }
01856                 else
01857                 {
01858                     currentSurface= msd.getOtherSurface(currentSurface);
01859                 }
01860             }
01861             else
01862             {
01863                 currentSurface= msd.getOtherSurface(currentSurface);
01864             }
01865 
01866             // Do we touch a wall?? should not happens, but important for security.
01867             bool    isWall;
01868             if(currentSurface.SurfaceId<0)
01869                 isWall= true;
01870             else
01871             {
01872                 // test if it is a walkable wall.
01873                 sint32  locRetId= this->getInstance(currentSurface.RetrieverInstanceId).getRetrieverId();
01874 
01875                 if (!_RetrieverBank->getRetriever(locRetId).isLoaded())
01876                     continue;
01877 
01878                 const CRetrievableSurface   &surf= _RetrieverBank->getRetriever(locRetId).getSurface(currentSurface.SurfaceId);
01879                 isWall= !(surf.isFloor() || surf.isCeiling());
01880             }
01881 
01882             // If we touch a wall, this is the end of search.
01883             if(isWall)
01884             {
01885                 // return a Wall ident. movement is invalid.
01886                 checkedExtEdges.clear();
01887                 return  CSurfaceIdent(-1, -1);
01888             }
01889         }
01890     }
01891 
01892     checkedExtEdges.clear();
01893     return currentSurface;
01894 }
01895 
01896 
01897 
01898 // ***************************************************************************
01899 const   NLPACS::TCollisionSurfaceDescVector
01900     *NLPACS::CGlobalRetriever::testCylinderMove(const UGlobalPosition &startPos, const NLMISC::CVector &delta, float radius, CCollisionSurfaceTemp &cst) const
01901 {
01902 //  H_AUTO(PACS_GR_testCylinderMove);
01903 
01904     CSurfaceIdent   startSurface(startPos.InstanceId, startPos.LocalPosition.Surface);
01905 
01906     // 0. reset.
01907     //===========
01908     // reset result.
01909     cst.CollisionDescs.clear();
01910 
01911     // In a surface ?
01912     if (startPos.InstanceId==-1)
01913     {
01914         // Warning this primitive is not on a surface
01915         //nlassertonce (0);
01916 
01917         // Return NULL when lost
01918         return NULL;
01919     }
01920     // store this request in cst.
01921     cst.PrecStartSurface= startSurface;
01922     cst.PrecStartPos= startPos.LocalPosition.Estimation;
01923     cst.PrecDeltaPos= delta;
01924     cst.PrecValid= true;
01925 
01926     // 0.bis
01927     //===========
01928     // Abort if deltamove is 0,0,0.
01929     if (delta.isNull())
01930         return &cst.CollisionDescs;
01931 
01932     // 1. Choose a local basis.
01933     //===========
01934     // Take the retrieverInstance of startPos as a local basis.
01935     CVector     origin;
01936     origin= getInstance(startPos.InstanceId).getOrigin();
01937 
01938 
01939     // 2. compute bboxmove.
01940     //===========
01941     CAABBox     bboxMove;
01942     // bounds the movement in a bbox.
01943     // compute start and end, relative to the retriever instance.
01944     CVector     start= startPos.LocalPosition.Estimation;
01945     CVector     end= start+delta;
01946     // extend the bbox.
01947     bboxMove.setCenter(start-CVector(radius, radius, 0));
01948     bboxMove.extend(start+CVector(radius, radius, 0));
01949     bboxMove.extend(end-CVector(radius, radius, 0));
01950     bboxMove.extend(end+CVector(radius, radius, 0));
01951 
01952 
01953     // 3. find possible collisions in bboxMove+origin. fill cst.CollisionChains.
01954     //===========
01955     findCollisionChains(cst, bboxMove, origin);
01956 
01957 
01958 
01959     // 4. test collisions with CollisionChains.
01960     //===========
01961     CVector2f   startCol(start.x, start.y);
01962     CVector2f   deltaCol(delta.x, delta.y);
01963     CVector2f   obbDummy[4];    // dummy OBB (not obb here so don't bother)
01964     testCollisionWithCollisionChains(cst, startCol, deltaCol, startSurface, radius, obbDummy, CGlobalRetriever::Circle);
01965 
01966     // result.
01967     return &cst.CollisionDescs;
01968 }
01969 
01970 
01971 // ***************************************************************************
01972 const   NLPACS::TCollisionSurfaceDescVector
01973     *NLPACS::CGlobalRetriever::testBBoxMove(const UGlobalPosition &startPos, const NLMISC::CVector &delta,
01974     const NLMISC::CVector &locI, const NLMISC::CVector &locJ, CCollisionSurfaceTemp &cst) const
01975 {
01976 //  H_AUTO(PACS_GR_testBBoxMove);
01977 
01978     CSurfaceIdent   startSurface(startPos.InstanceId, startPos.LocalPosition.Surface);
01979 
01980     // 0. reset.
01981     //===========
01982     // reset result.
01983     cst.CollisionDescs.clear();
01984 
01985     // In a surface ?
01986     if (startPos.InstanceId==-1)
01987     {
01988         // Warning this primitive is not on a surface
01989         //nlassertonce (0);
01990 
01991         // Return NULL when lost
01992         return NULL;
01993     }
01994 
01995     // store this request in cst.
01996     cst.PrecStartSurface= startSurface;
01997     cst.PrecStartPos= startPos.LocalPosition.Estimation;
01998     cst.PrecDeltaPos= delta;
01999     cst.PrecValid= true;
02000 
02001     // 0.bis
02002     //===========
02003     // Abort if deltamove is 0,0,0.
02004     if (delta.isNull())
02005         return &cst.CollisionDescs;
02006 
02007     // 1. Choose a local basis.
02008     //===========
02009     // Take the retrieverInstance of startPos as a local basis.
02010     CVector     origin;
02011     origin= getInstance(startPos.InstanceId).getOrigin();
02012 
02013 
02014     // 2. compute OBB.
02015     //===========
02016     CVector2f   obbStart[4];
02017     // compute start, relative to the retriever instance.
02018     CVector     start= startPos.LocalPosition.Estimation;
02019     CVector2f   obbCenter(start.x, start.y);
02020     CVector2f   locI2d(locI.x, locI.y);
02021     CVector2f   locJ2d(locJ.x, locJ.y);
02022 
02023     // build points in CCW.
02024     obbStart[0]= obbCenter - locI2d - locJ2d;
02025     obbStart[1]= obbCenter + locI2d - locJ2d;
02026     obbStart[2]= obbCenter + locI2d + locJ2d;
02027     obbStart[3]= obbCenter - locI2d + locJ2d;
02028 
02029     // 3. compute bboxmove.
02030     //===========
02031     CAABBox     bboxMove;
02032     // extend the bbox.
02033     bboxMove.setCenter(CVector(obbStart[0].x, obbStart[0].y, 0));
02034     bboxMove.extend(CVector(obbStart[1].x, obbStart[1].y, 0));
02035     bboxMove.extend(CVector(obbStart[2].x, obbStart[2].y, 0));
02036     bboxMove.extend(CVector(obbStart[3].x, obbStart[3].y, 0));
02037     bboxMove.extend(CVector(obbStart[0].x, obbStart[0].y, 0) + delta);
02038     bboxMove.extend(CVector(obbStart[1].x, obbStart[1].y, 0) + delta);
02039     bboxMove.extend(CVector(obbStart[2].x, obbStart[2].y, 0) + delta);
02040     bboxMove.extend(CVector(obbStart[3].x, obbStart[3].y, 0) + delta);
02041 
02042 
02043 
02044     // 4. find possible collisions in bboxMove+origin. fill cst.CollisionChains.
02045     //===========
02046     findCollisionChains(cst, bboxMove, origin);
02047 
02048 
02049 
02050     // 5. test collisions with CollisionChains.
02051     //===========
02052     CVector2f   startCol(start.x, start.y);
02053     CVector2f   deltaCol(delta.x, delta.y);
02054     testCollisionWithCollisionChains(cst, startCol, deltaCol, startSurface, 0, obbStart, CGlobalRetriever::BBox);
02055 
02056     // result.
02057     return &cst.CollisionDescs;
02058 }
02059 
02060 
02061 
02062 // ***************************************************************************
02063 NLPACS::UGlobalPosition
02064     NLPACS::CGlobalRetriever::doMove(const NLPACS::UGlobalPosition &startPos, const NLMISC::CVector &delta, float t, NLPACS::CCollisionSurfaceTemp &cst, bool rebuildChains) const
02065 {
02066 //  H_AUTO(PACS_GR_doMove);
02067 
02068     CSurfaceIdent   startSurface(startPos.InstanceId, startPos.LocalPosition.Surface);
02069 
02070     // clamp factor.
02071     clamp(t, 0.0f, 1.0f);
02072 
02073     // 0. reset.
02074     //===========
02075     // reset CollisionDescs.
02076     cst.CollisionDescs.clear();
02077 
02078     // In a surface ?
02079     if (startPos.InstanceId==-1)
02080     {
02081         // Warining: this primitive is not on a surface
02082         //nlassertonce (0);
02083 
02084         // Return startpos
02085         return startPos;
02086     }
02087 
02088     if(!rebuildChains)
02089     {
02090         // same move request than prec testMove() ??.
02091         if( cst.PrecStartSurface != startSurface ||
02092             cst.PrecStartPos!=startPos.LocalPosition.Estimation ||
02093             cst.PrecDeltaPos!=delta ||
02094             !cst.PrecValid)
02095         {
02096             // if not, just return start.
02097             //nlstop;
02098             //nlwarning ("BEN: you must fix this, it s happen!!!");
02099             return startPos;
02100         }
02101         // Since we are sure we have same movement than prec testMove(), no need to rebuild cst.CollisionChains.
02102     }
02103     else
02104     {
02105         // we don't have same movement than prec testMove(), we must rebuild cst.CollisionChains.
02106         // Prec settings no more valids.
02107         cst.PrecValid= false;
02108     }
02109 
02110 
02111 
02112 
02113     // 1. Choose a local basis (same than in testMove()).
02114     //===========
02115     // Take the retrieverInstance of startPos as a local basis.
02116     CVector     origin;
02117     origin= getInstance(startPos.InstanceId).getOrigin();
02118 
02119 
02120     // 2. test collisions with CollisionChains.
02121     //===========
02122     CVector     start= startPos.LocalPosition.Estimation;
02123     // compute end with real delta position.
02124     CVector     end= start + delta*t;
02125 
02126     // If asked, we must rebuild array of collision chains.
02127     if(rebuildChains)
02128     {
02129 //      H_AUTO(PACS_GR_doMove_rebuildChains);
02130 
02131         // compute bboxmove.
02132         CAABBox     bboxMove;
02133         // must add some extent, to be sure to include snapped CLocalRetriever vertex (2.0f/256 should be sufficient).
02134         // Nb: this include the precision problem just below (move a little).
02135         float   radius= 4.0f/Vector2sAccuracy;
02136         bboxMove.setCenter(start-CVector(radius, radius, 0));
02137         bboxMove.extend(start+CVector(radius, radius, 0));
02138         bboxMove.extend(end-CVector(radius, radius, 0));
02139         bboxMove.extend(end+CVector(radius, radius, 0));
02140 
02141         // find possible collisions in bboxMove+origin. fill cst.CollisionChains.
02142         findCollisionChains(cst, bboxMove, origin);
02143     }
02144 
02145 
02146     // look where we arrive.
02147     CSurfaceIdent   endSurface;
02148     CVector         endRequest= end;
02149     const sint      maxPbPrec= 32;  // move away from 4 mm at max, in each 8 direction.
02150     sint            pbPrecNum= 0;
02151 
02152     // must snap the end position.
02153     CRetrieverInstance::snapVector(endRequest);
02154     end= endRequest;
02155 
02156     // verify start is already snapped
02157     {
02158         CVector     startTest= start;
02159         CRetrieverInstance::snapVector(startTest);
02160         nlassert( start == startTest );
02161     }
02162 
02163 
02164     // Normally, just one iteration is made in this loop (but if precision problem (stopOnEdge, startOnEdge....).
02165     for(;;)
02166     {
02167         // must snap the end position.
02168         CRetrieverInstance::snapVector(end);
02169 
02170         CVector2f   startCol(start.x, start.y);
02171         CVector2f   endCol(end.x, end.y);
02172 
02173         // If same 2D position, just return startPos (suppose no movement)
02174         if(endCol==startCol)
02175         {
02176             UGlobalPosition     res;
02177             res= startPos;
02178             // keep good z movement.
02179             res.LocalPosition.Estimation.z= end.z;
02180             return res;
02181         }
02182 
02183         // search destination problem.
02184         UGlobalPosition restart;
02185         endSurface= testMovementWithCollisionChains(cst, startCol, endCol, startSurface, restart);
02186 
02187         // if no precision problem, Ok, we have found our destination surface (or anormal collide against a wall).
02188         if (endSurface.SurfaceId >= -1)
02189         {
02190             break;
02191         }
02192         // left an interior, retrieved position and ask to restart collision from retrieved position
02193         else if (endSurface.SurfaceId == -3)
02194         {
02195             start = getDoubleGlobalPosition(restart) - origin;
02196             startSurface.RetrieverInstanceId = restart.InstanceId;
02197             startSurface.SurfaceId = restart.LocalPosition.Surface;
02198             // should be snapped here
02199             CVector     startTest= start;
02200             CRetrieverInstance::snapVector(startTest);
02201             nlassert( start == startTest );
02202         }
02203         /* else we are in deep chit, for one on those reason:
02204             - traverse on point.
02205             - stop on a edge (dist==0).
02206             - start on a edge (dist==0).
02207             - run // on a edge (NB: dist==0 too).
02208         */
02209         else if (endSurface.SurfaceId == -2)
02210         {
02211             // For simplicty, just try to move a little the end position
02212             if(pbPrecNum<maxPbPrec)
02213             {
02214                 static struct   {sint x,y;}   dirs[8]= { {1,0}, {1,1}, {0,1}, {-1,1}, {-1,0}, {-1,-1}, {0,-1}, {1,-1}};
02215                 sint    dir= pbPrecNum%8;
02216                 sint    dist= pbPrecNum/8+1;
02217                 CVector     dta;
02218 
02219                 // compute small move.
02220                 dta.x= dirs[dir].x * dist * 1.0f/SnapPrecision;
02221                 dta.y= dirs[dir].y * dist * 1.0f/SnapPrecision;
02222                 dta.z= 0;
02223 
02224                 // add it to the original end pos requested.
02225                 end= endRequest + dta;
02226 
02227                 pbPrecNum++;
02228             }
02229             else
02230             {
02231                 // do not move at all.
02232                 endSurface= CSurfaceIdent(-1,-1);
02233                 break;
02234             }
02235         }
02236     }
02237 
02238     // 3. return result.
02239     //===========
02240     // Problem?? do not move.
02241     if(endSurface.SurfaceId==-1)
02242         return startPos;
02243     else
02244     {
02245         // else must return good GlobalPosition.
02246         CGlobalPosition     res;
02247 
02248         res.InstanceId= endSurface.RetrieverInstanceId;
02249         res.LocalPosition.Surface= endSurface.SurfaceId;
02250 
02251         // compute newPos, localy to the endSurface.
02252         // get delta between startPos.instance and curInstance.
02253         // NB: for float precision, it is important to compute deltaOrigin, and after compute newPos in local.
02254         CVector     deltaOrigin;
02255         deltaOrigin= origin - getInstance(res.InstanceId).getOrigin();
02256 
02257         // Because Origin precision is 1 meter, and end precision is 1/1024 meter, we have no precision problem.
02258         // this is true because we cannot move more than, say 4*160 meters in one doMove().
02259         // So global position should not be bigger than 1024 * 1024/1024 meters.  => Hence 20 bits of precision is
02260         // required. We have 23 with floats.
02261         res.LocalPosition.Estimation= end + deltaOrigin;
02262 
02263 
02264         // result.
02265         return res;
02266     }
02267 
02268 }
02269 
02270 
02271 // ***************************************************************************
02272 const NLPACS::TCollisionSurfaceDescVector   &NLPACS::CGlobalRetriever::testBBoxRot(const CGlobalPosition &startPos,
02273     const NLMISC::CVector &locI, const NLMISC::CVector &locJ, CCollisionSurfaceTemp &cst) const
02274 {
02275 //  H_AUTO(PACS_GR_testBBoxRot);
02276 
02277     CSurfaceIdent   startSurface(startPos.InstanceId, startPos.LocalPosition.Surface);
02278 
02279     // 0. reset.
02280     //===========
02281     // reset result.
02282     cst.CollisionDescs.clear();
02283 
02284     // should not doMove() after a testBBoxRot.
02285     cst.PrecValid= false;
02286 
02287 
02288     // 1. Choose a local basis.
02289     //===========
02290     // Take the retrieverInstance of startPos as a local basis.
02291     CVector     origin;
02292     origin= getInstance(startPos.InstanceId).getOrigin();
02293 
02294 
02295     // 2. compute OBB.
02296     //===========
02297     CVector2f   obbStart[4];
02298     // compute start, relative to the retriever instance.
02299     CVector     start= startPos.LocalPosition.Estimation;
02300     CVector2f   obbCenter(start.x, start.y);
02301     CVector2f   locI2d(locI.x, locI.y);
02302     CVector2f   locJ2d(locJ.x, locJ.y);
02303 
02304     // build points in CCW.
02305     obbStart[0]= obbCenter - locI2d - locJ2d;
02306     obbStart[1]= obbCenter + locI2d - locJ2d;
02307     obbStart[2]= obbCenter + locI2d + locJ2d;
02308     obbStart[3]= obbCenter - locI2d + locJ2d;
02309 
02310     // 3. compute bboxmove.
02311     //===========
02312     CAABBox     bboxMove;
02313     // extend the bbox.
02314     bboxMove.setCenter(CVector(obbStart[0].x, obbStart[0].y, 0));
02315     bboxMove.extend(CVector(obbStart[1].x, obbStart[1].y, 0));
02316     bboxMove.extend(CVector(obbStart[2].x, obbStart[2].y, 0));
02317     bboxMove.extend(CVector(obbStart[3].x, obbStart[3].y, 0));
02318 
02319 
02320 
02321     // 4. find possible collisions in bboxMove+origin. fill cst.CollisionChains.
02322     //===========
02323     findCollisionChains(cst, bboxMove, origin);
02324 
02325 
02326 
02327     // 5. test Rotcollisions with CollisionChains.
02328     //===========
02329     CVector2f   startCol(start.x, start.y);
02330     testRotCollisionWithCollisionChains(cst, startCol, startSurface, obbStart);
02331 
02332 
02333     // result.
02334     return cst.CollisionDescs;
02335 }
02336 
02337 
02338 // ***************************************************************************
02339 void    NLPACS::CGlobalRetriever::testRotCollisionWithCollisionChains(CCollisionSurfaceTemp &cst, const CVector2f &/* startCol */, CSurfaceIdent startSurface, const CVector2f bbox[4]) const
02340 {
02341 //  H_AUTO(PACS_GR_testRotCollisionWithCollisionChains);
02342 
02343     // start currentSurface with surface start.
02344     CSurfaceIdent   currentSurface= startSurface;
02345     sint            i;
02346 
02347     // reset result.
02348     cst.RotDescs.clear();
02349     cst.CollisionDescs.clear();
02350 
02351 
02352     /*
02353         Test collisions with all collision chains. Then, to manage recovery, test the graph of surfaces.
02354     */
02355     // run all collisionChain.
02356     //========================
02357     for(i=0; i<(sint)cst.CollisionChains.size(); i++)
02358     {
02359         CCollisionChain     &colChain= cst.CollisionChains[i];
02360 
02361 
02362         // test all edges of this chain, and insert if necessary.
02363         //========================
02364         // run list of edge.
02365         sint32      curEdge= colChain.FirstEdgeCollide;
02366         while(curEdge!=(sint32)0xFFFFFFFF)
02367         {
02368             // get the edge.
02369             CEdgeCollideNode    &colEdge= cst.getEdgeCollideNode(curEdge);
02370 
02371             // test collision with this edge.
02372             if(colEdge.testBBoxCollide(bbox))
02373             {
02374                 // yes we have a 2D collision with this chain.
02375                 cst.RotDescs.push_back(CRotSurfaceDesc(colChain.LeftSurface, colChain.RightSurface));
02376                 break;
02377             }
02378 
02379             // next edge.
02380             curEdge= colEdge.Next;
02381         }
02382     }
02383 
02384 
02385     // Traverse the array of collisions.
02386     //========================
02387     sint    indexCD=0;
02388     for(;;)
02389     {
02390         // What surfaces collided do we reach from this currentSurface??
02391         for(i=0;i<(sint)cst.RotDescs.size();i++)
02392         {
02393             // Do we collide with this chain?? chain not tested??
02394             if(cst.RotDescs[i].hasSurface(currentSurface) && !cst.RotDescs[i].Tested)
02395             {
02396                 cst.RotDescs[i].Tested= true;
02397 
02398                 // insert the collision with the other surface.
02399                 CCollisionSurfaceDesc   col;
02400                 col.ContactTime= 0;
02401                 col.ContactNormal= CVector::Null;
02402                 col.ContactSurface= cst.RotDescs[i].getOtherSurface(currentSurface);
02403                 cst.CollisionDescs.push_back(col);
02404             }
02405         }
02406 
02407         // get the next currentSurface from surface collided (traverse the graph of collisions).
02408         if(indexCD<(sint)cst.CollisionDescs.size())
02409             currentSurface= cst.CollisionDescs[indexCD++].ContactSurface;
02410         else
02411             break;
02412     }
02413 
02414 }
02415 
02416 // ***************************************************************************
02417 
02418 NLPACS::UGlobalRetriever *NLPACS::UGlobalRetriever::createGlobalRetriever (const char *globalRetriever, const NLPACS::URetrieverBank *retrieverBank)
02419 {
02420 
02421     // Cast
02422 //  nlassert (dynamic_cast<const NLPACS::CRetrieverBank*>(retrieverBank));
02423     const NLPACS::CRetrieverBank*   bank=static_cast<const NLPACS::CRetrieverBank*>(retrieverBank);
02424 
02425     CIFile  file;
02426     if (file.open(CPath::lookup(globalRetriever)))
02427     {
02428         CGlobalRetriever    *retriever = new CGlobalRetriever();
02429 
02430         // always set the retriever bank before serializing !!
02431         retriever->setRetrieverBank(bank);
02432 
02433         file.serial(*retriever);
02434         retriever->initAll(false);  // don't init instances as we serialized them
02435 
02436         return static_cast<UGlobalRetriever *>(retriever);
02437     }
02438     else
02439         return NULL;
02440 }
02441 
02442 // ***************************************************************************
02443 
02444 void NLPACS::UGlobalRetriever::deleteGlobalRetriever (UGlobalRetriever *retriever)
02445 {
02446     // Cast
02447     nlassert (dynamic_cast<NLPACS::CGlobalRetriever*>(retriever));
02448     NLPACS::CGlobalRetriever* r=static_cast<NLPACS::CGlobalRetriever*>(retriever);
02449 
02450     // Delete
02451     delete r;
02452 }
02453 
02454 // ***************************************************************************
02455 
02456 float           NLPACS::CGlobalRetriever::getMeanHeight(const UGlobalPosition &pos) const
02457 {
02458     // for wrong positions, leave it unchanged
02459     if ((pos.InstanceId==-1)||(pos.LocalPosition.Surface==-1))
02460         return pos.LocalPosition.Estimation.z;
02461 
02462     // get instance/localretriever.
02463     const CRetrieverInstance    &instance = getInstance(pos.InstanceId);
02464     const CLocalRetriever       &retriever= _RetrieverBank->getRetriever(instance.getRetrieverId());
02465 
02466     if (!retriever.isLoaded())
02467         return pos.LocalPosition.Estimation.z;
02468 
02469     // return height from local retriever
02470     return retriever.getHeight(pos.LocalPosition);
02471 }
02472 
02473 // ***************************************************************************
02474 float           NLPACS::CGlobalRetriever::getInteriorHeightAround(const UGlobalPosition &pos, float outsideTolerance) const
02475 {
02476     // for wrong positions, leave it unchanged
02477     if ((pos.InstanceId==-1)||(pos.LocalPosition.Surface==-1))
02478         return pos.LocalPosition.Estimation.z;
02479 
02480     // get instance/localretriever.
02481     const CRetrieverInstance    &instance = getInstance(pos.InstanceId);
02482     const CLocalRetriever       &retriever= _RetrieverBank->getRetriever(instance.getRetrieverId());
02483 
02484     if (!retriever.isLoaded())
02485         return pos.LocalPosition.Estimation.z;
02486 
02487     // return height from local retriever
02488     return retriever.getInteriorHeightAround(pos.LocalPosition, outsideTolerance);
02489 }
02490 
02491 // ***************************************************************************
02492 
02493 bool NLPACS::CGlobalRetriever::testRaytrace (const CVectorD &/* v0 */, const CVectorD &/* v1 */)
02494 {
02495     // TODO: implement raytrace
02496     return false;
02497 }
02498 
02499 // ***************************************************************************
02500 
02501 void    NLPACS::CGlobalRetriever::refreshLrAround(const CVector &position, float radius)
02502 {
02503     NLPACS_HAUTO_REFRESH_LR_AROUND
02504 
02505     // check if retriever bank is all loaded, and if yes don't refresh it
02506     if (_RetrieverBank->allLoaded())
02507         return;
02508 
02509     std::list<CLrLoader>::iterator ite = _LrLoaderList.begin();
02510     while (ite != _LrLoaderList.end())
02511     {
02512         // Finished loaded a lr, stream it into rbank
02513         if (ite->Finished && ite->Successful)
02514         {
02515             if (!ite->_Buffer.isReading())
02516                 ite->_Buffer.invert();
02517 
02518             ite->_Buffer.resetBufPos();
02519 
02520             //      NLMEMORY::CheckHeap (true);
02521 
02522             const_cast<CRetrieverBank*>(_RetrieverBank)->loadRetriever(ite->LrId, ite->_Buffer);
02523 
02524             //      NLMEMORY::CheckHeap (true);
02525 
02526             ite->_Buffer.clear();
02527 
02528             //      NLMEMORY::CheckHeap (true);
02529 
02530             nlinfo("Lr '%s' loading task complete", ite->LoadFile.c_str());
02531 
02532             // Remove this entry
02533             _LrLoaderList.erase (ite);
02534 
02535             break;
02536         }
02537 
02538         // Next lr
02539         ite++;
02540     }
02541 
02542     CAABBox box;
02543     box.setCenter(position);
02544     box.setHalfSize(CVector(radius, radius, 1000.0f));
02545 
02546     selectInstances(box, _InternalCST);
02547 
02548     set<uint>   newlr, in, out;
02549     map<uint, CVector>  lrPosition;
02550 
02551     uint    i;
02552     for (i=0; i<_InternalCST.CollisionInstances.size(); ++i)
02553     {
02554         uint lrId = (uint)(_Instances[_InternalCST.CollisionInstances[i]].getRetrieverId());
02555         newlr.insert(lrId);
02556         lrPosition.insert (map<uint, CVector>::value_type(lrId, _Instances[_InternalCST.CollisionInstances[i]].getBBox().getCenter()));
02557     }
02558 
02559     const_cast<CRetrieverBank*>(_RetrieverBank)->diff(newlr, in, out);
02560 
02561     set<uint>::iterator it;
02562 
02563     // unload all possible retrievers
02564     for (it=out.begin(); it!=out.end(); ++it)
02565     {
02566         const_cast<CRetrieverBank*>(_RetrieverBank)->unloadRetriever(*it);
02567         nlinfo("Freed Lr '%s'", (_RetrieverBank->getNamePrefix() + "_" + toString(*it) + ".lr").c_str());
02568     }
02569 
02570     // if load task idle and more lr to load, setup load task
02571     set<uint>::iterator iteIn = in.begin();
02572     while (iteIn != in.end())
02573     {
02574         // Already exist ?
02575         ite = _LrLoaderList.begin();
02576         while (ite != _LrLoaderList.end())
02577         {
02578             if (ite->LrId == *iteIn)
02579                 break;
02580 
02581             ite++;
02582         }
02583 
02584         // Not found ?
02585         if (ite == _LrLoaderList.end())
02586         {
02587             // Get the position fot this LR
02588             map<uint, CVector>::iterator iteLR = lrPosition.find(*iteIn);
02589             nlassert (iteLR != lrPosition.end());
02590 
02591             _LrLoaderList.push_back (CLrLoader (iteLR->second));
02592             CLrLoader &loader = _LrLoaderList.back();
02593             loader.Finished = false;
02594             loader.LrId = *iteIn;
02595             loader.LoadFile = _RetrieverBank->getNamePrefix() + "_" + toString(loader.LrId) + ".lr";
02596 
02597             CAsyncFileManager::getInstance().addLoadTask(&loader);
02598 
02599             nlinfo("Lr '%s' added to load", loader.LoadFile.c_str());
02600         }
02601 
02602         // Next lr to load
02603         iteIn++;
02604     }
02605 }
02606 
02607 // ***************************************************************************
02608 void    NLPACS::CGlobalRetriever::waitEndOfAsyncLoading()
02609 {
02610     while (!_LrLoaderList.empty ())
02611     {
02612         std::list<CLrLoader>::iterator ite = _LrLoaderList.begin();
02613         while (ite != _LrLoaderList.end())
02614         {
02615             // Finished loaded a lr, stream it into rbank
02616             if (ite->Finished)
02617             {
02618                 if (!ite->_Buffer.isReading())
02619                     ite->_Buffer.invert();
02620 
02621                 const_cast<CRetrieverBank*>(_RetrieverBank)->loadRetriever(ite->LrId, ite->_Buffer);
02622 
02623                 ite->_Buffer.clear();
02624 
02625                 // Remove this from the list
02626                 _LrLoaderList.erase(ite);
02627 
02628                 break;
02629             }
02630 
02631             //
02632             ite++;
02633         }
02634 
02635         if (!_LrLoaderList.empty())
02636             nlSleep(0);
02637     }
02638 
02639 }
02640 
02641 // ***************************************************************************
02642 void    NLPACS::CGlobalRetriever::refreshLrAroundNow(const CVector &position, float radius)
02643 {
02644     // check if retriever bank is all loaded, and if yes don't refresh it
02645     if (_RetrieverBank->allLoaded())
02646         return;
02647 
02648     // must wait all current have finished loading
02649     waitEndOfAsyncLoading();
02650 
02651     // Select new to load
02652     CAABBox box;
02653     box.setCenter(position);
02654     box.setHalfSize(CVector(radius, radius, 1000.0f));
02655 
02656     selectInstances(box, _InternalCST);
02657 
02658     set<uint>   newlr, in, out;
02659     uint    i;
02660     for (i=0; i<_InternalCST.CollisionInstances.size(); ++i)
02661         newlr.insert((uint)(_Instances[_InternalCST.CollisionInstances[i]].getRetrieverId()));
02662 
02663     const_cast<CRetrieverBank*>(_RetrieverBank)->diff(newlr, in, out);
02664 
02665     set<uint>::iterator it;
02666 
02667     // unload all possible retrievers
02668     for (it=out.begin(); it!=out.end(); ++it)
02669         const_cast<CRetrieverBank*>(_RetrieverBank)->unloadRetriever(*it);
02670 
02671     // unload all possible retrievers
02672     for (it=in.begin(); it!=in.end(); ++it)
02673     {
02674         string      fname = _RetrieverBank->getNamePrefix() + "_" + toString(*it) + ".lr";
02675         CIFile      f;
02676         if (!f.open(CPath::lookup(fname, false)))
02677         {
02678             nlwarning("Couldn't find file '%s' to load, retriever loading aborted", fname.c_str());
02679             continue;
02680         }
02681 
02682         const_cast<CRetrieverBank*>(_RetrieverBank)->loadRetriever(*it, f);
02683     }
02684 }
02685 
02686 void    NLPACS::CGlobalRetriever::CLrLoader::run()
02687 {
02688     CIFile      f;
02689 
02690     // async
02691     f.setAsyncLoading(true);
02692     f.setCacheFileOnOpen(true);
02693 
02694     Successful = false;
02695 
02696     if (!f.open(CPath::lookup(LoadFile, false)))
02697     {
02698         nlwarning("Couldn't find file '%s' to load, retriever loading aborted", LoadFile.c_str());
02699         _Buffer.clear();
02700         Finished = true;
02701         return;
02702     }
02703 
02704     if (!_Buffer.isReading())
02705         _Buffer.invert();
02706 
02707     uint8   *buffer = _Buffer.bufferToFill(f.getFileSize());
02708     f.serialBuffer(buffer, f.getFileSize());
02709 
02710     Successful = true;
02711     Finished = true;
02712 }
02713 
02714 // ***************************************************************************
02715 void    NLPACS::CGlobalRetriever::CLrLoader::getName (std::string &result) const
02716 {
02717     result = "LoadLR(" + LoadFile + ")";
02718 }
02719 
02720 
02721 //
02722 NLMISC_CATEGORISED_VARIABLE(nel, uint, PacsRetrieveVerbose, "Allow retrieve position to dump info");
02723 
02724 // end of CGlobalRetriever methods implementation

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