1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "path_behaviors.h"
19 #include "ais_actions.h"
20 #include "continent.h"
23 extern bool simulateBug(int bugId
);
25 using namespace RYAI_MAP_CRUNCH
;
26 using namespace CAISActionEnums
;
29 NLMISC::CVariable
<bool> ActivateStraightRepulsion("ai", "ActivateStraightRepulsion", "Activate the straight repulsion for follow route (only available with Ring shards for moment).", true, 0, true);
30 NLMISC::CVariable
<bool> LogTimeConsumingAStar("ai", "LogTimeConsumingAStar", "Activate logging of time consuming path finding operations", false, 0, true);
33 //////////////////////////////////////////////////////////////////////////////
34 // Actions used when parsing primitives //
35 //////////////////////////////////////////////////////////////////////////////
37 DEFINE_ACTION(ContextGlobal
,SETNOGO
)
39 // get hold of the parameters and check their validity
41 if (!getArgs(args
,name(),x
,y
))
44 const RYAI_MAP_CRUNCH::CMapPosition
pos(CAIVector (x
,y
));
46 const RYAI_MAP_CRUNCH::CWorldMap
&worldMap
=CWorldContainer::getWorldMap(/*0*/);
47 const CSuperCell
*superCell
=worldMap
.getSuperCellCst(pos
);
51 nlwarning("Unable to set flags at this position %.3f %.3f",x
,y
);
56 DEFINE_ACTION(ContextGlobal
,SAFEZONE
)
58 // get hold of the parameters and check their validity
61 if (!getArgs(args
,name(),x
,y
,r
))
64 const RYAI_MAP_CRUNCH::CMapPosition
pos(CAIVector (x
,y
));
65 CWorldContainer::getWorldMapNoCst().setFlagOnPosAndRadius(pos
,r
,1);
68 //////////////////////////////////////////////////////////////////////////////
69 // CFollowPathContext //
70 //////////////////////////////////////////////////////////////////////////////
72 CFollowPathContext::CFollowPathContext(const char* contextName
, uint32 maxSearchDepth
, bool forceMaxDepth
)
74 if (contextName
==NULL
)
76 // nldebug("CFollowPathContext: NULL : first init");
78 _ContextName
= "TopOfStack";
79 _MaxSearchDepth
= maxSearchDepth
;
84 // nldebug("CFollowPathContext: %s",contextName);
85 _PrevContext
= CFollowPath::getInstance()->_TopFollowPathContext
;
86 nlassert(_PrevContext
!=NULL
);
87 CFollowPath::getInstance()->_TopFollowPathContext
= this;
88 _PrevContext
->_NextContext
= this;
89 _ContextName
= contextName
;
90 _MaxSearchDepth
= (forceMaxDepth
)? maxSearchDepth
: std::min(maxSearchDepth
,_PrevContext
->_MaxSearchDepth
);
95 CFollowPathContext::~CFollowPathContext()
97 // if we're not the bottom of stack then fixup the previous stack entry
98 if (_PrevContext
!=NULL
)
100 _PrevContext
->_NextContext
= _NextContext
;
103 // if we're not at the top of stack then fixup the next stack entry
104 // otherwise fixup the stack top pointer in the CFollowPath singleton
105 if (_NextContext
!=NULL
)
107 _NextContext
->_PrevContext
= _PrevContext
;
111 CFollowPath::getInstance()->_TopFollowPathContext
= _PrevContext
;
115 void CFollowPathContext::buildContextName(std::string
&result
) const
117 // concatenate previous stack entries
118 if (_PrevContext
!=NULL
)
120 _PrevContext
->buildContextName(result
);
128 // add our name to the result
129 result
+= _ContextName
;
133 //////////////////////////////////////////////////////////////////////////////
135 //////////////////////////////////////////////////////////////////////////////
137 CFollowPath
* CFollowPath::_Instance
= NULL
;
139 CFollowPath
* CFollowPath::getInstance()
143 _Instance
= new CFollowPath
;
148 void CFollowPath::destroyInstance()
157 CFollowPath::CFollowPath()
158 : _LastReason(NO_REASON
)
159 , _LastFIASPReason(CWorldMap::FIASPR_NO_REASON
)
161 // initialise the _TopFollowPathContext stack
162 _TopFollowPathContext
= new CFollowPathContext(NULL
);
165 NLMISC::CVariable
<uint
> AStarNbStepsLogThreshold( "ais", "AStarNbStepsLogThreshold", "", 1000, 0, true );
166 namespace RYAI_MAP_CRUNCH
168 extern uint LastAStarNbSteps
;
171 inline void logTimeConsumingAStar(CModEntityPhysical
* bot
, float dist
, CPathCont
& pathCont
, CAIVector
* realDestination
)
173 if (!LogTimeConsumingAStar
.get())
176 if (RYAI_MAP_CRUNCH::LastAStarNbSteps
>= AStarNbStepsLogThreshold
.get() )
178 nlinfo( "ASTAR: Bot %s (type %s) used %u steps src=%s dest=%s dist=%g a*flag=%s context=%s",
179 bot
? bot
->getPersistent().getOneLineInfoString().c_str() : "-",
180 bot
? typeid(*bot
).name() : "-",
181 RYAI_MAP_CRUNCH::LastAStarNbSteps
,
182 bot
? bot
->pos().toString().c_str() : "-",
183 realDestination
? realDestination
->toString().c_str() : pathCont
.getDestination().toString().c_str(),
185 bot
? RYAI_MAP_CRUNCH::toString(bot
->getAStarFlag()).c_str() : "-",
186 CFollowPath::getInstance()->getContextName() );
190 NLMISC::CMustConsume
<CFollowPath::TFollowStatus
> CFollowPath::followPath(
191 CModEntityPhysical
* bot
,
192 CPathPosition
& pathPos
,
195 float modecalageDist
,
197 bool focusOnTargetDirection
,
198 CAIVector
* realDestination
,
205 return FOLLOW_BLOCKED
;
207 TFollowStatus returnStatus
= FOLLOWING
;
209 bool isMotionAngleComputed
= false;
211 CAIVector
addCorrection(0.0,0.0);
212 CWorldMap
const& worldMap
= CWorldContainer::getWorldMap();
214 CAIPos
const startPos
= CAIPos(bot
->pos());
216 nlassert(angleAmort
>=0.f
&& angleAmort
<=1.f
);
218 if (!bot
->wpos().isValid())
221 bool haveRestart
= false;
223 switch (pathPos
._PathState
)
225 case CPathPosition::NOT_INITIALIZED
:
227 pathPos
._Angle
=bot
->theta();
230 if (!pathCont
.getCalcPathForSource (pathPos
,bot
->wpos()))
232 pathPos
._PathState
= CPathPosition::NOT_INITIALIZED
;
233 returnStatus
= FOLLOW_NO_PATH
;
234 _LastReason
= FNP_NOT_INITIALIZED
;
237 logTimeConsumingAStar(bot
, dist
, pathCont
, realDestination
);
238 pathPos
._PathState
= CPathPosition::FOLLOWING_TOPO
;
242 case CPathPosition::FOLLOWING_TOPO
:
244 if (pathCont
._TimeTopoChanged
!=pathPos
._TimeTopoChanged
)
246 goto reStartFollowTopo
;
249 // If we have changed our current topology, we have to take the next furthest topo in the same 'cell'.
250 CTopology::TTopologyRef
botTopology(bot
->wpos().getTopologyRef());
251 while ( pathPos
.haveNextTopology(2)
252 && botTopology
==pathPos
.getNextTopology())
254 pathPos
.nextTopology();
257 if (!pathPos
.isFinished())
259 CGridDirectionLayer
const* layer
= worldMap
.getGridDirectionLayer(bot
->wpos(),pathPos
.getNextTopology());
261 if (!layer
) // We are now to far to have a layer to lead us to the next topo.
263 goto reStartFollowTopo
;
266 CDirection motion
= layer
->getDirection(bot
->wpos());
267 if (motion
.isValid())
269 motionAngle
= motion
.getAngle();
270 isMotionAngleComputed
=true;
274 pathPos
._PathState
= CPathPosition::FOLLOWING_INSIDE_TOPO
;
278 case CPathPosition::FOLLOWING_INSIDE_TOPO
:
280 if (pathCont
._TimeTopoChanged
!=pathPos
._TimeTopoChanged
)
282 goto reStartFollowTopo
;
285 if (pathCont
._TimeDestChanged
!=pathPos
._TimeDestChanged
)
287 pathPos
._InsidePath
=NULL
;
290 if (pathPos
._InsidePath
.isNull())
292 CInsidePath
* insidePath
= new CInsidePath();
293 pathPos
._InsidePath
= insidePath
;
295 if (!worldMap
.findInsideAStarPath(bot
->wpos(), pathCont
.getDestPos(), insidePath
->_DirectionPath
, pathCont
.denyFlags()))
297 // If findInsideAStarPath returned false we have a topology change
298 pathPos
._InsidePath
=NULL
;
301 nlassert(!haveRestart
);
306 goto reStartFollowTopo
;
308 returnStatus
= FOLLOW_NO_PATH
;
309 _LastReason
= FNP_NO_INSIDE_ASTAR_PATH
;
310 _LastFIASPReason
= worldMap
._LastFIASPReason
;
314 pathPos
._InsideIndex
= 0;
316 pathPos
._TimeDestChanged
= pathCont
._TimeDestChanged
;
317 pathPos
._TimeTopoChanged
= pathCont
._TimeTopoChanged
;
319 // If we reached path end
320 if (pathPos
._InsideIndex
>= insidePath
->_DirectionPath
.size())
322 returnStatus
= FOLLOW_ARRIVED
;
323 pathPos
._InsidePath
= NULL
;
327 pathPos
._InsideStartPos
= bot
->wpos();
328 CDirection direction
= insidePath
->_DirectionPath
[pathPos
._InsideIndex
];
329 pathPos
._InsideDestPos
= pathPos
._InsideStartPos
.step(direction
.dx(), direction
.dy());
333 if (!pathPos
._InsidePath
.isNull())
335 CInsidePath
* insidePath
= pathPos
._InsidePath
;
336 CMapPosition botWpos
= bot
->wpos();
338 while (pathPos
._InsideIndex
< insidePath
->_DirectionPath
.size())
340 if (botWpos
== pathPos
._InsideStartPos
)
343 if (botWpos
== pathPos
._InsideDestPos
)
345 ++pathPos
._InsideIndex
;
346 if (pathPos
._InsideIndex
>= insidePath
->_DirectionPath
.size())
348 returnStatus
= FOLLOW_ARRIVED
;
349 pathPos
._InsidePath
= NULL
;
353 pathPos
._InsideStartPos
= botWpos
;
354 CDirection direction
= insidePath
->_DirectionPath
[pathPos
._InsideIndex
];
355 pathPos
._InsideDestPos
= pathPos
._InsideStartPos
.step(direction
.dx(), direction
.dy());
361 pathPos
._InsideIndex
++;
365 if (returnStatus
!=FOLLOW_ARRIVED
&& pathPos
._InsideIndex
>= insidePath
->_DirectionPath
.size())
367 pathPos
._InsidePath
= NULL
;
371 if (returnStatus
!=FOLLOW_ARRIVED
)
373 motionAngle
= pathPos
._InsidePath
->_DirectionPath
[pathPos
._InsideIndex
].getAngle();
374 isMotionAngleComputed
= true;
378 pathPos
._PathState
= CPathPosition::REACH_END
;
385 case CPathPosition::REACH_END
:
387 if (pathCont
._TimeDestChanged
!=pathPos
._TimeDestChanged
)
389 goto reStartFollowTopo
;
393 returnStatus
=FOLLOW_ARRIVED
;
398 case CPathPosition::NO_PATH
:
405 if (isMotionAngleComputed
)
407 CAngle thisAngle
= pathPos
._Angle
;
409 CAIVector deltaToDest
= (realDestination
!=NULL
)?*realDestination
:pathCont
.getDestination();
410 deltaToDest
-= CAIVector(bot
->pos());
412 CAngle idealAngle
= deltaToDest
.asAngle();
414 sint32 absDeltaIdealAngle
= abs((sint16
)(idealAngle
.asRawSint16()-motionAngle
.asRawSint16()));
415 if (absDeltaIdealAngle
>=32768)
417 absDeltaIdealAngle
= abs((sint16
)absDeltaIdealAngle
-65536);
420 bool idealIsValid
= true;
422 if (absDeltaIdealAngle
>(32768*67.5/180)) // /*97*/ if a difference of slightly more than 95 degrees.
424 idealIsValid
= false;
428 //////////////////////////////////////////////////////////////////////////
429 // verify that the direction is valid in the map at our position (very slow, to be optimized).
430 CDirection dir0
, dir1
;
431 CDirection::getDirectionAround(idealAngle
, dir0
, dir1
);
432 CWorldPosition
testPos(bot
->wpos());
433 dir1
.addStep(CDirection::HALF_TURN_RIGHT
);
434 idealIsValid
=worldMap
.customCheckDiagMove(testPos
, dir1
, pathCont
.denyFlags());
439 motionAngle
= idealAngle
;
443 sint16 deltaAngle
= motionAngle
.asRawSint16()-thisAngle
.asRawSint16();
444 sint32 absDeltaAngle
= abs(deltaAngle
);
445 // Take the smallest angle must be add in CAngle.
446 if (absDeltaAngle
>= 32768)
449 deltaAngle
= (sint16
)deltaAngle
-65536;
451 deltaAngle
= (sint16
)65536-deltaAngle
;
454 // Only if significative.
455 if (absDeltaAngle
>32)
457 deltaAngle
= (sint16
)((float)deltaAngle
*angleAmort
);
458 thisAngle
+= deltaAngle
;
462 thisAngle
= motionAngle
;
466 pathPos
._Angle
= thisAngle
;
468 // Verify that dist is not too high !
470 float reachDist
= (float)(bot
->pos().quickDistTo(pathCont
.getDestination())*0.5+0.1);
471 if (dist
> reachDist
)
475 add
= CAIVector(thisAngle
.asVector2d()*dist
);
478 deltaToDest
.normalize(dist
*1000);
479 addCorrection
= deltaToDest
-add
;
483 CAIVector moveDecalage
=bot
->moveDecalage();
484 bot
->resetDecalage();
485 moveDecalage
.normalize(modecalageDist
*1000);
491 if (IsRingShard
.get() && ActivateStraightRepulsion
.get())
493 // straight repulsion
495 if (bot
->calcStraightRepulsion(startPos
+rAdd
, repulsion
))
497 rAdd
+= moveDecalage
;
502 return FOLLOW_BLOCKED
;
508 CAIVector repulsion
= bot
->calcRepulsion(startPos
+rAdd
);
509 rAdd
+= moveDecalage
;
510 repulsion
.normalize((float)(std::max((float)rAdd
.norm(),repulsSpeed
)*710)); // minimum of 0.25m/s.
516 rAdd
= add
+ moveDecalage
;
517 if (IsRingShard
.get() && ActivateStraightRepulsion
.get())
519 // straight repulsion
521 if (bot
->calcStraightRepulsion(startPos
+rAdd
, repulsion
))
527 return FOLLOW_BLOCKED
;
533 CAIVector repulsion
= bot
->calcRepulsion(startPos
+rAdd
);
534 repulsion
.normalize((float)(std::max((float)rAdd
.norm(),repulsSpeed
)*710)); // minimum of 0.25m/s.
539 if (!rAdd
.isNull() && !bot
->moveBy(rAdd
, pathCont
.denyFlags()))
541 if (rAdd
==add
|| !bot
->moveBy(add
, pathCont
.denyFlags())) // Try without correction / repulsion, etc .. (if there's any).
543 if (!isMotionAngleComputed
|| pathPos
._Angle
==motionAngle
)
545 // try a 1 meter step
546 add
= add
.normalize()*1000;
547 if (!bot
->moveBy(add
, pathCont
.denyFlags()))
548 return FOLLOW_BLOCKED
;
551 if (isMotionAngleComputed
)
553 pathPos
._Angle
= motionAngle
;
555 bot
->setTheta(motionAngle
);
562 bot
->setTheta(pathPos
._Angle
);
567 if (updateOrient
&& !rAdd
.isNull())
568 bot
->setTheta(rAdd
.asAngle());
573 const char* CFollowPath::getContextName() const
575 static std::string name
;
577 // the following should never happen but it's quite unimportant
578 if (_TopFollowPathContext
==NULL
)
579 return "<no context stack>";
581 // delegate to the top context to build the contextname
582 _TopFollowPathContext
->buildContextName(name
);
584 // we're allowed to return this value because 'name' is a static
589 //////////////////////////////////////////////////////////////////////////////
591 //////////////////////////////////////////////////////////////////////////////
593 CPathCont::CPathCont(RYAI_MAP_CRUNCH::TAStarFlag denyFlags
)
594 : _TimeTopoChanged(~0)
595 , _TimeDestChanged(~0)
596 , _denyFlags(denyFlags
)
600 CPathCont::CPathCont(CPathCont
const& pathCont
)
601 : _denyFlags(pathCont
._denyFlags
)
605 void CPathCont::clearPaths()
607 _SourcePaths
.clear();
610 void CPathCont::setDestination(RYAI_MAP_CRUNCH::CWorldPosition
const& destPos
)
612 RYAI_MAP_CRUNCH::CMapPosition
mapPos(destPos
);
614 if (_DestinationMapPos
==mapPos
)
617 _DestinationMapPos
= mapPos
;
618 _Destination
= destPos
;
619 _VerticalPos
= AITYPES::vp_auto
;
620 uint32 gameCycle
= CTimeInterface::gameCycle();
622 RYAI_MAP_CRUNCH::CWorldPosition tmpPos
= destPos
;
624 if (tmpPos
!=_DestPos
)
627 _TimeDestChanged
= gameCycle
;
629 if (!_DestPos
.isValid())
635 RYAI_MAP_CRUNCH::CTopology::TTopologyRef newTopo
= _DestPos
.getTopologyRef();
636 if (((RYAI_MAP_CRUNCH::CTopology::TTopologyId
)newTopo
)!=_TopoRef
)
638 _TimeTopoChanged
= gameCycle
;
646 void CPathCont::setDestination(AITYPES::TVerticalPos verticalPos
, CAIVector
const& destPos
)
648 RYAI_MAP_CRUNCH::CMapPosition
mapPos(destPos
);
650 if (_DestinationMapPos
==mapPos
)
653 _DestinationMapPos
= mapPos
;
654 _Destination
= destPos
;
655 _VerticalPos
= verticalPos
;
656 uint32 gameCycle
= CTimeInterface::gameCycle();
658 RYAI_MAP_CRUNCH::CWorldPosition tmpPos
;
659 CWorldContainer::getWorldMap().setWorldPosition(verticalPos
, tmpPos
,destPos
);
661 if (tmpPos
!=_DestPos
)
664 _TimeDestChanged
= gameCycle
;
666 if (!_DestPos
.isValid())
672 RYAI_MAP_CRUNCH::CTopology::TTopologyRef newTopo
= _DestPos
.getTopologyRef();
673 if (((RYAI_MAP_CRUNCH::CTopology::TTopologyId
)newTopo
)!=_TopoRef
)
675 _TimeTopoChanged
= gameCycle
;
683 bool CPathCont::getPathForSource(CPathPosition
& pathPos
, RYAI_MAP_CRUNCH::CWorldPosition
const& startPos
) const
685 H_AUTO(getPathForSource
);
686 RYAI_MAP_CRUNCH::CTopology::TTopologyRef
const startTopo
= startPos
.getTopologyRef();
688 std::vector
<NLMISC::CSmartPtr
<CAIPath
> >::const_iterator it
= _SourcePaths
.begin();
689 const std::vector
<NLMISC::CSmartPtr
<CAIPath
> >::const_iterator itEnd
= _SourcePaths
.end();
695 std::vector
<RYAI_MAP_CRUNCH::CTopology::TTopologyRef
>::const_iterator
const topoItBegin
=path
->topologiesPath().begin();
696 std::vector
<RYAI_MAP_CRUNCH::CTopology::TTopologyRef
>::const_iterator
const topoItEnd
=path
->topologiesPath().end();
697 std::vector
<RYAI_MAP_CRUNCH::CTopology::TTopologyRef
>::const_iterator
const topoItFind
= std::find(topoItBegin
,topoItEnd
,startTopo
);
699 if (topoItFind
!=topoItEnd
)
701 pathPos
._Index
= (uint
)(topoItFind
-topoItBegin
);
707 pathPos
._Path
= NULL
;
708 return false; // No path found.
711 bool CPathCont::calcPathForSource(CPathPosition
& pathPos
, RYAI_MAP_CRUNCH::CWorldPosition
const& startPos
)
713 H_AUTO(calcPathForSource
);
715 RYAI_MAP_CRUNCH::CWorldMap
const& worldMap
= CWorldContainer::getWorldMap();
719 std::vector
<NLMISC::CSmartPtr
<CAIPath
> >::iterator it
, itEnd
= _SourcePaths
.end();
720 for (it
= _SourcePaths
.begin(); it
!=itEnd
; ++it
)
721 if ((*it
)->getRefCount()==1) // one refcount is reserved for the current list.
724 // If we didn't found a free path we have to extend the vector..
727 _SourcePaths
.push_back(new CAIPath());
728 pathPos
._Path
= _SourcePaths
.back();
732 pathPos
._Path
= (*it
);
736 pathPos
._Index
= 0; // current topology index.
738 CAIPath
& pathRef
= *(pathPos
._Path
);
740 // Check start position validity
741 if (!startPos
.isValid())
743 RYAI_MAP_CRUNCH::CWorldPosition newpos
;
744 CWorldContainer::calcNearestWPosFromPosAnRadius(_VerticalPos
, newpos
, startPos
, 6, 100, CWorldContainer::CPosValidatorDefault());
746 if (newpos
.isValid() && LogAcceptablePos
)
747 nlwarning("Path pos error at position %s: an acceptable position could be %s", startPos
.toString().c_str(), newpos
.toString().c_str() );
748 if (!newpos
.isValid())
749 nlwarning("Path pos error at position %s: no acceptable position found around", startPos
.toString().c_str());
751 pathRef
.setStartPos(newpos
);
755 pathRef
.setStartPos(startPos
);
758 // Check dest position validity
759 if (!_DestPos
.isValid())
761 RYAI_MAP_CRUNCH::CWorldPosition newpos
;
762 CWorldContainer::calcNearestWPosFromPosAnRadius(_VerticalPos
, newpos
, _DestPos
, 6, 100, CWorldContainer::CPosValidatorDefault());
764 if (newpos
.isValid() && LogAcceptablePos
)
765 nlwarning("Path pos error at position %s, an acceptable position could be %s", _DestPos
.toString().c_str(), newpos
.toString().c_str() );
766 if (!newpos
.isValid())
767 nlwarning("Path pos error at position %s, no acceptable position found around", _DestPos
.toString().c_str());
772 pathRef
.setEndPos(_DestPos
);
774 if (!worldMap
.findAStarPath(pathRef
.getStartPos(), _DestPos
, pathRef
.topologiesPathForCalc(), _denyFlags
))
776 pathPos
._Path
= NULL
;
782 bool CPathCont::getCalcPathForSource(CPathPosition
& pathPos
, RYAI_MAP_CRUNCH::CWorldPosition
const& startPos
)
784 H_AUTO(GetCalcPathForSource
);
785 static uint32 getCount
= 0;
786 static uint32 calcCount
= 0;
787 pathPos
._TimeDestChanged
= _TimeDestChanged
;
788 pathPos
._TimeTopoChanged
= _TimeTopoChanged
;
790 if (getPathForSource(pathPos
, startPos
))
795 if (calcPathForSource(pathPos
, startPos
))
803 //////////////////////////////////////////////////////////////////////////////
805 //////////////////////////////////////////////////////////////////////////////
807 CPathPosition::CPathPosition(CAngle
const& angle
)
810 , _PathState(NOT_INITIALIZED
)
814 bool CPathPosition::isPathValid() const
816 return !_Path
.isNull();
819 RYAI_MAP_CRUNCH::CTopology::TTopologyRef
const& CPathPosition::getTopology() const
822 nlassert(_Index
<_Path
->topologiesPath().size());
824 return _Path
->topologiesPath()[_Index
];
827 RYAI_MAP_CRUNCH::CTopology::TTopologyRef
const& CPathPosition::getNextTopology() const
830 nlassert((_Index
+1)<_Path
->topologiesPath().size());
832 return _Path
->topologiesPath()[_Index
+1];
835 bool CPathPosition::isFinished() const
837 uint32 size
= (uint32
)_Path
->topologiesPath().size();
838 return (size
==0 || _Index
==size
-1);
841 bool CPathPosition::nextTopology()
844 return _Index
<_Path
->topologiesPath().size();
847 bool CPathPosition::haveNextTopology(uint nbTopo
)
849 return (_Index
+nbTopo
)<_Path
->topologiesPath().size();
852 //////////////////////////////////////////////////////////////////////////////
853 //////////////////////////////////////////////////////////////////////////////
854 //////////////////////////////////////////////////////////////////////////////