DetourNavMeshQuery.cpp 99 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #include <float.h>
  19. #include <string.h>
  20. #include "DetourNavMeshQuery.h"
  21. #include "DetourNavMesh.h"
  22. #include "DetourNode.h"
  23. #include "DetourCommon.h"
  24. #include "DetourMath.h"
  25. #include "DetourAlloc.h"
  26. #include "DetourAssert.h"
  27. #include <new>
  28. /// @class dtQueryFilter
  29. ///
  30. /// <b>The Default Implementation</b>
  31. ///
  32. /// At construction: All area costs default to 1.0. All flags are included
  33. /// and none are excluded.
  34. ///
  35. /// If a polygon has both an include and an exclude flag, it will be excluded.
  36. ///
  37. /// The way filtering works, a navigation mesh polygon must have at least one flag
  38. /// set to ever be considered by a query. So a polygon with no flags will never
  39. /// be considered.
  40. ///
  41. /// Setting the include flags to 0 will result in all polygons being excluded.
  42. ///
  43. /// <b>Custom Implementations</b>
  44. ///
  45. /// DT_VIRTUAL_QUERYFILTER must be defined in order to extend this class.
  46. ///
  47. /// Implement a custom query filter by overriding the virtual passFilter()
  48. /// and getCost() functions. If this is done, both functions should be as
  49. /// fast as possible. Use cached local copies of data rather than accessing
  50. /// your own objects where possible.
  51. ///
  52. /// Custom implementations do not need to adhere to the flags or cost logic
  53. /// used by the default implementation.
  54. ///
  55. /// In order for A* searches to work properly, the cost should be proportional to
  56. /// the travel distance. Implementing a cost modifier less than 1.0 is likely
  57. /// to lead to problems during pathfinding.
  58. ///
  59. /// @see dtNavMeshQuery
  60. dtQueryFilter::dtQueryFilter() :
  61. m_includeFlags(0xffff),
  62. m_excludeFlags(0)
  63. {
  64. for (int i = 0; i < DT_MAX_AREAS; ++i)
  65. m_areaCost[i] = 1.0f;
  66. }
  67. #ifdef DT_VIRTUAL_QUERYFILTER
  68. bool dtQueryFilter::passFilter(const dtPolyRef /*ref*/,
  69. const dtMeshTile* /*tile*/,
  70. const dtPoly* poly) const
  71. {
  72. return (poly->flags & m_includeFlags) != 0 && (poly->flags & m_excludeFlags) == 0;
  73. }
  74. float dtQueryFilter::getCost(const float* pa, const float* pb,
  75. const dtPolyRef /*prevRef*/, const dtMeshTile* /*prevTile*/, const dtPoly* /*prevPoly*/,
  76. const dtPolyRef /*curRef*/, const dtMeshTile* /*curTile*/, const dtPoly* curPoly,
  77. const dtPolyRef /*nextRef*/, const dtMeshTile* /*nextTile*/, const dtPoly* /*nextPoly*/) const
  78. {
  79. return dtVdist(pa, pb) * m_areaCost[curPoly->getArea()];
  80. }
  81. #else
  82. inline bool dtQueryFilter::passFilter(const dtPolyRef /*ref*/,
  83. const dtMeshTile* /*tile*/,
  84. const dtPoly* poly) const
  85. {
  86. return (poly->flags & m_includeFlags) != 0 && (poly->flags & m_excludeFlags) == 0;
  87. }
  88. inline float dtQueryFilter::getCost(const float* pa, const float* pb,
  89. const dtPolyRef /*prevRef*/, const dtMeshTile* /*prevTile*/, const dtPoly* /*prevPoly*/,
  90. const dtPolyRef /*curRef*/, const dtMeshTile* /*curTile*/, const dtPoly* curPoly,
  91. const dtPolyRef /*nextRef*/, const dtMeshTile* /*nextTile*/, const dtPoly* /*nextPoly*/) const
  92. {
  93. return dtVdist(pa, pb) * m_areaCost[curPoly->getArea()];
  94. }
  95. #endif
  96. static const float H_SCALE = 0.999f; // Search heuristic scale.
  97. dtNavMeshQuery* dtAllocNavMeshQuery()
  98. {
  99. void* mem = dtAlloc(sizeof(dtNavMeshQuery), DT_ALLOC_PERM);
  100. if (!mem) return 0;
  101. return new(mem) dtNavMeshQuery;
  102. }
  103. void dtFreeNavMeshQuery(dtNavMeshQuery* navmesh)
  104. {
  105. if (!navmesh) return;
  106. navmesh->~dtNavMeshQuery();
  107. dtFree(navmesh);
  108. }
  109. //////////////////////////////////////////////////////////////////////////////////////////
  110. /// @class dtNavMeshQuery
  111. ///
  112. /// For methods that support undersized buffers, if the buffer is too small
  113. /// to hold the entire result set the return status of the method will include
  114. /// the #DT_BUFFER_TOO_SMALL flag.
  115. ///
  116. /// Constant member functions can be used by multiple clients without side
  117. /// effects. (E.g. No change to the closed list. No impact on an in-progress
  118. /// sliced path query. Etc.)
  119. ///
  120. /// Walls and portals: A @e wall is a polygon segment that is
  121. /// considered impassable. A @e portal is a passable segment between polygons.
  122. /// A portal may be treated as a wall based on the dtQueryFilter used for a query.
  123. ///
  124. /// @see dtNavMesh, dtQueryFilter, #dtAllocNavMeshQuery(), #dtAllocNavMeshQuery()
  125. dtNavMeshQuery::dtNavMeshQuery() :
  126. m_nav(0),
  127. m_tinyNodePool(0),
  128. m_nodePool(0),
  129. m_openList(0)
  130. {
  131. memset(&m_query, 0, sizeof(dtQueryData));
  132. }
  133. dtNavMeshQuery::~dtNavMeshQuery()
  134. {
  135. if (m_tinyNodePool)
  136. m_tinyNodePool->~dtNodePool();
  137. if (m_nodePool)
  138. m_nodePool->~dtNodePool();
  139. if (m_openList)
  140. m_openList->~dtNodeQueue();
  141. dtFree(m_tinyNodePool);
  142. dtFree(m_nodePool);
  143. dtFree(m_openList);
  144. }
  145. /// @par
  146. ///
  147. /// Must be the first function called after construction, before other
  148. /// functions are used.
  149. ///
  150. /// This function can be used multiple times.
  151. dtStatus dtNavMeshQuery::init(const dtNavMesh* nav, const int maxNodes)
  152. {
  153. m_nav = nav;
  154. if (!m_nodePool || m_nodePool->getMaxNodes() < maxNodes)
  155. {
  156. if (m_nodePool)
  157. {
  158. m_nodePool->~dtNodePool();
  159. dtFree(m_nodePool);
  160. m_nodePool = 0;
  161. }
  162. m_nodePool = new (dtAlloc(sizeof(dtNodePool), DT_ALLOC_PERM)) dtNodePool(maxNodes, dtNextPow2(maxNodes/4));
  163. if (!m_nodePool)
  164. return DT_FAILURE | DT_OUT_OF_MEMORY;
  165. }
  166. else
  167. {
  168. m_nodePool->clear();
  169. }
  170. if (!m_tinyNodePool)
  171. {
  172. m_tinyNodePool = new (dtAlloc(sizeof(dtNodePool), DT_ALLOC_PERM)) dtNodePool(64, 32);
  173. if (!m_tinyNodePool)
  174. return DT_FAILURE | DT_OUT_OF_MEMORY;
  175. }
  176. else
  177. {
  178. m_tinyNodePool->clear();
  179. }
  180. // TODO: check the open list size too.
  181. if (!m_openList || m_openList->getCapacity() < maxNodes)
  182. {
  183. if (m_openList)
  184. {
  185. m_openList->~dtNodeQueue();
  186. dtFree(m_openList);
  187. m_openList = 0;
  188. }
  189. m_openList = new (dtAlloc(sizeof(dtNodeQueue), DT_ALLOC_PERM)) dtNodeQueue(maxNodes);
  190. if (!m_openList)
  191. return DT_FAILURE | DT_OUT_OF_MEMORY;
  192. }
  193. else
  194. {
  195. m_openList->clear();
  196. }
  197. return DT_SUCCESS;
  198. }
  199. dtStatus dtNavMeshQuery::findRandomPoint(const dtQueryFilter* filter, float (*frand)(),
  200. dtPolyRef* randomRef, float* randomPt) const
  201. {
  202. dtAssert(m_nav);
  203. // Randomly pick one tile. Assume that all tiles cover roughly the same area.
  204. const dtMeshTile* tile = 0;
  205. float tsum = 0.0f;
  206. for (int i = 0; i < m_nav->getMaxTiles(); i++)
  207. {
  208. const dtMeshTile* t = m_nav->getTile(i);
  209. if (!t || !t->header) continue;
  210. // Choose random tile using reservoi sampling.
  211. const float area = 1.0f; // Could be tile area too.
  212. tsum += area;
  213. const float u = frand();
  214. if (u*tsum <= area)
  215. tile = t;
  216. }
  217. if (!tile)
  218. return DT_FAILURE;
  219. // Randomly pick one polygon weighted by polygon area.
  220. const dtPoly* poly = 0;
  221. dtPolyRef polyRef = 0;
  222. const dtPolyRef base = m_nav->getPolyRefBase(tile);
  223. float areaSum = 0.0f;
  224. for (int i = 0; i < tile->header->polyCount; ++i)
  225. {
  226. const dtPoly* p = &tile->polys[i];
  227. // Do not return off-mesh connection polygons.
  228. if (p->getType() != DT_POLYTYPE_GROUND)
  229. continue;
  230. // Must pass filter
  231. const dtPolyRef ref = base | (dtPolyRef)i;
  232. if (!filter->passFilter(ref, tile, p))
  233. continue;
  234. // Calc area of the polygon.
  235. float polyArea = 0.0f;
  236. for (int j = 2; j < p->vertCount; ++j)
  237. {
  238. const float* va = &tile->verts[p->verts[0]*3];
  239. const float* vb = &tile->verts[p->verts[j-1]*3];
  240. const float* vc = &tile->verts[p->verts[j]*3];
  241. polyArea += dtTriArea2D(va,vb,vc);
  242. }
  243. // Choose random polygon weighted by area, using reservoi sampling.
  244. areaSum += polyArea;
  245. const float u = frand();
  246. if (u*areaSum <= polyArea)
  247. {
  248. poly = p;
  249. polyRef = ref;
  250. }
  251. }
  252. if (!poly)
  253. return DT_FAILURE;
  254. // Randomly pick point on polygon.
  255. const float* v = &tile->verts[poly->verts[0]*3];
  256. float verts[3*DT_VERTS_PER_POLYGON];
  257. float areas[DT_VERTS_PER_POLYGON];
  258. dtVcopy(&verts[0*3],v);
  259. for (int j = 1; j < poly->vertCount; ++j)
  260. {
  261. v = &tile->verts[poly->verts[j]*3];
  262. dtVcopy(&verts[j*3],v);
  263. }
  264. const float s = frand();
  265. const float t = frand();
  266. float pt[3];
  267. dtRandomPointInConvexPoly(verts, poly->vertCount, areas, s, t, pt);
  268. float h = 0.0f;
  269. dtStatus status = getPolyHeight(polyRef, pt, &h);
  270. if (dtStatusFailed(status))
  271. return status;
  272. pt[1] = h;
  273. dtVcopy(randomPt, pt);
  274. *randomRef = polyRef;
  275. return DT_SUCCESS;
  276. }
  277. dtStatus dtNavMeshQuery::findRandomPointAroundCircle(dtPolyRef startRef, const float* centerPos, const float maxRadius,
  278. const dtQueryFilter* filter, float (*frand)(),
  279. dtPolyRef* randomRef, float* randomPt) const
  280. {
  281. dtAssert(m_nav);
  282. dtAssert(m_nodePool);
  283. dtAssert(m_openList);
  284. // Validate input
  285. if (!startRef || !m_nav->isValidPolyRef(startRef))
  286. return DT_FAILURE | DT_INVALID_PARAM;
  287. const dtMeshTile* startTile = 0;
  288. const dtPoly* startPoly = 0;
  289. m_nav->getTileAndPolyByRefUnsafe(startRef, &startTile, &startPoly);
  290. if (!filter->passFilter(startRef, startTile, startPoly))
  291. return DT_FAILURE | DT_INVALID_PARAM;
  292. m_nodePool->clear();
  293. m_openList->clear();
  294. dtNode* startNode = m_nodePool->getNode(startRef);
  295. dtVcopy(startNode->pos, centerPos);
  296. startNode->pidx = 0;
  297. startNode->cost = 0;
  298. startNode->total = 0;
  299. startNode->id = startRef;
  300. startNode->flags = DT_NODE_OPEN;
  301. m_openList->push(startNode);
  302. dtStatus status = DT_SUCCESS;
  303. const float radiusSqr = dtSqr(maxRadius);
  304. float areaSum = 0.0f;
  305. const dtMeshTile* randomTile = 0;
  306. const dtPoly* randomPoly = 0;
  307. dtPolyRef randomPolyRef = 0;
  308. while (!m_openList->empty())
  309. {
  310. dtNode* bestNode = m_openList->pop();
  311. bestNode->flags &= ~DT_NODE_OPEN;
  312. bestNode->flags |= DT_NODE_CLOSED;
  313. // Get poly and tile.
  314. // The API input has been cheked already, skip checking internal data.
  315. const dtPolyRef bestRef = bestNode->id;
  316. const dtMeshTile* bestTile = 0;
  317. const dtPoly* bestPoly = 0;
  318. m_nav->getTileAndPolyByRefUnsafe(bestRef, &bestTile, &bestPoly);
  319. // Place random locations on on ground.
  320. if (bestPoly->getType() == DT_POLYTYPE_GROUND)
  321. {
  322. // Calc area of the polygon.
  323. float polyArea = 0.0f;
  324. for (int j = 2; j < bestPoly->vertCount; ++j)
  325. {
  326. const float* va = &bestTile->verts[bestPoly->verts[0]*3];
  327. const float* vb = &bestTile->verts[bestPoly->verts[j-1]*3];
  328. const float* vc = &bestTile->verts[bestPoly->verts[j]*3];
  329. polyArea += dtTriArea2D(va,vb,vc);
  330. }
  331. // Choose random polygon weighted by area, using reservoi sampling.
  332. areaSum += polyArea;
  333. const float u = frand();
  334. if (u*areaSum <= polyArea)
  335. {
  336. randomTile = bestTile;
  337. randomPoly = bestPoly;
  338. randomPolyRef = bestRef;
  339. }
  340. }
  341. // Get parent poly and tile.
  342. dtPolyRef parentRef = 0;
  343. const dtMeshTile* parentTile = 0;
  344. const dtPoly* parentPoly = 0;
  345. if (bestNode->pidx)
  346. parentRef = m_nodePool->getNodeAtIdx(bestNode->pidx)->id;
  347. if (parentRef)
  348. m_nav->getTileAndPolyByRefUnsafe(parentRef, &parentTile, &parentPoly);
  349. for (unsigned int i = bestPoly->firstLink; i != DT_NULL_LINK; i = bestTile->links[i].next)
  350. {
  351. const dtLink* link = &bestTile->links[i];
  352. dtPolyRef neighbourRef = link->ref;
  353. // Skip invalid neighbours and do not follow back to parent.
  354. if (!neighbourRef || neighbourRef == parentRef)
  355. continue;
  356. // Expand to neighbour
  357. const dtMeshTile* neighbourTile = 0;
  358. const dtPoly* neighbourPoly = 0;
  359. m_nav->getTileAndPolyByRefUnsafe(neighbourRef, &neighbourTile, &neighbourPoly);
  360. // Do not advance if the polygon is excluded by the filter.
  361. if (!filter->passFilter(neighbourRef, neighbourTile, neighbourPoly))
  362. continue;
  363. // Find edge and calc distance to the edge.
  364. float va[3], vb[3];
  365. if (!getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, neighbourTile, va, vb))
  366. continue;
  367. // If the circle is not touching the next polygon, skip it.
  368. float tseg;
  369. float distSqr = dtDistancePtSegSqr2D(centerPos, va, vb, tseg);
  370. if (distSqr > radiusSqr)
  371. continue;
  372. dtNode* neighbourNode = m_nodePool->getNode(neighbourRef);
  373. if (!neighbourNode)
  374. {
  375. status |= DT_OUT_OF_NODES;
  376. continue;
  377. }
  378. if (neighbourNode->flags & DT_NODE_CLOSED)
  379. continue;
  380. // Cost
  381. if (neighbourNode->flags == 0)
  382. dtVlerp(neighbourNode->pos, va, vb, 0.5f);
  383. const float total = bestNode->total + dtVdist(bestNode->pos, neighbourNode->pos);
  384. // The node is already in open list and the new result is worse, skip.
  385. if ((neighbourNode->flags & DT_NODE_OPEN) && total >= neighbourNode->total)
  386. continue;
  387. neighbourNode->id = neighbourRef;
  388. neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED);
  389. neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode);
  390. neighbourNode->total = total;
  391. if (neighbourNode->flags & DT_NODE_OPEN)
  392. {
  393. m_openList->modify(neighbourNode);
  394. }
  395. else
  396. {
  397. neighbourNode->flags = DT_NODE_OPEN;
  398. m_openList->push(neighbourNode);
  399. }
  400. }
  401. }
  402. if (!randomPoly)
  403. return DT_FAILURE;
  404. // Randomly pick point on polygon.
  405. const float* v = &randomTile->verts[randomPoly->verts[0]*3];
  406. float verts[3*DT_VERTS_PER_POLYGON];
  407. float areas[DT_VERTS_PER_POLYGON];
  408. dtVcopy(&verts[0*3],v);
  409. for (int j = 1; j < randomPoly->vertCount; ++j)
  410. {
  411. v = &randomTile->verts[randomPoly->verts[j]*3];
  412. dtVcopy(&verts[j*3],v);
  413. }
  414. const float s = frand();
  415. const float t = frand();
  416. float pt[3];
  417. dtRandomPointInConvexPoly(verts, randomPoly->vertCount, areas, s, t, pt);
  418. float h = 0.0f;
  419. dtStatus stat = getPolyHeight(randomPolyRef, pt, &h);
  420. if (dtStatusFailed(status))
  421. return stat;
  422. pt[1] = h;
  423. dtVcopy(randomPt, pt);
  424. *randomRef = randomPolyRef;
  425. return DT_SUCCESS;
  426. }
  427. //////////////////////////////////////////////////////////////////////////////////////////
  428. /// @par
  429. ///
  430. /// Uses the detail polygons to find the surface height. (Most accurate.)
  431. ///
  432. /// @p pos does not have to be within the bounds of the polygon or navigation mesh.
  433. ///
  434. /// See closestPointOnPolyBoundary() for a limited but faster option.
  435. ///
  436. dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const
  437. {
  438. dtAssert(m_nav);
  439. const dtMeshTile* tile = 0;
  440. const dtPoly* poly = 0;
  441. if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly)))
  442. return DT_FAILURE | DT_INVALID_PARAM;
  443. if (!tile)
  444. return DT_FAILURE | DT_INVALID_PARAM;
  445. // Off-mesh connections don't have detail polygons.
  446. if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
  447. {
  448. const float* v0 = &tile->verts[poly->verts[0]*3];
  449. const float* v1 = &tile->verts[poly->verts[1]*3];
  450. const float d0 = dtVdist(pos, v0);
  451. const float d1 = dtVdist(pos, v1);
  452. const float u = d0 / (d0+d1);
  453. dtVlerp(closest, v0, v1, u);
  454. if (posOverPoly)
  455. *posOverPoly = false;
  456. return DT_SUCCESS;
  457. }
  458. const unsigned int ip = (unsigned int)(poly - tile->polys);
  459. const dtPolyDetail* pd = &tile->detailMeshes[ip];
  460. // Clamp point to be inside the polygon.
  461. float verts[DT_VERTS_PER_POLYGON*3];
  462. float edged[DT_VERTS_PER_POLYGON];
  463. float edget[DT_VERTS_PER_POLYGON];
  464. const int nv = poly->vertCount;
  465. for (int i = 0; i < nv; ++i)
  466. dtVcopy(&verts[i*3], &tile->verts[poly->verts[i]*3]);
  467. dtVcopy(closest, pos);
  468. if (!dtDistancePtPolyEdgesSqr(pos, verts, nv, edged, edget))
  469. {
  470. // Point is outside the polygon, dtClamp to nearest edge.
  471. float dmin = FLT_MAX;
  472. int imin = -1;
  473. for (int i = 0; i < nv; ++i)
  474. {
  475. if (edged[i] < dmin)
  476. {
  477. dmin = edged[i];
  478. imin = i;
  479. }
  480. }
  481. const float* va = &verts[imin*3];
  482. const float* vb = &verts[((imin+1)%nv)*3];
  483. dtVlerp(closest, va, vb, edget[imin]);
  484. if (posOverPoly)
  485. *posOverPoly = false;
  486. }
  487. else
  488. {
  489. if (posOverPoly)
  490. *posOverPoly = true;
  491. }
  492. // Find height at the location.
  493. for (int j = 0; j < pd->triCount; ++j)
  494. {
  495. const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
  496. const float* v[3];
  497. for (int k = 0; k < 3; ++k)
  498. {
  499. if (t[k] < poly->vertCount)
  500. v[k] = &tile->verts[poly->verts[t[k]]*3];
  501. else
  502. v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3];
  503. }
  504. float h;
  505. if (dtClosestHeightPointTriangle(pos, v[0], v[1], v[2], h))
  506. {
  507. closest[1] = h;
  508. break;
  509. }
  510. }
  511. return DT_SUCCESS;
  512. }
  513. /// @par
  514. ///
  515. /// Much faster than closestPointOnPoly().
  516. ///
  517. /// If the provided position lies within the polygon's xz-bounds (above or below),
  518. /// then @p pos and @p closest will be equal.
  519. ///
  520. /// The height of @p closest will be the polygon boundary. The height detail is not used.
  521. ///
  522. /// @p pos does not have to be within the bounds of the polybon or the navigation mesh.
  523. ///
  524. dtStatus dtNavMeshQuery::closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const
  525. {
  526. dtAssert(m_nav);
  527. const dtMeshTile* tile = 0;
  528. const dtPoly* poly = 0;
  529. if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly)))
  530. return DT_FAILURE | DT_INVALID_PARAM;
  531. // Collect vertices.
  532. float verts[DT_VERTS_PER_POLYGON*3];
  533. float edged[DT_VERTS_PER_POLYGON];
  534. float edget[DT_VERTS_PER_POLYGON];
  535. int nv = 0;
  536. for (int i = 0; i < (int)poly->vertCount; ++i)
  537. {
  538. dtVcopy(&verts[nv*3], &tile->verts[poly->verts[i]*3]);
  539. nv++;
  540. }
  541. bool inside = dtDistancePtPolyEdgesSqr(pos, verts, nv, edged, edget);
  542. if (inside)
  543. {
  544. // Point is inside the polygon, return the point.
  545. dtVcopy(closest, pos);
  546. }
  547. else
  548. {
  549. // Point is outside the polygon, dtClamp to nearest edge.
  550. float dmin = FLT_MAX;
  551. int imin = -1;
  552. for (int i = 0; i < nv; ++i)
  553. {
  554. if (edged[i] < dmin)
  555. {
  556. dmin = edged[i];
  557. imin = i;
  558. }
  559. }
  560. const float* va = &verts[imin*3];
  561. const float* vb = &verts[((imin+1)%nv)*3];
  562. dtVlerp(closest, va, vb, edget[imin]);
  563. }
  564. return DT_SUCCESS;
  565. }
  566. /// @par
  567. ///
  568. /// Will return #DT_FAILURE if the provided position is outside the xz-bounds
  569. /// of the polygon.
  570. ///
  571. dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* height) const
  572. {
  573. dtAssert(m_nav);
  574. const dtMeshTile* tile = 0;
  575. const dtPoly* poly = 0;
  576. if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly)))
  577. return DT_FAILURE | DT_INVALID_PARAM;
  578. if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
  579. {
  580. const float* v0 = &tile->verts[poly->verts[0]*3];
  581. const float* v1 = &tile->verts[poly->verts[1]*3];
  582. const float d0 = dtVdist2D(pos, v0);
  583. const float d1 = dtVdist2D(pos, v1);
  584. const float u = d0 / (d0+d1);
  585. if (height)
  586. *height = v0[1] + (v1[1] - v0[1]) * u;
  587. return DT_SUCCESS;
  588. }
  589. else
  590. {
  591. const unsigned int ip = (unsigned int)(poly - tile->polys);
  592. const dtPolyDetail* pd = &tile->detailMeshes[ip];
  593. for (int j = 0; j < pd->triCount; ++j)
  594. {
  595. const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
  596. const float* v[3];
  597. for (int k = 0; k < 3; ++k)
  598. {
  599. if (t[k] < poly->vertCount)
  600. v[k] = &tile->verts[poly->verts[t[k]]*3];
  601. else
  602. v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3];
  603. }
  604. float h;
  605. if (dtClosestHeightPointTriangle(pos, v[0], v[1], v[2], h))
  606. {
  607. if (height)
  608. *height = h;
  609. return DT_SUCCESS;
  610. }
  611. }
  612. }
  613. return DT_FAILURE | DT_INVALID_PARAM;
  614. }
  615. /// @par
  616. ///
  617. /// @note If the search box does not intersect any polygons the search will
  618. /// return #DT_SUCCESS, but @p nearestRef will be zero. So if in doubt, check
  619. /// @p nearestRef before using @p nearestPt.
  620. ///
  621. /// @warning This function is not suitable for large area searches. If the search
  622. /// extents overlaps more than MAX_SEARCH (128) polygons it may return an invalid result.
  623. ///
  624. dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* extents,
  625. const dtQueryFilter* filter,
  626. dtPolyRef* nearestRef, float* nearestPt) const
  627. {
  628. dtAssert(m_nav);
  629. *nearestRef = 0;
  630. // Get nearby polygons from proximity grid.
  631. const int MAX_SEARCH = 128;
  632. dtPolyRef polys[MAX_SEARCH];
  633. int polyCount = 0;
  634. if (dtStatusFailed(queryPolygons(center, extents, filter, polys, &polyCount, MAX_SEARCH)))
  635. return DT_FAILURE | DT_INVALID_PARAM;
  636. // Find nearest polygon amongst the nearby polygons.
  637. dtPolyRef nearest = 0;
  638. float nearestDistanceSqr = FLT_MAX;
  639. for (int i = 0; i < polyCount; ++i)
  640. {
  641. dtPolyRef ref = polys[i];
  642. float closestPtPoly[3];
  643. float diff[3];
  644. bool posOverPoly = false;
  645. float d = 0;
  646. closestPointOnPoly(ref, center, closestPtPoly, &posOverPoly);
  647. // If a point is directly over a polygon and closer than
  648. // climb height, favor that instead of straight line nearest point.
  649. dtVsub(diff, center, closestPtPoly);
  650. if (posOverPoly)
  651. {
  652. const dtMeshTile* tile = 0;
  653. const dtPoly* poly = 0;
  654. m_nav->getTileAndPolyByRefUnsafe(polys[i], &tile, &poly);
  655. d = dtAbs(diff[1]) - tile->header->walkableClimb;
  656. d = d > 0 ? d*d : 0;
  657. }
  658. else
  659. {
  660. d = dtVlenSqr(diff);
  661. }
  662. if (d < nearestDistanceSqr)
  663. {
  664. if (nearestPt)
  665. dtVcopy(nearestPt, closestPtPoly);
  666. nearestDistanceSqr = d;
  667. nearest = ref;
  668. }
  669. }
  670. if (nearestRef)
  671. *nearestRef = nearest;
  672. return DT_SUCCESS;
  673. }
  674. int dtNavMeshQuery::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, const float* qmax,
  675. const dtQueryFilter* filter,
  676. dtPolyRef* polys, const int maxPolys) const
  677. {
  678. dtAssert(m_nav);
  679. if (tile->bvTree)
  680. {
  681. const dtBVNode* node = &tile->bvTree[0];
  682. const dtBVNode* end = &tile->bvTree[tile->header->bvNodeCount];
  683. const float* tbmin = tile->header->bmin;
  684. const float* tbmax = tile->header->bmax;
  685. const float qfac = tile->header->bvQuantFactor;
  686. // Calculate quantized box
  687. unsigned short bmin[3], bmax[3];
  688. // dtClamp query box to world box.
  689. float minx = dtClamp(qmin[0], tbmin[0], tbmax[0]) - tbmin[0];
  690. float miny = dtClamp(qmin[1], tbmin[1], tbmax[1]) - tbmin[1];
  691. float minz = dtClamp(qmin[2], tbmin[2], tbmax[2]) - tbmin[2];
  692. float maxx = dtClamp(qmax[0], tbmin[0], tbmax[0]) - tbmin[0];
  693. float maxy = dtClamp(qmax[1], tbmin[1], tbmax[1]) - tbmin[1];
  694. float maxz = dtClamp(qmax[2], tbmin[2], tbmax[2]) - tbmin[2];
  695. // Quantize
  696. bmin[0] = (unsigned short)(qfac * minx) & 0xfffe;
  697. bmin[1] = (unsigned short)(qfac * miny) & 0xfffe;
  698. bmin[2] = (unsigned short)(qfac * minz) & 0xfffe;
  699. bmax[0] = (unsigned short)(qfac * maxx + 1) | 1;
  700. bmax[1] = (unsigned short)(qfac * maxy + 1) | 1;
  701. bmax[2] = (unsigned short)(qfac * maxz + 1) | 1;
  702. // Traverse tree
  703. const dtPolyRef base = m_nav->getPolyRefBase(tile);
  704. int n = 0;
  705. while (node < end)
  706. {
  707. const bool overlap = dtOverlapQuantBounds(bmin, bmax, node->bmin, node->bmax);
  708. const bool isLeafNode = node->i >= 0;
  709. if (isLeafNode && overlap)
  710. {
  711. dtPolyRef ref = base | (dtPolyRef)node->i;
  712. if (filter->passFilter(ref, tile, &tile->polys[node->i]))
  713. {
  714. if (n < maxPolys)
  715. polys[n++] = ref;
  716. }
  717. }
  718. if (overlap || isLeafNode)
  719. node++;
  720. else
  721. {
  722. const int escapeIndex = -node->i;
  723. node += escapeIndex;
  724. }
  725. }
  726. return n;
  727. }
  728. else
  729. {
  730. float bmin[3], bmax[3];
  731. int n = 0;
  732. const dtPolyRef base = m_nav->getPolyRefBase(tile);
  733. for (int i = 0; i < tile->header->polyCount; ++i)
  734. {
  735. const dtPoly* p = &tile->polys[i];
  736. // Do not return off-mesh connection polygons.
  737. if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
  738. continue;
  739. // Must pass filter
  740. const dtPolyRef ref = base | (dtPolyRef)i;
  741. if (!filter->passFilter(ref, tile, p))
  742. continue;
  743. // Calc polygon bounds.
  744. const float* v = &tile->verts[p->verts[0]*3];
  745. dtVcopy(bmin, v);
  746. dtVcopy(bmax, v);
  747. for (int j = 1; j < p->vertCount; ++j)
  748. {
  749. v = &tile->verts[p->verts[j]*3];
  750. dtVmin(bmin, v);
  751. dtVmax(bmax, v);
  752. }
  753. if (dtOverlapBounds(qmin,qmax, bmin,bmax))
  754. {
  755. if (n < maxPolys)
  756. polys[n++] = ref;
  757. }
  758. }
  759. return n;
  760. }
  761. }
  762. /// @par
  763. ///
  764. /// If no polygons are found, the function will return #DT_SUCCESS with a
  765. /// @p polyCount of zero.
  766. ///
  767. /// If @p polys is too small to hold the entire result set, then the array will
  768. /// be filled to capacity. The method of choosing which polygons from the
  769. /// full set are included in the partial result set is undefined.
  770. ///
  771. dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* extents,
  772. const dtQueryFilter* filter,
  773. dtPolyRef* polys, int* polyCount, const int maxPolys) const
  774. {
  775. dtAssert(m_nav);
  776. float bmin[3], bmax[3];
  777. dtVsub(bmin, center, extents);
  778. dtVadd(bmax, center, extents);
  779. // Find tiles the query touches.
  780. int minx, miny, maxx, maxy;
  781. m_nav->calcTileLoc(bmin, &minx, &miny);
  782. m_nav->calcTileLoc(bmax, &maxx, &maxy);
  783. static const int MAX_NEIS = 32;
  784. const dtMeshTile* neis[MAX_NEIS];
  785. int n = 0;
  786. for (int y = miny; y <= maxy; ++y)
  787. {
  788. for (int x = minx; x <= maxx; ++x)
  789. {
  790. const int nneis = m_nav->getTilesAt(x,y,neis,MAX_NEIS);
  791. for (int j = 0; j < nneis; ++j)
  792. {
  793. n += queryPolygonsInTile(neis[j], bmin, bmax, filter, polys+n, maxPolys-n);
  794. if (n >= maxPolys)
  795. {
  796. *polyCount = n;
  797. return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
  798. }
  799. }
  800. }
  801. }
  802. *polyCount = n;
  803. return DT_SUCCESS;
  804. }
  805. /// @par
  806. ///
  807. /// If the end polygon cannot be reached through the navigation graph,
  808. /// the last polygon in the path will be the nearest the end polygon.
  809. ///
  810. /// If the path array is to small to hold the full result, it will be filled as
  811. /// far as possible from the start polygon toward the end polygon.
  812. ///
  813. /// The start and end positions are used to calculate traversal costs.
  814. /// (The y-values impact the result.)
  815. ///
  816. dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef,
  817. const float* startPos, const float* endPos,
  818. const dtQueryFilter* filter,
  819. dtPolyRef* path, int* pathCount, const int maxPath) const
  820. {
  821. dtAssert(m_nav);
  822. dtAssert(m_nodePool);
  823. dtAssert(m_openList);
  824. *pathCount = 0;
  825. if (!startRef || !endRef)
  826. return DT_FAILURE | DT_INVALID_PARAM;
  827. if (!maxPath)
  828. return DT_FAILURE | DT_INVALID_PARAM;
  829. // Validate input
  830. if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef))
  831. return DT_FAILURE | DT_INVALID_PARAM;
  832. if (startRef == endRef)
  833. {
  834. path[0] = startRef;
  835. *pathCount = 1;
  836. return DT_SUCCESS;
  837. }
  838. m_nodePool->clear();
  839. m_openList->clear();
  840. dtNode* startNode = m_nodePool->getNode(startRef);
  841. dtVcopy(startNode->pos, startPos);
  842. startNode->pidx = 0;
  843. startNode->cost = 0;
  844. startNode->total = dtVdist(startPos, endPos) * H_SCALE;
  845. startNode->id = startRef;
  846. startNode->flags = DT_NODE_OPEN;
  847. m_openList->push(startNode);
  848. dtNode* lastBestNode = startNode;
  849. float lastBestNodeCost = startNode->total;
  850. dtStatus status = DT_SUCCESS;
  851. while (!m_openList->empty())
  852. {
  853. // Remove node from open list and put it in closed list.
  854. dtNode* bestNode = m_openList->pop();
  855. bestNode->flags &= ~DT_NODE_OPEN;
  856. bestNode->flags |= DT_NODE_CLOSED;
  857. // Reached the goal, stop searching.
  858. if (bestNode->id == endRef)
  859. {
  860. lastBestNode = bestNode;
  861. break;
  862. }
  863. // Get current poly and tile.
  864. // The API input has been cheked already, skip checking internal data.
  865. const dtPolyRef bestRef = bestNode->id;
  866. const dtMeshTile* bestTile = 0;
  867. const dtPoly* bestPoly = 0;
  868. m_nav->getTileAndPolyByRefUnsafe(bestRef, &bestTile, &bestPoly);
  869. // Get parent poly and tile.
  870. dtPolyRef parentRef = 0;
  871. const dtMeshTile* parentTile = 0;
  872. const dtPoly* parentPoly = 0;
  873. if (bestNode->pidx)
  874. parentRef = m_nodePool->getNodeAtIdx(bestNode->pidx)->id;
  875. if (parentRef)
  876. m_nav->getTileAndPolyByRefUnsafe(parentRef, &parentTile, &parentPoly);
  877. for (unsigned int i = bestPoly->firstLink; i != DT_NULL_LINK; i = bestTile->links[i].next)
  878. {
  879. dtPolyRef neighbourRef = bestTile->links[i].ref;
  880. // Skip invalid ids and do not expand back to where we came from.
  881. if (!neighbourRef || neighbourRef == parentRef)
  882. continue;
  883. // Get neighbour poly and tile.
  884. // The API input has been cheked already, skip checking internal data.
  885. const dtMeshTile* neighbourTile = 0;
  886. const dtPoly* neighbourPoly = 0;
  887. m_nav->getTileAndPolyByRefUnsafe(neighbourRef, &neighbourTile, &neighbourPoly);
  888. if (!filter->passFilter(neighbourRef, neighbourTile, neighbourPoly))
  889. continue;
  890. // deal explicitly with crossing tile boundaries
  891. unsigned char crossSide = 0;
  892. if (bestTile->links[i].side != 0xff)
  893. crossSide = bestTile->links[i].side >> 1;
  894. // get the node
  895. dtNode* neighbourNode = m_nodePool->getNode(neighbourRef, crossSide);
  896. if (!neighbourNode)
  897. {
  898. status |= DT_OUT_OF_NODES;
  899. continue;
  900. }
  901. // If the node is visited the first time, calculate node position.
  902. if (neighbourNode->flags == 0)
  903. {
  904. getEdgeMidPoint(bestRef, bestPoly, bestTile,
  905. neighbourRef, neighbourPoly, neighbourTile,
  906. neighbourNode->pos);
  907. }
  908. // Calculate cost and heuristic.
  909. float cost = 0;
  910. float heuristic = 0;
  911. // Special case for last node.
  912. if (neighbourRef == endRef)
  913. {
  914. // Cost
  915. const float curCost = filter->getCost(bestNode->pos, neighbourNode->pos,
  916. parentRef, parentTile, parentPoly,
  917. bestRef, bestTile, bestPoly,
  918. neighbourRef, neighbourTile, neighbourPoly);
  919. const float endCost = filter->getCost(neighbourNode->pos, endPos,
  920. bestRef, bestTile, bestPoly,
  921. neighbourRef, neighbourTile, neighbourPoly,
  922. 0, 0, 0);
  923. cost = bestNode->cost + curCost + endCost;
  924. heuristic = 0;
  925. }
  926. else
  927. {
  928. // Cost
  929. const float curCost = filter->getCost(bestNode->pos, neighbourNode->pos,
  930. parentRef, parentTile, parentPoly,
  931. bestRef, bestTile, bestPoly,
  932. neighbourRef, neighbourTile, neighbourPoly);
  933. cost = bestNode->cost + curCost;
  934. heuristic = dtVdist(neighbourNode->pos, endPos)*H_SCALE;
  935. }
  936. const float total = cost + heuristic;
  937. // The node is already in open list and the new result is worse, skip.
  938. if ((neighbourNode->flags & DT_NODE_OPEN) && total >= neighbourNode->total)
  939. continue;
  940. // The node is already visited and process, and the new result is worse, skip.
  941. if ((neighbourNode->flags & DT_NODE_CLOSED) && total >= neighbourNode->total)
  942. continue;
  943. // Add or update the node.
  944. neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode);
  945. neighbourNode->id = neighbourRef;
  946. neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED);
  947. neighbourNode->cost = cost;
  948. neighbourNode->total = total;
  949. if (neighbourNode->flags & DT_NODE_OPEN)
  950. {
  951. // Already in open, update node location.
  952. m_openList->modify(neighbourNode);
  953. }
  954. else
  955. {
  956. // Put the node in open list.
  957. neighbourNode->flags |= DT_NODE_OPEN;
  958. m_openList->push(neighbourNode);
  959. }
  960. // Update nearest node to target so far.
  961. if (heuristic < lastBestNodeCost)
  962. {
  963. lastBestNodeCost = heuristic;
  964. lastBestNode = neighbourNode;
  965. }
  966. }
  967. }
  968. if (lastBestNode->id != endRef)
  969. status |= DT_PARTIAL_RESULT;
  970. // Reverse the path.
  971. dtNode* prev = 0;
  972. dtNode* node = lastBestNode;
  973. do
  974. {
  975. dtNode* next = m_nodePool->getNodeAtIdx(node->pidx);
  976. node->pidx = m_nodePool->getNodeIdx(prev);
  977. prev = node;
  978. node = next;
  979. }
  980. while (node);
  981. // Store path
  982. node = prev;
  983. int n = 0;
  984. do
  985. {
  986. path[n++] = node->id;
  987. if (n >= maxPath)
  988. {
  989. status |= DT_BUFFER_TOO_SMALL;
  990. break;
  991. }
  992. node = m_nodePool->getNodeAtIdx(node->pidx);
  993. }
  994. while (node);
  995. *pathCount = n;
  996. return status;
  997. }
  998. /// @par
  999. ///
  1000. /// @warning Calling any non-slice methods before calling finalizeSlicedFindPath()
  1001. /// or finalizeSlicedFindPathPartial() may result in corrupted data!
  1002. ///
  1003. /// The @p filter pointer is stored and used for the duration of the sliced
  1004. /// path query.
  1005. ///
  1006. dtStatus dtNavMeshQuery::initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef,
  1007. const float* startPos, const float* endPos,
  1008. const dtQueryFilter* filter, const unsigned int options)
  1009. {
  1010. dtAssert(m_nav);
  1011. dtAssert(m_nodePool);
  1012. dtAssert(m_openList);
  1013. // Init path state.
  1014. memset(&m_query, 0, sizeof(dtQueryData));
  1015. m_query.status = DT_FAILURE;
  1016. m_query.startRef = startRef;
  1017. m_query.endRef = endRef;
  1018. dtVcopy(m_query.startPos, startPos);
  1019. dtVcopy(m_query.endPos, endPos);
  1020. m_query.filter = filter;
  1021. m_query.options = options;
  1022. m_query.raycastLimitSqr = FLT_MAX;
  1023. if (!startRef || !endRef)
  1024. return DT_FAILURE | DT_INVALID_PARAM;
  1025. // Validate input
  1026. if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef))
  1027. return DT_FAILURE | DT_INVALID_PARAM;
  1028. // trade quality with performance?
  1029. if (options & DT_FINDPATH_ANY_ANGLE)
  1030. {
  1031. // limiting to several times the character radius yields nice results. It is not sensitive
  1032. // so it is enough to compute it from the first tile.
  1033. const dtMeshTile* tile = m_nav->getTileByRef(startRef);
  1034. float agentRadius = tile->header->walkableRadius;
  1035. m_query.raycastLimitSqr = dtSqr(agentRadius * DT_RAY_CAST_LIMIT_PROPORTIONS);
  1036. }
  1037. if (startRef == endRef)
  1038. {
  1039. m_query.status = DT_SUCCESS;
  1040. return DT_SUCCESS;
  1041. }
  1042. m_nodePool->clear();
  1043. m_openList->clear();
  1044. dtNode* startNode = m_nodePool->getNode(startRef);
  1045. dtVcopy(startNode->pos, startPos);
  1046. startNode->pidx = 0;
  1047. startNode->cost = 0;
  1048. startNode->total = dtVdist(startPos, endPos) * H_SCALE;
  1049. startNode->id = startRef;
  1050. startNode->flags = DT_NODE_OPEN;
  1051. m_openList->push(startNode);
  1052. m_query.status = DT_IN_PROGRESS;
  1053. m_query.lastBestNode = startNode;
  1054. m_query.lastBestNodeCost = startNode->total;
  1055. return m_query.status;
  1056. }
  1057. dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters)
  1058. {
  1059. if (!dtStatusInProgress(m_query.status))
  1060. return m_query.status;
  1061. // Make sure the request is still valid.
  1062. if (!m_nav->isValidPolyRef(m_query.startRef) || !m_nav->isValidPolyRef(m_query.endRef))
  1063. {
  1064. m_query.status = DT_FAILURE;
  1065. return DT_FAILURE;
  1066. }
  1067. dtRaycastHit rayHit;
  1068. rayHit.maxPath = 0;
  1069. int iter = 0;
  1070. while (iter < maxIter && !m_openList->empty())
  1071. {
  1072. iter++;
  1073. // Remove node from open list and put it in closed list.
  1074. dtNode* bestNode = m_openList->pop();
  1075. bestNode->flags &= ~DT_NODE_OPEN;
  1076. bestNode->flags |= DT_NODE_CLOSED;
  1077. // Reached the goal, stop searching.
  1078. if (bestNode->id == m_query.endRef)
  1079. {
  1080. m_query.lastBestNode = bestNode;
  1081. const dtStatus details = m_query.status & DT_STATUS_DETAIL_MASK;
  1082. m_query.status = DT_SUCCESS | details;
  1083. if (doneIters)
  1084. *doneIters = iter;
  1085. return m_query.status;
  1086. }
  1087. // Get current poly and tile.
  1088. // The API input has been cheked already, skip checking internal data.
  1089. const dtPolyRef bestRef = bestNode->id;
  1090. const dtMeshTile* bestTile = 0;
  1091. const dtPoly* bestPoly = 0;
  1092. if (dtStatusFailed(m_nav->getTileAndPolyByRef(bestRef, &bestTile, &bestPoly)))
  1093. {
  1094. // The polygon has disappeared during the sliced query, fail.
  1095. m_query.status = DT_FAILURE;
  1096. if (doneIters)
  1097. *doneIters = iter;
  1098. return m_query.status;
  1099. }
  1100. // Get parent and grand parent poly and tile.
  1101. dtPolyRef parentRef = 0, grandpaRef = 0;
  1102. const dtMeshTile* parentTile = 0;
  1103. const dtPoly* parentPoly = 0;
  1104. dtNode* parentNode = 0;
  1105. if (bestNode->pidx)
  1106. {
  1107. parentNode = m_nodePool->getNodeAtIdx(bestNode->pidx);
  1108. parentRef = parentNode->id;
  1109. if (parentNode->pidx)
  1110. grandpaRef = m_nodePool->getNodeAtIdx(parentNode->pidx)->id;
  1111. }
  1112. if (parentRef)
  1113. {
  1114. bool invalidParent = dtStatusFailed(m_nav->getTileAndPolyByRef(parentRef, &parentTile, &parentPoly));
  1115. if (invalidParent || (grandpaRef && !m_nav->isValidPolyRef(grandpaRef)) )
  1116. {
  1117. // The polygon has disappeared during the sliced query, fail.
  1118. m_query.status = DT_FAILURE;
  1119. if (doneIters)
  1120. *doneIters = iter;
  1121. return m_query.status;
  1122. }
  1123. }
  1124. // decide whether to test raycast to previous nodes
  1125. bool tryLOS = false;
  1126. if (m_query.options & DT_FINDPATH_ANY_ANGLE)
  1127. {
  1128. if ((parentRef != 0) && (dtVdistSqr(parentNode->pos, bestNode->pos) < m_query.raycastLimitSqr))
  1129. tryLOS = true;
  1130. }
  1131. for (unsigned int i = bestPoly->firstLink; i != DT_NULL_LINK; i = bestTile->links[i].next)
  1132. {
  1133. dtPolyRef neighbourRef = bestTile->links[i].ref;
  1134. // Skip invalid ids and do not expand back to where we came from.
  1135. if (!neighbourRef || neighbourRef == parentRef)
  1136. continue;
  1137. // Get neighbour poly and tile.
  1138. // The API input has been cheked already, skip checking internal data.
  1139. const dtMeshTile* neighbourTile = 0;
  1140. const dtPoly* neighbourPoly = 0;
  1141. m_nav->getTileAndPolyByRefUnsafe(neighbourRef, &neighbourTile, &neighbourPoly);
  1142. if (!m_query.filter->passFilter(neighbourRef, neighbourTile, neighbourPoly))
  1143. continue;
  1144. // get the neighbor node
  1145. dtNode* neighbourNode = m_nodePool->getNode(neighbourRef, 0);
  1146. if (!neighbourNode)
  1147. {
  1148. m_query.status |= DT_OUT_OF_NODES;
  1149. continue;
  1150. }
  1151. // do not expand to nodes that were already visited from the same parent
  1152. if (neighbourNode->pidx != 0 && neighbourNode->pidx == bestNode->pidx)
  1153. continue;
  1154. // If the node is visited the first time, calculate node position.
  1155. if (neighbourNode->flags == 0)
  1156. {
  1157. getEdgeMidPoint(bestRef, bestPoly, bestTile,
  1158. neighbourRef, neighbourPoly, neighbourTile,
  1159. neighbourNode->pos);
  1160. }
  1161. // Calculate cost and heuristic.
  1162. float cost = 0;
  1163. float heuristic = 0;
  1164. // raycast parent
  1165. bool foundShortCut = false;
  1166. rayHit.pathCost = rayHit.t = 0;
  1167. if (tryLOS)
  1168. {
  1169. raycast(parentRef, parentNode->pos, neighbourNode->pos, m_query.filter, DT_RAYCAST_USE_COSTS, &rayHit, grandpaRef);
  1170. foundShortCut = rayHit.t >= 1.0f;
  1171. }
  1172. // update move cost
  1173. if (foundShortCut)
  1174. {
  1175. // shortcut found using raycast. Using shorter cost instead
  1176. cost = parentNode->cost + rayHit.pathCost;
  1177. }
  1178. else
  1179. {
  1180. // No shortcut found.
  1181. const float curCost = m_query.filter->getCost(bestNode->pos, neighbourNode->pos,
  1182. parentRef, parentTile, parentPoly,
  1183. bestRef, bestTile, bestPoly,
  1184. neighbourRef, neighbourTile, neighbourPoly);
  1185. cost = bestNode->cost + curCost;
  1186. }
  1187. // Special case for last node.
  1188. if (neighbourRef == m_query.endRef)
  1189. {
  1190. const float endCost = m_query.filter->getCost(neighbourNode->pos, m_query.endPos,
  1191. bestRef, bestTile, bestPoly,
  1192. neighbourRef, neighbourTile, neighbourPoly,
  1193. 0, 0, 0);
  1194. cost = cost + endCost;
  1195. heuristic = 0;
  1196. }
  1197. else
  1198. {
  1199. heuristic = dtVdist(neighbourNode->pos, m_query.endPos)*H_SCALE;
  1200. }
  1201. const float total = cost + heuristic;
  1202. // The node is already in open list and the new result is worse, skip.
  1203. if ((neighbourNode->flags & DT_NODE_OPEN) && total >= neighbourNode->total)
  1204. continue;
  1205. // The node is already visited and process, and the new result is worse, skip.
  1206. if ((neighbourNode->flags & DT_NODE_CLOSED) && total >= neighbourNode->total)
  1207. continue;
  1208. // Add or update the node.
  1209. neighbourNode->pidx = foundShortCut ? bestNode->pidx : m_nodePool->getNodeIdx(bestNode);
  1210. neighbourNode->id = neighbourRef;
  1211. neighbourNode->flags = (neighbourNode->flags & ~(DT_NODE_CLOSED | DT_NODE_PARENT_DETACHED));
  1212. neighbourNode->cost = cost;
  1213. neighbourNode->total = total;
  1214. if (foundShortCut)
  1215. neighbourNode->flags = (neighbourNode->flags | DT_NODE_PARENT_DETACHED);
  1216. if (neighbourNode->flags & DT_NODE_OPEN)
  1217. {
  1218. // Already in open, update node location.
  1219. m_openList->modify(neighbourNode);
  1220. }
  1221. else
  1222. {
  1223. // Put the node in open list.
  1224. neighbourNode->flags |= DT_NODE_OPEN;
  1225. m_openList->push(neighbourNode);
  1226. }
  1227. // Update nearest node to target so far.
  1228. if (heuristic < m_query.lastBestNodeCost)
  1229. {
  1230. m_query.lastBestNodeCost = heuristic;
  1231. m_query.lastBestNode = neighbourNode;
  1232. }
  1233. }
  1234. }
  1235. // Exhausted all nodes, but could not find path.
  1236. if (m_openList->empty())
  1237. {
  1238. const dtStatus details = m_query.status & DT_STATUS_DETAIL_MASK;
  1239. m_query.status = DT_SUCCESS | details;
  1240. }
  1241. if (doneIters)
  1242. *doneIters = iter;
  1243. return m_query.status;
  1244. }
  1245. dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath)
  1246. {
  1247. *pathCount = 0;
  1248. if (dtStatusFailed(m_query.status))
  1249. {
  1250. // Reset query.
  1251. memset(&m_query, 0, sizeof(dtQueryData));
  1252. return DT_FAILURE;
  1253. }
  1254. int n = 0;
  1255. if (m_query.startRef == m_query.endRef)
  1256. {
  1257. // Special case: the search starts and ends at same poly.
  1258. path[n++] = m_query.startRef;
  1259. }
  1260. else
  1261. {
  1262. // Reverse the path.
  1263. dtAssert(m_query.lastBestNode);
  1264. if (m_query.lastBestNode->id != m_query.endRef)
  1265. m_query.status |= DT_PARTIAL_RESULT;
  1266. dtNode* prev = 0;
  1267. dtNode* node = m_query.lastBestNode;
  1268. int prevRay = 0;
  1269. do
  1270. {
  1271. dtNode* next = m_nodePool->getNodeAtIdx(node->pidx);
  1272. node->pidx = m_nodePool->getNodeIdx(prev);
  1273. prev = node;
  1274. int nextRay = node->flags & DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent (i.e. due to raycast shortcut)
  1275. node->flags = (node->flags & ~DT_NODE_PARENT_DETACHED) | prevRay; // and store it in the reversed path's node
  1276. prevRay = nextRay;
  1277. node = next;
  1278. }
  1279. while (node);
  1280. // Store path
  1281. node = prev;
  1282. do
  1283. {
  1284. dtNode* next = m_nodePool->getNodeAtIdx(node->pidx);
  1285. dtStatus status = 0;
  1286. if (node->flags & DT_NODE_PARENT_DETACHED)
  1287. {
  1288. float t, normal[3];
  1289. int m;
  1290. status = raycast(node->id, node->pos, next->pos, m_query.filter, &t, normal, path+n, &m, maxPath-n);
  1291. n += m;
  1292. // raycast ends on poly boundary and the path might include the next poly boundary.
  1293. if (path[n-1] == next->id)
  1294. n--; // remove to avoid duplicates
  1295. }
  1296. else
  1297. {
  1298. path[n++] = node->id;
  1299. if (n >= maxPath)
  1300. status = DT_BUFFER_TOO_SMALL;
  1301. }
  1302. if (status & DT_STATUS_DETAIL_MASK)
  1303. {
  1304. m_query.status |= status & DT_STATUS_DETAIL_MASK;
  1305. break;
  1306. }
  1307. node = next;
  1308. }
  1309. while (node);
  1310. }
  1311. const dtStatus details = m_query.status & DT_STATUS_DETAIL_MASK;
  1312. // Reset query.
  1313. memset(&m_query, 0, sizeof(dtQueryData));
  1314. *pathCount = n;
  1315. return DT_SUCCESS | details;
  1316. }
  1317. dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
  1318. dtPolyRef* path, int* pathCount, const int maxPath)
  1319. {
  1320. *pathCount = 0;
  1321. if (existingSize == 0)
  1322. {
  1323. return DT_FAILURE;
  1324. }
  1325. if (dtStatusFailed(m_query.status))
  1326. {
  1327. // Reset query.
  1328. memset(&m_query, 0, sizeof(dtQueryData));
  1329. return DT_FAILURE;
  1330. }
  1331. int n = 0;
  1332. if (m_query.startRef == m_query.endRef)
  1333. {
  1334. // Special case: the search starts and ends at same poly.
  1335. path[n++] = m_query.startRef;
  1336. }
  1337. else
  1338. {
  1339. // Find furthest existing node that was visited.
  1340. dtNode* prev = 0;
  1341. dtNode* node = 0;
  1342. for (int i = existingSize-1; i >= 0; --i)
  1343. {
  1344. m_nodePool->findNodes(existing[i], &node, 1);
  1345. if (node)
  1346. break;
  1347. }
  1348. if (!node)
  1349. {
  1350. m_query.status |= DT_PARTIAL_RESULT;
  1351. dtAssert(m_query.lastBestNode);
  1352. node = m_query.lastBestNode;
  1353. }
  1354. // Reverse the path.
  1355. int prevRay = 0;
  1356. do
  1357. {
  1358. dtNode* next = m_nodePool->getNodeAtIdx(node->pidx);
  1359. node->pidx = m_nodePool->getNodeIdx(prev);
  1360. prev = node;
  1361. int nextRay = node->flags & DT_NODE_PARENT_DETACHED; // keep track of whether parent is not adjacent (i.e. due to raycast shortcut)
  1362. node->flags = (node->flags & ~DT_NODE_PARENT_DETACHED) | prevRay; // and store it in the reversed path's node
  1363. prevRay = nextRay;
  1364. node = next;
  1365. }
  1366. while (node);
  1367. // Store path
  1368. node = prev;
  1369. do
  1370. {
  1371. dtNode* next = m_nodePool->getNodeAtIdx(node->pidx);
  1372. dtStatus status = 0;
  1373. if (node->flags & DT_NODE_PARENT_DETACHED)
  1374. {
  1375. float t, normal[3];
  1376. int m;
  1377. status = raycast(node->id, node->pos, next->pos, m_query.filter, &t, normal, path+n, &m, maxPath-n);
  1378. n += m;
  1379. // raycast ends on poly boundary and the path might include the next poly boundary.
  1380. if (path[n-1] == next->id)
  1381. n--; // remove to avoid duplicates
  1382. }
  1383. else
  1384. {
  1385. path[n++] = node->id;
  1386. if (n >= maxPath)
  1387. status = DT_BUFFER_TOO_SMALL;
  1388. }
  1389. if (status & DT_STATUS_DETAIL_MASK)
  1390. {
  1391. m_query.status |= status & DT_STATUS_DETAIL_MASK;
  1392. break;
  1393. }
  1394. node = next;
  1395. }
  1396. while (node);
  1397. }
  1398. const dtStatus details = m_query.status & DT_STATUS_DETAIL_MASK;
  1399. // Reset query.
  1400. memset(&m_query, 0, sizeof(dtQueryData));
  1401. *pathCount = n;
  1402. return DT_SUCCESS | details;
  1403. }
  1404. dtStatus dtNavMeshQuery::appendVertex(const float* pos, const unsigned char flags, const dtPolyRef ref,
  1405. float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
  1406. int* straightPathCount, const int maxStraightPath) const
  1407. {
  1408. if ((*straightPathCount) > 0 && dtVequal(&straightPath[((*straightPathCount)-1)*3], pos))
  1409. {
  1410. // The vertices are equal, update flags and poly.
  1411. if (straightPathFlags)
  1412. straightPathFlags[(*straightPathCount)-1] = flags;
  1413. if (straightPathRefs)
  1414. straightPathRefs[(*straightPathCount)-1] = ref;
  1415. }
  1416. else
  1417. {
  1418. // Append new vertex.
  1419. dtVcopy(&straightPath[(*straightPathCount)*3], pos);
  1420. if (straightPathFlags)
  1421. straightPathFlags[(*straightPathCount)] = flags;
  1422. if (straightPathRefs)
  1423. straightPathRefs[(*straightPathCount)] = ref;
  1424. (*straightPathCount)++;
  1425. // If reached end of path or there is no space to append more vertices, return.
  1426. if (flags == DT_STRAIGHTPATH_END || (*straightPathCount) >= maxStraightPath)
  1427. {
  1428. return DT_SUCCESS | (((*straightPathCount) >= maxStraightPath) ? DT_BUFFER_TOO_SMALL : 0);
  1429. }
  1430. }
  1431. return DT_IN_PROGRESS;
  1432. }
  1433. dtStatus dtNavMeshQuery::appendPortals(const int startIdx, const int endIdx, const float* endPos, const dtPolyRef* path,
  1434. float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
  1435. int* straightPathCount, const int maxStraightPath, const int options) const
  1436. {
  1437. const float* startPos = &straightPath[(*straightPathCount-1)*3];
  1438. // Append or update last vertex
  1439. dtStatus stat = 0;
  1440. for (int i = startIdx; i < endIdx; i++)
  1441. {
  1442. // Calculate portal
  1443. const dtPolyRef from = path[i];
  1444. const dtMeshTile* fromTile = 0;
  1445. const dtPoly* fromPoly = 0;
  1446. if (dtStatusFailed(m_nav->getTileAndPolyByRef(from, &fromTile, &fromPoly)))
  1447. return DT_FAILURE | DT_INVALID_PARAM;
  1448. const dtPolyRef to = path[i+1];
  1449. const dtMeshTile* toTile = 0;
  1450. const dtPoly* toPoly = 0;
  1451. if (dtStatusFailed(m_nav->getTileAndPolyByRef(to, &toTile, &toPoly)))
  1452. return DT_FAILURE | DT_INVALID_PARAM;
  1453. float left[3], right[3];
  1454. if (dtStatusFailed(getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, left, right)))
  1455. break;
  1456. if (options & DT_STRAIGHTPATH_AREA_CROSSINGS)
  1457. {
  1458. // Skip intersection if only area crossings are requested.
  1459. if (fromPoly->getArea() == toPoly->getArea())
  1460. continue;
  1461. }
  1462. // Append intersection
  1463. float s,t;
  1464. if (dtIntersectSegSeg2D(startPos, endPos, left, right, s, t))
  1465. {
  1466. float pt[3];
  1467. dtVlerp(pt, left,right, t);
  1468. stat = appendVertex(pt, 0, path[i+1],
  1469. straightPath, straightPathFlags, straightPathRefs,
  1470. straightPathCount, maxStraightPath);
  1471. if (stat != DT_IN_PROGRESS)
  1472. return stat;
  1473. }
  1474. }
  1475. return DT_IN_PROGRESS;
  1476. }
  1477. /// @par
  1478. ///
  1479. /// This method peforms what is often called 'string pulling'.
  1480. ///
  1481. /// The start position is clamped to the first polygon in the path, and the
  1482. /// end position is clamped to the last. So the start and end positions should
  1483. /// normally be within or very near the first and last polygons respectively.
  1484. ///
  1485. /// The returned polygon references represent the reference id of the polygon
  1486. /// that is entered at the associated path position. The reference id associated
  1487. /// with the end point will always be zero. This allows, for example, matching
  1488. /// off-mesh link points to their representative polygons.
  1489. ///
  1490. /// If the provided result buffers are too small for the entire result set,
  1491. /// they will be filled as far as possible from the start toward the end
  1492. /// position.
  1493. ///
  1494. dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* endPos,
  1495. const dtPolyRef* path, const int pathSize,
  1496. float* straightPath, unsigned char* straightPathFlags, dtPolyRef* straightPathRefs,
  1497. int* straightPathCount, const int maxStraightPath, const int options) const
  1498. {
  1499. dtAssert(m_nav);
  1500. *straightPathCount = 0;
  1501. if (!maxStraightPath)
  1502. return DT_FAILURE | DT_INVALID_PARAM;
  1503. if (!path[0])
  1504. return DT_FAILURE | DT_INVALID_PARAM;
  1505. dtStatus stat = 0;
  1506. // TODO: Should this be callers responsibility?
  1507. float closestStartPos[3];
  1508. if (dtStatusFailed(closestPointOnPolyBoundary(path[0], startPos, closestStartPos)))
  1509. return DT_FAILURE | DT_INVALID_PARAM;
  1510. float closestEndPos[3];
  1511. if (dtStatusFailed(closestPointOnPolyBoundary(path[pathSize-1], endPos, closestEndPos)))
  1512. return DT_FAILURE | DT_INVALID_PARAM;
  1513. // Add start point.
  1514. stat = appendVertex(closestStartPos, DT_STRAIGHTPATH_START, path[0],
  1515. straightPath, straightPathFlags, straightPathRefs,
  1516. straightPathCount, maxStraightPath);
  1517. if (stat != DT_IN_PROGRESS)
  1518. return stat;
  1519. if (pathSize > 1)
  1520. {
  1521. float portalApex[3], portalLeft[3], portalRight[3];
  1522. dtVcopy(portalApex, closestStartPos);
  1523. dtVcopy(portalLeft, portalApex);
  1524. dtVcopy(portalRight, portalApex);
  1525. int apexIndex = 0;
  1526. int leftIndex = 0;
  1527. int rightIndex = 0;
  1528. unsigned char leftPolyType = 0;
  1529. unsigned char rightPolyType = 0;
  1530. dtPolyRef leftPolyRef = path[0];
  1531. dtPolyRef rightPolyRef = path[0];
  1532. for (int i = 0; i < pathSize; ++i)
  1533. {
  1534. float left[3], right[3];
  1535. unsigned char fromType, toType;
  1536. if (i+1 < pathSize)
  1537. {
  1538. // Next portal.
  1539. if (dtStatusFailed(getPortalPoints(path[i], path[i+1], left, right, fromType, toType)))
  1540. {
  1541. // Failed to get portal points, in practice this means that path[i+1] is invalid polygon.
  1542. // Clamp the end point to path[i], and return the path so far.
  1543. if (dtStatusFailed(closestPointOnPolyBoundary(path[i], endPos, closestEndPos)))
  1544. {
  1545. // This should only happen when the first polygon is invalid.
  1546. return DT_FAILURE | DT_INVALID_PARAM;
  1547. }
  1548. // Apeend portals along the current straight path segment.
  1549. if (options & (DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS))
  1550. {
  1551. stat = appendPortals(apexIndex, i, closestEndPos, path,
  1552. straightPath, straightPathFlags, straightPathRefs,
  1553. straightPathCount, maxStraightPath, options);
  1554. }
  1555. stat = appendVertex(closestEndPos, 0, path[i],
  1556. straightPath, straightPathFlags, straightPathRefs,
  1557. straightPathCount, maxStraightPath);
  1558. return DT_SUCCESS | DT_PARTIAL_RESULT | ((*straightPathCount >= maxStraightPath) ? DT_BUFFER_TOO_SMALL : 0);
  1559. }
  1560. // If starting really close the portal, advance.
  1561. if (i == 0)
  1562. {
  1563. float t;
  1564. if (dtDistancePtSegSqr2D(portalApex, left, right, t) < dtSqr(0.001f))
  1565. continue;
  1566. }
  1567. }
  1568. else
  1569. {
  1570. // End of the path.
  1571. dtVcopy(left, closestEndPos);
  1572. dtVcopy(right, closestEndPos);
  1573. fromType = toType = DT_POLYTYPE_GROUND;
  1574. }
  1575. // Right vertex.
  1576. if (dtTriArea2D(portalApex, portalRight, right) <= 0.0f)
  1577. {
  1578. if (dtVequal(portalApex, portalRight) || dtTriArea2D(portalApex, portalLeft, right) > 0.0f)
  1579. {
  1580. dtVcopy(portalRight, right);
  1581. rightPolyRef = (i+1 < pathSize) ? path[i+1] : 0;
  1582. rightPolyType = toType;
  1583. rightIndex = i;
  1584. }
  1585. else
  1586. {
  1587. // Append portals along the current straight path segment.
  1588. if (options & (DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS))
  1589. {
  1590. stat = appendPortals(apexIndex, leftIndex, portalLeft, path,
  1591. straightPath, straightPathFlags, straightPathRefs,
  1592. straightPathCount, maxStraightPath, options);
  1593. if (stat != DT_IN_PROGRESS)
  1594. return stat;
  1595. }
  1596. dtVcopy(portalApex, portalLeft);
  1597. apexIndex = leftIndex;
  1598. unsigned char flags = 0;
  1599. if (!leftPolyRef)
  1600. flags = DT_STRAIGHTPATH_END;
  1601. else if (leftPolyType == DT_POLYTYPE_OFFMESH_CONNECTION)
  1602. flags = DT_STRAIGHTPATH_OFFMESH_CONNECTION;
  1603. dtPolyRef ref = leftPolyRef;
  1604. // Append or update vertex
  1605. stat = appendVertex(portalApex, flags, ref,
  1606. straightPath, straightPathFlags, straightPathRefs,
  1607. straightPathCount, maxStraightPath);
  1608. if (stat != DT_IN_PROGRESS)
  1609. return stat;
  1610. dtVcopy(portalLeft, portalApex);
  1611. dtVcopy(portalRight, portalApex);
  1612. leftIndex = apexIndex;
  1613. rightIndex = apexIndex;
  1614. // Restart
  1615. i = apexIndex;
  1616. continue;
  1617. }
  1618. }
  1619. // Left vertex.
  1620. if (dtTriArea2D(portalApex, portalLeft, left) >= 0.0f)
  1621. {
  1622. if (dtVequal(portalApex, portalLeft) || dtTriArea2D(portalApex, portalRight, left) < 0.0f)
  1623. {
  1624. dtVcopy(portalLeft, left);
  1625. leftPolyRef = (i+1 < pathSize) ? path[i+1] : 0;
  1626. leftPolyType = toType;
  1627. leftIndex = i;
  1628. }
  1629. else
  1630. {
  1631. // Append portals along the current straight path segment.
  1632. if (options & (DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS))
  1633. {
  1634. stat = appendPortals(apexIndex, rightIndex, portalRight, path,
  1635. straightPath, straightPathFlags, straightPathRefs,
  1636. straightPathCount, maxStraightPath, options);
  1637. if (stat != DT_IN_PROGRESS)
  1638. return stat;
  1639. }
  1640. dtVcopy(portalApex, portalRight);
  1641. apexIndex = rightIndex;
  1642. unsigned char flags = 0;
  1643. if (!rightPolyRef)
  1644. flags = DT_STRAIGHTPATH_END;
  1645. else if (rightPolyType == DT_POLYTYPE_OFFMESH_CONNECTION)
  1646. flags = DT_STRAIGHTPATH_OFFMESH_CONNECTION;
  1647. dtPolyRef ref = rightPolyRef;
  1648. // Append or update vertex
  1649. stat = appendVertex(portalApex, flags, ref,
  1650. straightPath, straightPathFlags, straightPathRefs,
  1651. straightPathCount, maxStraightPath);
  1652. if (stat != DT_IN_PROGRESS)
  1653. return stat;
  1654. dtVcopy(portalLeft, portalApex);
  1655. dtVcopy(portalRight, portalApex);
  1656. leftIndex = apexIndex;
  1657. rightIndex = apexIndex;
  1658. // Restart
  1659. i = apexIndex;
  1660. continue;
  1661. }
  1662. }
  1663. }
  1664. // Append portals along the current straight path segment.
  1665. if (options & (DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS))
  1666. {
  1667. stat = appendPortals(apexIndex, pathSize-1, closestEndPos, path,
  1668. straightPath, straightPathFlags, straightPathRefs,
  1669. straightPathCount, maxStraightPath, options);
  1670. if (stat != DT_IN_PROGRESS)
  1671. return stat;
  1672. }
  1673. }
  1674. stat = appendVertex(closestEndPos, DT_STRAIGHTPATH_END, 0,
  1675. straightPath, straightPathFlags, straightPathRefs,
  1676. straightPathCount, maxStraightPath);
  1677. return DT_SUCCESS | ((*straightPathCount >= maxStraightPath) ? DT_BUFFER_TOO_SMALL : 0);
  1678. }
  1679. /// @par
  1680. ///
  1681. /// This method is optimized for small delta movement and a small number of
  1682. /// polygons. If used for too great a distance, the result set will form an
  1683. /// incomplete path.
  1684. ///
  1685. /// @p resultPos will equal the @p endPos if the end is reached.
  1686. /// Otherwise the closest reachable position will be returned.
  1687. ///
  1688. /// @p resultPos is not projected onto the surface of the navigation
  1689. /// mesh. Use #getPolyHeight if this is needed.
  1690. ///
  1691. /// This method treats the end position in the same manner as
  1692. /// the #raycast method. (As a 2D point.) See that method's documentation
  1693. /// for details.
  1694. ///
  1695. /// If the @p visited array is too small to hold the entire result set, it will
  1696. /// be filled as far as possible from the start position toward the end
  1697. /// position.
  1698. ///
  1699. dtStatus dtNavMeshQuery::moveAlongSurface(dtPolyRef startRef, const float* startPos, const float* endPos,
  1700. const dtQueryFilter* filter,
  1701. float* resultPos, dtPolyRef* visited, int* visitedCount, const int maxVisitedSize) const
  1702. {
  1703. dtAssert(m_nav);
  1704. dtAssert(m_tinyNodePool);
  1705. *visitedCount = 0;
  1706. // Validate input
  1707. if (!startRef)
  1708. return DT_FAILURE | DT_INVALID_PARAM;
  1709. if (!m_nav->isValidPolyRef(startRef))
  1710. return DT_FAILURE | DT_INVALID_PARAM;
  1711. dtStatus status = DT_SUCCESS;
  1712. static const int MAX_STACK = 48;
  1713. dtNode* stack[MAX_STACK];
  1714. int nstack = 0;
  1715. m_tinyNodePool->clear();
  1716. dtNode* startNode = m_tinyNodePool->getNode(startRef);
  1717. startNode->pidx = 0;
  1718. startNode->cost = 0;
  1719. startNode->total = 0;
  1720. startNode->id = startRef;
  1721. startNode->flags = DT_NODE_CLOSED;
  1722. stack[nstack++] = startNode;
  1723. float bestPos[3];
  1724. float bestDist = FLT_MAX;
  1725. dtNode* bestNode = 0;
  1726. dtVcopy(bestPos, startPos);
  1727. // Search constraints
  1728. float searchPos[3], searchRadSqr;
  1729. dtVlerp(searchPos, startPos, endPos, 0.5f);
  1730. searchRadSqr = dtSqr(dtVdist(startPos, endPos)/2.0f + 0.001f);
  1731. float verts[DT_VERTS_PER_POLYGON*3];
  1732. while (nstack)
  1733. {
  1734. // Pop front.
  1735. dtNode* curNode = stack[0];
  1736. for (int i = 0; i < nstack-1; ++i)
  1737. stack[i] = stack[i+1];
  1738. nstack--;
  1739. // Get poly and tile.
  1740. // The API input has been cheked already, skip checking internal data.
  1741. const dtPolyRef curRef = curNode->id;
  1742. const dtMeshTile* curTile = 0;
  1743. const dtPoly* curPoly = 0;
  1744. m_nav->getTileAndPolyByRefUnsafe(curRef, &curTile, &curPoly);
  1745. // Collect vertices.
  1746. const int nverts = curPoly->vertCount;
  1747. for (int i = 0; i < nverts; ++i)
  1748. dtVcopy(&verts[i*3], &curTile->verts[curPoly->verts[i]*3]);
  1749. // If target is inside the poly, stop search.
  1750. if (dtPointInPolygon(endPos, verts, nverts))
  1751. {
  1752. bestNode = curNode;
  1753. dtVcopy(bestPos, endPos);
  1754. break;
  1755. }
  1756. // Find wall edges and find nearest point inside the walls.
  1757. for (int i = 0, j = (int)curPoly->vertCount-1; i < (int)curPoly->vertCount; j = i++)
  1758. {
  1759. // Find links to neighbours.
  1760. static const int MAX_NEIS = 8;
  1761. int nneis = 0;
  1762. dtPolyRef neis[MAX_NEIS];
  1763. if (curPoly->neis[j] & DT_EXT_LINK)
  1764. {
  1765. // Tile border.
  1766. for (unsigned int k = curPoly->firstLink; k != DT_NULL_LINK; k = curTile->links[k].next)
  1767. {
  1768. const dtLink* link = &curTile->links[k];
  1769. if (link->edge == j)
  1770. {
  1771. if (link->ref != 0)
  1772. {
  1773. const dtMeshTile* neiTile = 0;
  1774. const dtPoly* neiPoly = 0;
  1775. m_nav->getTileAndPolyByRefUnsafe(link->ref, &neiTile, &neiPoly);
  1776. if (filter->passFilter(link->ref, neiTile, neiPoly))
  1777. {
  1778. if (nneis < MAX_NEIS)
  1779. neis[nneis++] = link->ref;
  1780. }
  1781. }
  1782. }
  1783. }
  1784. }
  1785. else if (curPoly->neis[j])
  1786. {
  1787. const unsigned int idx = (unsigned int)(curPoly->neis[j]-1);
  1788. const dtPolyRef ref = m_nav->getPolyRefBase(curTile) | idx;
  1789. if (filter->passFilter(ref, curTile, &curTile->polys[idx]))
  1790. {
  1791. // Internal edge, encode id.
  1792. neis[nneis++] = ref;
  1793. }
  1794. }
  1795. if (!nneis)
  1796. {
  1797. // Wall edge, calc distance.
  1798. const float* vj = &verts[j*3];
  1799. const float* vi = &verts[i*3];
  1800. float tseg;
  1801. const float distSqr = dtDistancePtSegSqr2D(endPos, vj, vi, tseg);
  1802. if (distSqr < bestDist)
  1803. {
  1804. // Update nearest distance.
  1805. dtVlerp(bestPos, vj,vi, tseg);
  1806. bestDist = distSqr;
  1807. bestNode = curNode;
  1808. }
  1809. }
  1810. else
  1811. {
  1812. for (int k = 0; k < nneis; ++k)
  1813. {
  1814. // Skip if no node can be allocated.
  1815. dtNode* neighbourNode = m_tinyNodePool->getNode(neis[k]);
  1816. if (!neighbourNode)
  1817. continue;
  1818. // Skip if already visited.
  1819. if (neighbourNode->flags & DT_NODE_CLOSED)
  1820. continue;
  1821. // Skip the link if it is too far from search constraint.
  1822. // TODO: Maybe should use getPortalPoints(), but this one is way faster.
  1823. const float* vj = &verts[j*3];
  1824. const float* vi = &verts[i*3];
  1825. float tseg;
  1826. float distSqr = dtDistancePtSegSqr2D(searchPos, vj, vi, tseg);
  1827. if (distSqr > searchRadSqr)
  1828. continue;
  1829. // Mark as the node as visited and push to queue.
  1830. if (nstack < MAX_STACK)
  1831. {
  1832. neighbourNode->pidx = m_tinyNodePool->getNodeIdx(curNode);
  1833. neighbourNode->flags |= DT_NODE_CLOSED;
  1834. stack[nstack++] = neighbourNode;
  1835. }
  1836. }
  1837. }
  1838. }
  1839. }
  1840. int n = 0;
  1841. if (bestNode)
  1842. {
  1843. // Reverse the path.
  1844. dtNode* prev = 0;
  1845. dtNode* node = bestNode;
  1846. do
  1847. {
  1848. dtNode* next = m_tinyNodePool->getNodeAtIdx(node->pidx);
  1849. node->pidx = m_tinyNodePool->getNodeIdx(prev);
  1850. prev = node;
  1851. node = next;
  1852. }
  1853. while (node);
  1854. // Store result
  1855. node = prev;
  1856. do
  1857. {
  1858. visited[n++] = node->id;
  1859. if (n >= maxVisitedSize)
  1860. {
  1861. status |= DT_BUFFER_TOO_SMALL;
  1862. break;
  1863. }
  1864. node = m_tinyNodePool->getNodeAtIdx(node->pidx);
  1865. }
  1866. while (node);
  1867. }
  1868. dtVcopy(resultPos, bestPos);
  1869. *visitedCount = n;
  1870. return status;
  1871. }
  1872. dtStatus dtNavMeshQuery::getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float* right,
  1873. unsigned char& fromType, unsigned char& toType) const
  1874. {
  1875. dtAssert(m_nav);
  1876. const dtMeshTile* fromTile = 0;
  1877. const dtPoly* fromPoly = 0;
  1878. if (dtStatusFailed(m_nav->getTileAndPolyByRef(from, &fromTile, &fromPoly)))
  1879. return DT_FAILURE | DT_INVALID_PARAM;
  1880. fromType = fromPoly->getType();
  1881. const dtMeshTile* toTile = 0;
  1882. const dtPoly* toPoly = 0;
  1883. if (dtStatusFailed(m_nav->getTileAndPolyByRef(to, &toTile, &toPoly)))
  1884. return DT_FAILURE | DT_INVALID_PARAM;
  1885. toType = toPoly->getType();
  1886. return getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, left, right);
  1887. }
  1888. // Returns portal points between two polygons.
  1889. dtStatus dtNavMeshQuery::getPortalPoints(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
  1890. dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
  1891. float* left, float* right) const
  1892. {
  1893. // Find the link that points to the 'to' polygon.
  1894. const dtLink* link = 0;
  1895. for (unsigned int i = fromPoly->firstLink; i != DT_NULL_LINK; i = fromTile->links[i].next)
  1896. {
  1897. if (fromTile->links[i].ref == to)
  1898. {
  1899. link = &fromTile->links[i];
  1900. break;
  1901. }
  1902. }
  1903. if (!link)
  1904. return DT_FAILURE | DT_INVALID_PARAM;
  1905. // Handle off-mesh connections.
  1906. if (fromPoly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
  1907. {
  1908. // Find link that points to first vertex.
  1909. for (unsigned int i = fromPoly->firstLink; i != DT_NULL_LINK; i = fromTile->links[i].next)
  1910. {
  1911. if (fromTile->links[i].ref == to)
  1912. {
  1913. const int v = fromTile->links[i].edge;
  1914. dtVcopy(left, &fromTile->verts[fromPoly->verts[v]*3]);
  1915. dtVcopy(right, &fromTile->verts[fromPoly->verts[v]*3]);
  1916. return DT_SUCCESS;
  1917. }
  1918. }
  1919. return DT_FAILURE | DT_INVALID_PARAM;
  1920. }
  1921. if (toPoly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
  1922. {
  1923. for (unsigned int i = toPoly->firstLink; i != DT_NULL_LINK; i = toTile->links[i].next)
  1924. {
  1925. if (toTile->links[i].ref == from)
  1926. {
  1927. const int v = toTile->links[i].edge;
  1928. dtVcopy(left, &toTile->verts[toPoly->verts[v]*3]);
  1929. dtVcopy(right, &toTile->verts[toPoly->verts[v]*3]);
  1930. return DT_SUCCESS;
  1931. }
  1932. }
  1933. return DT_FAILURE | DT_INVALID_PARAM;
  1934. }
  1935. // Find portal vertices.
  1936. const int v0 = fromPoly->verts[link->edge];
  1937. const int v1 = fromPoly->verts[(link->edge+1) % (int)fromPoly->vertCount];
  1938. dtVcopy(left, &fromTile->verts[v0*3]);
  1939. dtVcopy(right, &fromTile->verts[v1*3]);
  1940. // If the link is at tile boundary, dtClamp the vertices to
  1941. // the link width.
  1942. if (link->side != 0xff)
  1943. {
  1944. // Unpack portal limits.
  1945. if (link->bmin != 0 || link->bmax != 255)
  1946. {
  1947. const float s = 1.0f/255.0f;
  1948. const float tmin = link->bmin*s;
  1949. const float tmax = link->bmax*s;
  1950. dtVlerp(left, &fromTile->verts[v0*3], &fromTile->verts[v1*3], tmin);
  1951. dtVlerp(right, &fromTile->verts[v0*3], &fromTile->verts[v1*3], tmax);
  1952. }
  1953. }
  1954. return DT_SUCCESS;
  1955. }
  1956. // Returns edge mid point between two polygons.
  1957. dtStatus dtNavMeshQuery::getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const
  1958. {
  1959. float left[3], right[3];
  1960. unsigned char fromType, toType;
  1961. if (dtStatusFailed(getPortalPoints(from, to, left,right, fromType, toType)))
  1962. return DT_FAILURE | DT_INVALID_PARAM;
  1963. mid[0] = (left[0]+right[0])*0.5f;
  1964. mid[1] = (left[1]+right[1])*0.5f;
  1965. mid[2] = (left[2]+right[2])*0.5f;
  1966. return DT_SUCCESS;
  1967. }
  1968. dtStatus dtNavMeshQuery::getEdgeMidPoint(dtPolyRef from, const dtPoly* fromPoly, const dtMeshTile* fromTile,
  1969. dtPolyRef to, const dtPoly* toPoly, const dtMeshTile* toTile,
  1970. float* mid) const
  1971. {
  1972. float left[3], right[3];
  1973. if (dtStatusFailed(getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, left, right)))
  1974. return DT_FAILURE | DT_INVALID_PARAM;
  1975. mid[0] = (left[0]+right[0])*0.5f;
  1976. mid[1] = (left[1]+right[1])*0.5f;
  1977. mid[2] = (left[2]+right[2])*0.5f;
  1978. return DT_SUCCESS;
  1979. }
  1980. /// @par
  1981. ///
  1982. /// This method is meant to be used for quick, short distance checks.
  1983. ///
  1984. /// If the path array is too small to hold the result, it will be filled as
  1985. /// far as possible from the start postion toward the end position.
  1986. ///
  1987. /// <b>Using the Hit Parameter (t)</b>
  1988. ///
  1989. /// If the hit parameter is a very high value (FLT_MAX), then the ray has hit
  1990. /// the end position. In this case the path represents a valid corridor to the
  1991. /// end position and the value of @p hitNormal is undefined.
  1992. ///
  1993. /// If the hit parameter is zero, then the start position is on the wall that
  1994. /// was hit and the value of @p hitNormal is undefined.
  1995. ///
  1996. /// If 0 < t < 1.0 then the following applies:
  1997. ///
  1998. /// @code
  1999. /// distanceToHitBorder = distanceToEndPosition * t
  2000. /// hitPoint = startPos + (endPos - startPos) * t
  2001. /// @endcode
  2002. ///
  2003. /// <b>Use Case Restriction</b>
  2004. ///
  2005. /// The raycast ignores the y-value of the end position. (2D check.) This
  2006. /// places significant limits on how it can be used. For example:
  2007. ///
  2008. /// Consider a scene where there is a main floor with a second floor balcony
  2009. /// that hangs over the main floor. So the first floor mesh extends below the
  2010. /// balcony mesh. The start position is somewhere on the first floor. The end
  2011. /// position is on the balcony.
  2012. ///
  2013. /// The raycast will search toward the end position along the first floor mesh.
  2014. /// If it reaches the end position's xz-coordinates it will indicate FLT_MAX
  2015. /// (no wall hit), meaning it reached the end position. This is one example of why
  2016. /// this method is meant for short distance checks.
  2017. ///
  2018. dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
  2019. const dtQueryFilter* filter,
  2020. float* t, float* hitNormal, dtPolyRef* path, int* pathCount, const int maxPath) const
  2021. {
  2022. dtRaycastHit hit;
  2023. hit.path = path;
  2024. hit.maxPath = maxPath;
  2025. dtStatus status = raycast(startRef, startPos, endPos, filter, 0, &hit);
  2026. *t = hit.t;
  2027. if (hitNormal)
  2028. dtVcopy(hitNormal, hit.hitNormal);
  2029. if (pathCount)
  2030. *pathCount = hit.pathCount;
  2031. return status;
  2032. }
  2033. /// @par
  2034. ///
  2035. /// This method is meant to be used for quick, short distance checks.
  2036. ///
  2037. /// If the path array is too small to hold the result, it will be filled as
  2038. /// far as possible from the start postion toward the end position.
  2039. ///
  2040. /// <b>Using the Hit Parameter t of RaycastHit</b>
  2041. ///
  2042. /// If the hit parameter is a very high value (FLT_MAX), then the ray has hit
  2043. /// the end position. In this case the path represents a valid corridor to the
  2044. /// end position and the value of @p hitNormal is undefined.
  2045. ///
  2046. /// If the hit parameter is zero, then the start position is on the wall that
  2047. /// was hit and the value of @p hitNormal is undefined.
  2048. ///
  2049. /// If 0 < t < 1.0 then the following applies:
  2050. ///
  2051. /// @code
  2052. /// distanceToHitBorder = distanceToEndPosition * t
  2053. /// hitPoint = startPos + (endPos - startPos) * t
  2054. /// @endcode
  2055. ///
  2056. /// <b>Use Case Restriction</b>
  2057. ///
  2058. /// The raycast ignores the y-value of the end position. (2D check.) This
  2059. /// places significant limits on how it can be used. For example:
  2060. ///
  2061. /// Consider a scene where there is a main floor with a second floor balcony
  2062. /// that hangs over the main floor. So the first floor mesh extends below the
  2063. /// balcony mesh. The start position is somewhere on the first floor. The end
  2064. /// position is on the balcony.
  2065. ///
  2066. /// The raycast will search toward the end position along the first floor mesh.
  2067. /// If it reaches the end position's xz-coordinates it will indicate FLT_MAX
  2068. /// (no wall hit), meaning it reached the end position. This is one example of why
  2069. /// this method is meant for short distance checks.
  2070. ///
  2071. dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, const float* endPos,
  2072. const dtQueryFilter* filter, const unsigned int options,
  2073. dtRaycastHit* hit, dtPolyRef prevRef) const
  2074. {
  2075. dtAssert(m_nav);
  2076. hit->t = 0;
  2077. hit->pathCount = 0;
  2078. hit->pathCost = 0;
  2079. // Validate input
  2080. if (!startRef || !m_nav->isValidPolyRef(startRef))
  2081. return DT_FAILURE | DT_INVALID_PARAM;
  2082. if (prevRef && !m_nav->isValidPolyRef(prevRef))
  2083. return DT_FAILURE | DT_INVALID_PARAM;
  2084. float dir[3], curPos[3], lastPos[3];
  2085. float verts[DT_VERTS_PER_POLYGON*3+3];
  2086. int n = 0;
  2087. dtVcopy(curPos, startPos);
  2088. dtVsub(dir, endPos, startPos);
  2089. dtVset(hit->hitNormal, 0, 0, 0);
  2090. dtStatus status = DT_SUCCESS;
  2091. const dtMeshTile* prevTile, *tile, *nextTile;
  2092. const dtPoly* prevPoly, *poly, *nextPoly;
  2093. dtPolyRef curRef, nextRef;
  2094. // The API input has been checked already, skip checking internal data.
  2095. nextRef = curRef = startRef;
  2096. tile = 0;
  2097. poly = 0;
  2098. m_nav->getTileAndPolyByRefUnsafe(curRef, &tile, &poly);
  2099. nextTile = prevTile = tile;
  2100. nextPoly = prevPoly = poly;
  2101. if (prevRef)
  2102. m_nav->getTileAndPolyByRefUnsafe(prevRef, &prevTile, &prevPoly);
  2103. while (curRef)
  2104. {
  2105. // Cast ray against current polygon.
  2106. // Collect vertices.
  2107. int nv = 0;
  2108. for (int i = 0; i < (int)poly->vertCount; ++i)
  2109. {
  2110. dtVcopy(&verts[nv*3], &tile->verts[poly->verts[i]*3]);
  2111. nv++;
  2112. }
  2113. float tmin, tmax;
  2114. int segMin, segMax;
  2115. if (!dtIntersectSegmentPoly2D(startPos, endPos, verts, nv, tmin, tmax, segMin, segMax))
  2116. {
  2117. // Could not hit the polygon, keep the old t and report hit.
  2118. hit->pathCount = n;
  2119. return status;
  2120. }
  2121. // Keep track of furthest t so far.
  2122. if (tmax > hit->t)
  2123. hit->t = tmax;
  2124. // Store visited polygons.
  2125. if (n < hit->maxPath)
  2126. hit->path[n++] = curRef;
  2127. else
  2128. status |= DT_BUFFER_TOO_SMALL;
  2129. // Ray end is completely inside the polygon.
  2130. if (segMax == -1)
  2131. {
  2132. hit->t = FLT_MAX;
  2133. hit->pathCount = n;
  2134. // add the cost
  2135. if (options & DT_RAYCAST_USE_COSTS)
  2136. hit->pathCost += filter->getCost(curPos, endPos, prevRef, prevTile, prevPoly, curRef, tile, poly, curRef, tile, poly);
  2137. return status;
  2138. }
  2139. // Follow neighbours.
  2140. nextRef = 0;
  2141. for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = tile->links[i].next)
  2142. {
  2143. const dtLink* link = &tile->links[i];
  2144. // Find link which contains this edge.
  2145. if ((int)link->edge != segMax)
  2146. continue;
  2147. // Get pointer to the next polygon.
  2148. nextTile = 0;
  2149. nextPoly = 0;
  2150. m_nav->getTileAndPolyByRefUnsafe(link->ref, &nextTile, &nextPoly);
  2151. // Skip off-mesh connections.
  2152. if (nextPoly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
  2153. continue;
  2154. // Skip links based on filter.
  2155. if (!filter->passFilter(link->ref, nextTile, nextPoly))
  2156. continue;
  2157. // If the link is internal, just return the ref.
  2158. if (link->side == 0xff)
  2159. {
  2160. nextRef = link->ref;
  2161. break;
  2162. }
  2163. // If the link is at tile boundary,
  2164. // Check if the link spans the whole edge, and accept.
  2165. if (link->bmin == 0 && link->bmax == 255)
  2166. {
  2167. nextRef = link->ref;
  2168. break;
  2169. }
  2170. // Check for partial edge links.
  2171. const int v0 = poly->verts[link->edge];
  2172. const int v1 = poly->verts[(link->edge+1) % poly->vertCount];
  2173. const float* left = &tile->verts[v0*3];
  2174. const float* right = &tile->verts[v1*3];
  2175. // Check that the intersection lies inside the link portal.
  2176. if (link->side == 0 || link->side == 4)
  2177. {
  2178. // Calculate link size.
  2179. const float s = 1.0f/255.0f;
  2180. float lmin = left[2] + (right[2] - left[2])*(link->bmin*s);
  2181. float lmax = left[2] + (right[2] - left[2])*(link->bmax*s);
  2182. if (lmin > lmax) dtSwap(lmin, lmax);
  2183. // Find Z intersection.
  2184. float z = startPos[2] + (endPos[2]-startPos[2])*tmax;
  2185. if (z >= lmin && z <= lmax)
  2186. {
  2187. nextRef = link->ref;
  2188. break;
  2189. }
  2190. }
  2191. else if (link->side == 2 || link->side == 6)
  2192. {
  2193. // Calculate link size.
  2194. const float s = 1.0f/255.0f;
  2195. float lmin = left[0] + (right[0] - left[0])*(link->bmin*s);
  2196. float lmax = left[0] + (right[0] - left[0])*(link->bmax*s);
  2197. if (lmin > lmax) dtSwap(lmin, lmax);
  2198. // Find X intersection.
  2199. float x = startPos[0] + (endPos[0]-startPos[0])*tmax;
  2200. if (x >= lmin && x <= lmax)
  2201. {
  2202. nextRef = link->ref;
  2203. break;
  2204. }
  2205. }
  2206. }
  2207. // add the cost
  2208. if (options & DT_RAYCAST_USE_COSTS)
  2209. {
  2210. // compute the intersection point at the furthest end of the polygon
  2211. // and correct the height (since the raycast moves in 2d)
  2212. dtVcopy(lastPos, curPos);
  2213. dtVmad(curPos, startPos, dir, hit->t);
  2214. float* e1 = &verts[segMax*3];
  2215. float* e2 = &verts[((segMax+1)%nv)*3];
  2216. float eDir[3], diff[3];
  2217. dtVsub(eDir, e2, e1);
  2218. dtVsub(diff, curPos, e1);
  2219. float s = dtSqr(eDir[0]) > dtSqr(eDir[2]) ? diff[0] / eDir[0] : diff[2] / eDir[2];
  2220. curPos[1] = e1[1] + eDir[1] * s;
  2221. hit->pathCost += filter->getCost(lastPos, curPos, prevRef, prevTile, prevPoly, curRef, tile, poly, nextRef, nextTile, nextPoly);
  2222. }
  2223. if (!nextRef)
  2224. {
  2225. // No neighbour, we hit a wall.
  2226. // Calculate hit normal.
  2227. const int a = segMax;
  2228. const int b = segMax+1 < nv ? segMax+1 : 0;
  2229. const float* va = &verts[a*3];
  2230. const float* vb = &verts[b*3];
  2231. const float dx = vb[0] - va[0];
  2232. const float dz = vb[2] - va[2];
  2233. hit->hitNormal[0] = dz;
  2234. hit->hitNormal[1] = 0;
  2235. hit->hitNormal[2] = -dx;
  2236. dtVnormalize(hit->hitNormal);
  2237. hit->pathCount = n;
  2238. return status;
  2239. }
  2240. // No hit, advance to neighbour polygon.
  2241. prevRef = curRef;
  2242. curRef = nextRef;
  2243. prevTile = tile;
  2244. tile = nextTile;
  2245. prevPoly = poly;
  2246. poly = nextPoly;
  2247. }
  2248. hit->pathCount = n;
  2249. return status;
  2250. }
  2251. /// @par
  2252. ///
  2253. /// At least one result array must be provided.
  2254. ///
  2255. /// The order of the result set is from least to highest cost to reach the polygon.
  2256. ///
  2257. /// A common use case for this method is to perform Dijkstra searches.
  2258. /// Candidate polygons are found by searching the graph beginning at the start polygon.
  2259. ///
  2260. /// If a polygon is not found via the graph search, even if it intersects the
  2261. /// search circle, it will not be included in the result set. For example:
  2262. ///
  2263. /// polyA is the start polygon.
  2264. /// polyB shares an edge with polyA. (Is adjacent.)
  2265. /// polyC shares an edge with polyB, but not with polyA
  2266. /// Even if the search circle overlaps polyC, it will not be included in the
  2267. /// result set unless polyB is also in the set.
  2268. ///
  2269. /// The value of the center point is used as the start position for cost
  2270. /// calculations. It is not projected onto the surface of the mesh, so its
  2271. /// y-value will effect the costs.
  2272. ///
  2273. /// Intersection tests occur in 2D. All polygons and the search circle are
  2274. /// projected onto the xz-plane. So the y-value of the center point does not
  2275. /// effect intersection tests.
  2276. ///
  2277. /// If the result arrays are to small to hold the entire result set, they will be
  2278. /// filled to capacity.
  2279. ///
  2280. dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* centerPos, const float radius,
  2281. const dtQueryFilter* filter,
  2282. dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
  2283. int* resultCount, const int maxResult) const
  2284. {
  2285. dtAssert(m_nav);
  2286. dtAssert(m_nodePool);
  2287. dtAssert(m_openList);
  2288. *resultCount = 0;
  2289. // Validate input
  2290. if (!startRef || !m_nav->isValidPolyRef(startRef))
  2291. return DT_FAILURE | DT_INVALID_PARAM;
  2292. m_nodePool->clear();
  2293. m_openList->clear();
  2294. dtNode* startNode = m_nodePool->getNode(startRef);
  2295. dtVcopy(startNode->pos, centerPos);
  2296. startNode->pidx = 0;
  2297. startNode->cost = 0;
  2298. startNode->total = 0;
  2299. startNode->id = startRef;
  2300. startNode->flags = DT_NODE_OPEN;
  2301. m_openList->push(startNode);
  2302. dtStatus status = DT_SUCCESS;
  2303. int n = 0;
  2304. if (n < maxResult)
  2305. {
  2306. if (resultRef)
  2307. resultRef[n] = startNode->id;
  2308. if (resultParent)
  2309. resultParent[n] = 0;
  2310. if (resultCost)
  2311. resultCost[n] = 0;
  2312. ++n;
  2313. }
  2314. else
  2315. {
  2316. status |= DT_BUFFER_TOO_SMALL;
  2317. }
  2318. const float radiusSqr = dtSqr(radius);
  2319. while (!m_openList->empty())
  2320. {
  2321. dtNode* bestNode = m_openList->pop();
  2322. bestNode->flags &= ~DT_NODE_OPEN;
  2323. bestNode->flags |= DT_NODE_CLOSED;
  2324. // Get poly and tile.
  2325. // The API input has been cheked already, skip checking internal data.
  2326. const dtPolyRef bestRef = bestNode->id;
  2327. const dtMeshTile* bestTile = 0;
  2328. const dtPoly* bestPoly = 0;
  2329. m_nav->getTileAndPolyByRefUnsafe(bestRef, &bestTile, &bestPoly);
  2330. // Get parent poly and tile.
  2331. dtPolyRef parentRef = 0;
  2332. const dtMeshTile* parentTile = 0;
  2333. const dtPoly* parentPoly = 0;
  2334. if (bestNode->pidx)
  2335. parentRef = m_nodePool->getNodeAtIdx(bestNode->pidx)->id;
  2336. if (parentRef)
  2337. m_nav->getTileAndPolyByRefUnsafe(parentRef, &parentTile, &parentPoly);
  2338. for (unsigned int i = bestPoly->firstLink; i != DT_NULL_LINK; i = bestTile->links[i].next)
  2339. {
  2340. const dtLink* link = &bestTile->links[i];
  2341. dtPolyRef neighbourRef = link->ref;
  2342. // Skip invalid neighbours and do not follow back to parent.
  2343. if (!neighbourRef || neighbourRef == parentRef)
  2344. continue;
  2345. // Expand to neighbour
  2346. const dtMeshTile* neighbourTile = 0;
  2347. const dtPoly* neighbourPoly = 0;
  2348. m_nav->getTileAndPolyByRefUnsafe(neighbourRef, &neighbourTile, &neighbourPoly);
  2349. // Do not advance if the polygon is excluded by the filter.
  2350. if (!filter->passFilter(neighbourRef, neighbourTile, neighbourPoly))
  2351. continue;
  2352. // Find edge and calc distance to the edge.
  2353. float va[3], vb[3];
  2354. if (!getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, neighbourTile, va, vb))
  2355. continue;
  2356. // If the circle is not touching the next polygon, skip it.
  2357. float tseg;
  2358. float distSqr = dtDistancePtSegSqr2D(centerPos, va, vb, tseg);
  2359. if (distSqr > radiusSqr)
  2360. continue;
  2361. dtNode* neighbourNode = m_nodePool->getNode(neighbourRef);
  2362. if (!neighbourNode)
  2363. {
  2364. status |= DT_OUT_OF_NODES;
  2365. continue;
  2366. }
  2367. if (neighbourNode->flags & DT_NODE_CLOSED)
  2368. continue;
  2369. // Cost
  2370. if (neighbourNode->flags == 0)
  2371. dtVlerp(neighbourNode->pos, va, vb, 0.5f);
  2372. const float total = bestNode->total + dtVdist(bestNode->pos, neighbourNode->pos);
  2373. // The node is already in open list and the new result is worse, skip.
  2374. if ((neighbourNode->flags & DT_NODE_OPEN) && total >= neighbourNode->total)
  2375. continue;
  2376. neighbourNode->id = neighbourRef;
  2377. neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED);
  2378. neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode);
  2379. neighbourNode->total = total;
  2380. if (neighbourNode->flags & DT_NODE_OPEN)
  2381. {
  2382. m_openList->modify(neighbourNode);
  2383. }
  2384. else
  2385. {
  2386. if (n < maxResult)
  2387. {
  2388. if (resultRef)
  2389. resultRef[n] = neighbourNode->id;
  2390. if (resultParent)
  2391. resultParent[n] = m_nodePool->getNodeAtIdx(neighbourNode->pidx)->id;
  2392. if (resultCost)
  2393. resultCost[n] = neighbourNode->total;
  2394. ++n;
  2395. }
  2396. else
  2397. {
  2398. status |= DT_BUFFER_TOO_SMALL;
  2399. }
  2400. neighbourNode->flags = DT_NODE_OPEN;
  2401. m_openList->push(neighbourNode);
  2402. }
  2403. }
  2404. }
  2405. *resultCount = n;
  2406. return status;
  2407. }
  2408. /// @par
  2409. ///
  2410. /// The order of the result set is from least to highest cost.
  2411. ///
  2412. /// At least one result array must be provided.
  2413. ///
  2414. /// A common use case for this method is to perform Dijkstra searches.
  2415. /// Candidate polygons are found by searching the graph beginning at the start
  2416. /// polygon.
  2417. ///
  2418. /// The same intersection test restrictions that apply to findPolysAroundCircle()
  2419. /// method apply to this method.
  2420. ///
  2421. /// The 3D centroid of the search polygon is used as the start position for cost
  2422. /// calculations.
  2423. ///
  2424. /// Intersection tests occur in 2D. All polygons are projected onto the
  2425. /// xz-plane. So the y-values of the vertices do not effect intersection tests.
  2426. ///
  2427. /// If the result arrays are is too small to hold the entire result set, they will
  2428. /// be filled to capacity.
  2429. ///
  2430. dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* verts, const int nverts,
  2431. const dtQueryFilter* filter,
  2432. dtPolyRef* resultRef, dtPolyRef* resultParent, float* resultCost,
  2433. int* resultCount, const int maxResult) const
  2434. {
  2435. dtAssert(m_nav);
  2436. dtAssert(m_nodePool);
  2437. dtAssert(m_openList);
  2438. *resultCount = 0;
  2439. // Validate input
  2440. if (!startRef || !m_nav->isValidPolyRef(startRef))
  2441. return DT_FAILURE | DT_INVALID_PARAM;
  2442. m_nodePool->clear();
  2443. m_openList->clear();
  2444. float centerPos[3] = {0,0,0};
  2445. for (int i = 0; i < nverts; ++i)
  2446. dtVadd(centerPos,centerPos,&verts[i*3]);
  2447. dtVscale(centerPos,centerPos,1.0f/nverts);
  2448. dtNode* startNode = m_nodePool->getNode(startRef);
  2449. dtVcopy(startNode->pos, centerPos);
  2450. startNode->pidx = 0;
  2451. startNode->cost = 0;
  2452. startNode->total = 0;
  2453. startNode->id = startRef;
  2454. startNode->flags = DT_NODE_OPEN;
  2455. m_openList->push(startNode);
  2456. dtStatus status = DT_SUCCESS;
  2457. int n = 0;
  2458. if (n < maxResult)
  2459. {
  2460. if (resultRef)
  2461. resultRef[n] = startNode->id;
  2462. if (resultParent)
  2463. resultParent[n] = 0;
  2464. if (resultCost)
  2465. resultCost[n] = 0;
  2466. ++n;
  2467. }
  2468. else
  2469. {
  2470. status |= DT_BUFFER_TOO_SMALL;
  2471. }
  2472. while (!m_openList->empty())
  2473. {
  2474. dtNode* bestNode = m_openList->pop();
  2475. bestNode->flags &= ~DT_NODE_OPEN;
  2476. bestNode->flags |= DT_NODE_CLOSED;
  2477. // Get poly and tile.
  2478. // The API input has been cheked already, skip checking internal data.
  2479. const dtPolyRef bestRef = bestNode->id;
  2480. const dtMeshTile* bestTile = 0;
  2481. const dtPoly* bestPoly = 0;
  2482. m_nav->getTileAndPolyByRefUnsafe(bestRef, &bestTile, &bestPoly);
  2483. // Get parent poly and tile.
  2484. dtPolyRef parentRef = 0;
  2485. const dtMeshTile* parentTile = 0;
  2486. const dtPoly* parentPoly = 0;
  2487. if (bestNode->pidx)
  2488. parentRef = m_nodePool->getNodeAtIdx(bestNode->pidx)->id;
  2489. if (parentRef)
  2490. m_nav->getTileAndPolyByRefUnsafe(parentRef, &parentTile, &parentPoly);
  2491. for (unsigned int i = bestPoly->firstLink; i != DT_NULL_LINK; i = bestTile->links[i].next)
  2492. {
  2493. const dtLink* link = &bestTile->links[i];
  2494. dtPolyRef neighbourRef = link->ref;
  2495. // Skip invalid neighbours and do not follow back to parent.
  2496. if (!neighbourRef || neighbourRef == parentRef)
  2497. continue;
  2498. // Expand to neighbour
  2499. const dtMeshTile* neighbourTile = 0;
  2500. const dtPoly* neighbourPoly = 0;
  2501. m_nav->getTileAndPolyByRefUnsafe(neighbourRef, &neighbourTile, &neighbourPoly);
  2502. // Do not advance if the polygon is excluded by the filter.
  2503. if (!filter->passFilter(neighbourRef, neighbourTile, neighbourPoly))
  2504. continue;
  2505. // Find edge and calc distance to the edge.
  2506. float va[3], vb[3];
  2507. if (!getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly, neighbourTile, va, vb))
  2508. continue;
  2509. // If the poly is not touching the edge to the next polygon, skip the connection it.
  2510. float tmin, tmax;
  2511. int segMin, segMax;
  2512. if (!dtIntersectSegmentPoly2D(va, vb, verts, nverts, tmin, tmax, segMin, segMax))
  2513. continue;
  2514. if (tmin > 1.0f || tmax < 0.0f)
  2515. continue;
  2516. dtNode* neighbourNode = m_nodePool->getNode(neighbourRef);
  2517. if (!neighbourNode)
  2518. {
  2519. status |= DT_OUT_OF_NODES;
  2520. continue;
  2521. }
  2522. if (neighbourNode->flags & DT_NODE_CLOSED)
  2523. continue;
  2524. // Cost
  2525. if (neighbourNode->flags == 0)
  2526. dtVlerp(neighbourNode->pos, va, vb, 0.5f);
  2527. const float total = bestNode->total + dtVdist(bestNode->pos, neighbourNode->pos);
  2528. // The node is already in open list and the new result is worse, skip.
  2529. if ((neighbourNode->flags & DT_NODE_OPEN) && total >= neighbourNode->total)
  2530. continue;
  2531. neighbourNode->id = neighbourRef;
  2532. neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED);
  2533. neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode);
  2534. neighbourNode->total = total;
  2535. if (neighbourNode->flags & DT_NODE_OPEN)
  2536. {
  2537. m_openList->modify(neighbourNode);
  2538. }
  2539. else
  2540. {
  2541. if (n < maxResult)
  2542. {
  2543. if (resultRef)
  2544. resultRef[n] = neighbourNode->id;
  2545. if (resultParent)
  2546. resultParent[n] = m_nodePool->getNodeAtIdx(neighbourNode->pidx)->id;
  2547. if (resultCost)
  2548. resultCost[n] = neighbourNode->total;
  2549. ++n;
  2550. }
  2551. else
  2552. {
  2553. status |= DT_BUFFER_TOO_SMALL;
  2554. }
  2555. neighbourNode->flags = DT_NODE_OPEN;
  2556. m_openList->push(neighbourNode);
  2557. }
  2558. }
  2559. }
  2560. *resultCount = n;
  2561. return status;
  2562. }
  2563. /// @par
  2564. ///
  2565. /// This method is optimized for a small search radius and small number of result
  2566. /// polygons.
  2567. ///
  2568. /// Candidate polygons are found by searching the navigation graph beginning at
  2569. /// the start polygon.
  2570. ///
  2571. /// The same intersection test restrictions that apply to the findPolysAroundCircle
  2572. /// mehtod applies to this method.
  2573. ///
  2574. /// The value of the center point is used as the start point for cost calculations.
  2575. /// It is not projected onto the surface of the mesh, so its y-value will effect
  2576. /// the costs.
  2577. ///
  2578. /// Intersection tests occur in 2D. All polygons and the search circle are
  2579. /// projected onto the xz-plane. So the y-value of the center point does not
  2580. /// effect intersection tests.
  2581. ///
  2582. /// If the result arrays are is too small to hold the entire result set, they will
  2583. /// be filled to capacity.
  2584. ///
  2585. dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* centerPos, const float radius,
  2586. const dtQueryFilter* filter,
  2587. dtPolyRef* resultRef, dtPolyRef* resultParent,
  2588. int* resultCount, const int maxResult) const
  2589. {
  2590. dtAssert(m_nav);
  2591. dtAssert(m_tinyNodePool);
  2592. *resultCount = 0;
  2593. // Validate input
  2594. if (!startRef || !m_nav->isValidPolyRef(startRef))
  2595. return DT_FAILURE | DT_INVALID_PARAM;
  2596. static const int MAX_STACK = 48;
  2597. dtNode* stack[MAX_STACK];
  2598. int nstack = 0;
  2599. m_tinyNodePool->clear();
  2600. dtNode* startNode = m_tinyNodePool->getNode(startRef);
  2601. startNode->pidx = 0;
  2602. startNode->id = startRef;
  2603. startNode->flags = DT_NODE_CLOSED;
  2604. stack[nstack++] = startNode;
  2605. const float radiusSqr = dtSqr(radius);
  2606. float pa[DT_VERTS_PER_POLYGON*3];
  2607. float pb[DT_VERTS_PER_POLYGON*3];
  2608. dtStatus status = DT_SUCCESS;
  2609. int n = 0;
  2610. if (n < maxResult)
  2611. {
  2612. resultRef[n] = startNode->id;
  2613. if (resultParent)
  2614. resultParent[n] = 0;
  2615. ++n;
  2616. }
  2617. else
  2618. {
  2619. status |= DT_BUFFER_TOO_SMALL;
  2620. }
  2621. while (nstack)
  2622. {
  2623. // Pop front.
  2624. dtNode* curNode = stack[0];
  2625. for (int i = 0; i < nstack-1; ++i)
  2626. stack[i] = stack[i+1];
  2627. nstack--;
  2628. // Get poly and tile.
  2629. // The API input has been cheked already, skip checking internal data.
  2630. const dtPolyRef curRef = curNode->id;
  2631. const dtMeshTile* curTile = 0;
  2632. const dtPoly* curPoly = 0;
  2633. m_nav->getTileAndPolyByRefUnsafe(curRef, &curTile, &curPoly);
  2634. for (unsigned int i = curPoly->firstLink; i != DT_NULL_LINK; i = curTile->links[i].next)
  2635. {
  2636. const dtLink* link = &curTile->links[i];
  2637. dtPolyRef neighbourRef = link->ref;
  2638. // Skip invalid neighbours.
  2639. if (!neighbourRef)
  2640. continue;
  2641. // Skip if cannot alloca more nodes.
  2642. dtNode* neighbourNode = m_tinyNodePool->getNode(neighbourRef);
  2643. if (!neighbourNode)
  2644. continue;
  2645. // Skip visited.
  2646. if (neighbourNode->flags & DT_NODE_CLOSED)
  2647. continue;
  2648. // Expand to neighbour
  2649. const dtMeshTile* neighbourTile = 0;
  2650. const dtPoly* neighbourPoly = 0;
  2651. m_nav->getTileAndPolyByRefUnsafe(neighbourRef, &neighbourTile, &neighbourPoly);
  2652. // Skip off-mesh connections.
  2653. if (neighbourPoly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
  2654. continue;
  2655. // Do not advance if the polygon is excluded by the filter.
  2656. if (!filter->passFilter(neighbourRef, neighbourTile, neighbourPoly))
  2657. continue;
  2658. // Find edge and calc distance to the edge.
  2659. float va[3], vb[3];
  2660. if (!getPortalPoints(curRef, curPoly, curTile, neighbourRef, neighbourPoly, neighbourTile, va, vb))
  2661. continue;
  2662. // If the circle is not touching the next polygon, skip it.
  2663. float tseg;
  2664. float distSqr = dtDistancePtSegSqr2D(centerPos, va, vb, tseg);
  2665. if (distSqr > radiusSqr)
  2666. continue;
  2667. // Mark node visited, this is done before the overlap test so that
  2668. // we will not visit the poly again if the test fails.
  2669. neighbourNode->flags |= DT_NODE_CLOSED;
  2670. neighbourNode->pidx = m_tinyNodePool->getNodeIdx(curNode);
  2671. // Check that the polygon does not collide with existing polygons.
  2672. // Collect vertices of the neighbour poly.
  2673. const int npa = neighbourPoly->vertCount;
  2674. for (int k = 0; k < npa; ++k)
  2675. dtVcopy(&pa[k*3], &neighbourTile->verts[neighbourPoly->verts[k]*3]);
  2676. bool overlap = false;
  2677. for (int j = 0; j < n; ++j)
  2678. {
  2679. dtPolyRef pastRef = resultRef[j];
  2680. // Connected polys do not overlap.
  2681. bool connected = false;
  2682. for (unsigned int k = curPoly->firstLink; k != DT_NULL_LINK; k = curTile->links[k].next)
  2683. {
  2684. if (curTile->links[k].ref == pastRef)
  2685. {
  2686. connected = true;
  2687. break;
  2688. }
  2689. }
  2690. if (connected)
  2691. continue;
  2692. // Potentially overlapping.
  2693. const dtMeshTile* pastTile = 0;
  2694. const dtPoly* pastPoly = 0;
  2695. m_nav->getTileAndPolyByRefUnsafe(pastRef, &pastTile, &pastPoly);
  2696. // Get vertices and test overlap
  2697. const int npb = pastPoly->vertCount;
  2698. for (int k = 0; k < npb; ++k)
  2699. dtVcopy(&pb[k*3], &pastTile->verts[pastPoly->verts[k]*3]);
  2700. if (dtOverlapPolyPoly2D(pa,npa, pb,npb))
  2701. {
  2702. overlap = true;
  2703. break;
  2704. }
  2705. }
  2706. if (overlap)
  2707. continue;
  2708. // This poly is fine, store and advance to the poly.
  2709. if (n < maxResult)
  2710. {
  2711. resultRef[n] = neighbourRef;
  2712. if (resultParent)
  2713. resultParent[n] = curRef;
  2714. ++n;
  2715. }
  2716. else
  2717. {
  2718. status |= DT_BUFFER_TOO_SMALL;
  2719. }
  2720. if (nstack < MAX_STACK)
  2721. {
  2722. stack[nstack++] = neighbourNode;
  2723. }
  2724. }
  2725. }
  2726. *resultCount = n;
  2727. return status;
  2728. }
  2729. struct dtSegInterval
  2730. {
  2731. dtPolyRef ref;
  2732. short tmin, tmax;
  2733. };
  2734. static void insertInterval(dtSegInterval* ints, int& nints, const int maxInts,
  2735. const short tmin, const short tmax, const dtPolyRef ref)
  2736. {
  2737. if (nints+1 > maxInts) return;
  2738. // Find insertion point.
  2739. int idx = 0;
  2740. while (idx < nints)
  2741. {
  2742. if (tmax <= ints[idx].tmin)
  2743. break;
  2744. idx++;
  2745. }
  2746. // Move current results.
  2747. if (nints-idx)
  2748. memmove(ints+idx+1, ints+idx, sizeof(dtSegInterval)*(nints-idx));
  2749. // Store
  2750. ints[idx].ref = ref;
  2751. ints[idx].tmin = tmin;
  2752. ints[idx].tmax = tmax;
  2753. nints++;
  2754. }
  2755. /// @par
  2756. ///
  2757. /// If the @p segmentRefs parameter is provided, then all polygon segments will be returned.
  2758. /// Otherwise only the wall segments are returned.
  2759. ///
  2760. /// A segment that is normally a portal will be included in the result set as a
  2761. /// wall if the @p filter results in the neighbor polygon becoomming impassable.
  2762. ///
  2763. /// The @p segmentVerts and @p segmentRefs buffers should normally be sized for the
  2764. /// maximum segments per polygon of the source navigation mesh.
  2765. ///
  2766. dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter,
  2767. float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount,
  2768. const int maxSegments) const
  2769. {
  2770. dtAssert(m_nav);
  2771. *segmentCount = 0;
  2772. const dtMeshTile* tile = 0;
  2773. const dtPoly* poly = 0;
  2774. if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly)))
  2775. return DT_FAILURE | DT_INVALID_PARAM;
  2776. int n = 0;
  2777. static const int MAX_INTERVAL = 16;
  2778. dtSegInterval ints[MAX_INTERVAL];
  2779. int nints;
  2780. const bool storePortals = segmentRefs != 0;
  2781. dtStatus status = DT_SUCCESS;
  2782. for (int i = 0, j = (int)poly->vertCount-1; i < (int)poly->vertCount; j = i++)
  2783. {
  2784. // Skip non-solid edges.
  2785. nints = 0;
  2786. if (poly->neis[j] & DT_EXT_LINK)
  2787. {
  2788. // Tile border.
  2789. for (unsigned int k = poly->firstLink; k != DT_NULL_LINK; k = tile->links[k].next)
  2790. {
  2791. const dtLink* link = &tile->links[k];
  2792. if (link->edge == j)
  2793. {
  2794. if (link->ref != 0)
  2795. {
  2796. const dtMeshTile* neiTile = 0;
  2797. const dtPoly* neiPoly = 0;
  2798. m_nav->getTileAndPolyByRefUnsafe(link->ref, &neiTile, &neiPoly);
  2799. if (filter->passFilter(link->ref, neiTile, neiPoly))
  2800. {
  2801. insertInterval(ints, nints, MAX_INTERVAL, link->bmin, link->bmax, link->ref);
  2802. }
  2803. }
  2804. }
  2805. }
  2806. }
  2807. else
  2808. {
  2809. // Internal edge
  2810. dtPolyRef neiRef = 0;
  2811. if (poly->neis[j])
  2812. {
  2813. const unsigned int idx = (unsigned int)(poly->neis[j]-1);
  2814. neiRef = m_nav->getPolyRefBase(tile) | idx;
  2815. if (!filter->passFilter(neiRef, tile, &tile->polys[idx]))
  2816. neiRef = 0;
  2817. }
  2818. // If the edge leads to another polygon and portals are not stored, skip.
  2819. if (neiRef != 0 && !storePortals)
  2820. continue;
  2821. if (n < maxSegments)
  2822. {
  2823. const float* vj = &tile->verts[poly->verts[j]*3];
  2824. const float* vi = &tile->verts[poly->verts[i]*3];
  2825. float* seg = &segmentVerts[n*6];
  2826. dtVcopy(seg+0, vj);
  2827. dtVcopy(seg+3, vi);
  2828. if (segmentRefs)
  2829. segmentRefs[n] = neiRef;
  2830. n++;
  2831. }
  2832. else
  2833. {
  2834. status |= DT_BUFFER_TOO_SMALL;
  2835. }
  2836. continue;
  2837. }
  2838. // Add sentinels
  2839. insertInterval(ints, nints, MAX_INTERVAL, -1, 0, 0);
  2840. insertInterval(ints, nints, MAX_INTERVAL, 255, 256, 0);
  2841. // Store segments.
  2842. const float* vj = &tile->verts[poly->verts[j]*3];
  2843. const float* vi = &tile->verts[poly->verts[i]*3];
  2844. for (int k = 1; k < nints; ++k)
  2845. {
  2846. // Portal segment.
  2847. if (storePortals && ints[k].ref)
  2848. {
  2849. const float tmin = ints[k].tmin/255.0f;
  2850. const float tmax = ints[k].tmax/255.0f;
  2851. if (n < maxSegments)
  2852. {
  2853. float* seg = &segmentVerts[n*6];
  2854. dtVlerp(seg+0, vj,vi, tmin);
  2855. dtVlerp(seg+3, vj,vi, tmax);
  2856. if (segmentRefs)
  2857. segmentRefs[n] = ints[k].ref;
  2858. n++;
  2859. }
  2860. else
  2861. {
  2862. status |= DT_BUFFER_TOO_SMALL;
  2863. }
  2864. }
  2865. // Wall segment.
  2866. const int imin = ints[k-1].tmax;
  2867. const int imax = ints[k].tmin;
  2868. if (imin != imax)
  2869. {
  2870. const float tmin = imin/255.0f;
  2871. const float tmax = imax/255.0f;
  2872. if (n < maxSegments)
  2873. {
  2874. float* seg = &segmentVerts[n*6];
  2875. dtVlerp(seg+0, vj,vi, tmin);
  2876. dtVlerp(seg+3, vj,vi, tmax);
  2877. if (segmentRefs)
  2878. segmentRefs[n] = 0;
  2879. n++;
  2880. }
  2881. else
  2882. {
  2883. status |= DT_BUFFER_TOO_SMALL;
  2884. }
  2885. }
  2886. }
  2887. }
  2888. *segmentCount = n;
  2889. return status;
  2890. }
  2891. /// @par
  2892. ///
  2893. /// @p hitPos is not adjusted using the height detail data.
  2894. ///
  2895. /// @p hitDist will equal the search radius if there is no wall within the
  2896. /// radius. In this case the values of @p hitPos and @p hitNormal are
  2897. /// undefined.
  2898. ///
  2899. /// The normal will become unpredicable if @p hitDist is a very small number.
  2900. ///
  2901. dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* centerPos, const float maxRadius,
  2902. const dtQueryFilter* filter,
  2903. float* hitDist, float* hitPos, float* hitNormal) const
  2904. {
  2905. dtAssert(m_nav);
  2906. dtAssert(m_nodePool);
  2907. dtAssert(m_openList);
  2908. // Validate input
  2909. if (!startRef || !m_nav->isValidPolyRef(startRef))
  2910. return DT_FAILURE | DT_INVALID_PARAM;
  2911. m_nodePool->clear();
  2912. m_openList->clear();
  2913. dtNode* startNode = m_nodePool->getNode(startRef);
  2914. dtVcopy(startNode->pos, centerPos);
  2915. startNode->pidx = 0;
  2916. startNode->cost = 0;
  2917. startNode->total = 0;
  2918. startNode->id = startRef;
  2919. startNode->flags = DT_NODE_OPEN;
  2920. m_openList->push(startNode);
  2921. float radiusSqr = dtSqr(maxRadius);
  2922. dtStatus status = DT_SUCCESS;
  2923. while (!m_openList->empty())
  2924. {
  2925. dtNode* bestNode = m_openList->pop();
  2926. bestNode->flags &= ~DT_NODE_OPEN;
  2927. bestNode->flags |= DT_NODE_CLOSED;
  2928. // Get poly and tile.
  2929. // The API input has been cheked already, skip checking internal data.
  2930. const dtPolyRef bestRef = bestNode->id;
  2931. const dtMeshTile* bestTile = 0;
  2932. const dtPoly* bestPoly = 0;
  2933. m_nav->getTileAndPolyByRefUnsafe(bestRef, &bestTile, &bestPoly);
  2934. // Get parent poly and tile.
  2935. dtPolyRef parentRef = 0;
  2936. const dtMeshTile* parentTile = 0;
  2937. const dtPoly* parentPoly = 0;
  2938. if (bestNode->pidx)
  2939. parentRef = m_nodePool->getNodeAtIdx(bestNode->pidx)->id;
  2940. if (parentRef)
  2941. m_nav->getTileAndPolyByRefUnsafe(parentRef, &parentTile, &parentPoly);
  2942. // Hit test walls.
  2943. for (int i = 0, j = (int)bestPoly->vertCount-1; i < (int)bestPoly->vertCount; j = i++)
  2944. {
  2945. // Skip non-solid edges.
  2946. if (bestPoly->neis[j] & DT_EXT_LINK)
  2947. {
  2948. // Tile border.
  2949. bool solid = true;
  2950. for (unsigned int k = bestPoly->firstLink; k != DT_NULL_LINK; k = bestTile->links[k].next)
  2951. {
  2952. const dtLink* link = &bestTile->links[k];
  2953. if (link->edge == j)
  2954. {
  2955. if (link->ref != 0)
  2956. {
  2957. const dtMeshTile* neiTile = 0;
  2958. const dtPoly* neiPoly = 0;
  2959. m_nav->getTileAndPolyByRefUnsafe(link->ref, &neiTile, &neiPoly);
  2960. if (filter->passFilter(link->ref, neiTile, neiPoly))
  2961. solid = false;
  2962. }
  2963. break;
  2964. }
  2965. }
  2966. if (!solid) continue;
  2967. }
  2968. else if (bestPoly->neis[j])
  2969. {
  2970. // Internal edge
  2971. const unsigned int idx = (unsigned int)(bestPoly->neis[j]-1);
  2972. const dtPolyRef ref = m_nav->getPolyRefBase(bestTile) | idx;
  2973. if (filter->passFilter(ref, bestTile, &bestTile->polys[idx]))
  2974. continue;
  2975. }
  2976. // Calc distance to the edge.
  2977. const float* vj = &bestTile->verts[bestPoly->verts[j]*3];
  2978. const float* vi = &bestTile->verts[bestPoly->verts[i]*3];
  2979. float tseg;
  2980. float distSqr = dtDistancePtSegSqr2D(centerPos, vj, vi, tseg);
  2981. // Edge is too far, skip.
  2982. if (distSqr > radiusSqr)
  2983. continue;
  2984. // Hit wall, update radius.
  2985. radiusSqr = distSqr;
  2986. // Calculate hit pos.
  2987. hitPos[0] = vj[0] + (vi[0] - vj[0])*tseg;
  2988. hitPos[1] = vj[1] + (vi[1] - vj[1])*tseg;
  2989. hitPos[2] = vj[2] + (vi[2] - vj[2])*tseg;
  2990. }
  2991. for (unsigned int i = bestPoly->firstLink; i != DT_NULL_LINK; i = bestTile->links[i].next)
  2992. {
  2993. const dtLink* link = &bestTile->links[i];
  2994. dtPolyRef neighbourRef = link->ref;
  2995. // Skip invalid neighbours and do not follow back to parent.
  2996. if (!neighbourRef || neighbourRef == parentRef)
  2997. continue;
  2998. // Expand to neighbour.
  2999. const dtMeshTile* neighbourTile = 0;
  3000. const dtPoly* neighbourPoly = 0;
  3001. m_nav->getTileAndPolyByRefUnsafe(neighbourRef, &neighbourTile, &neighbourPoly);
  3002. // Skip off-mesh connections.
  3003. if (neighbourPoly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
  3004. continue;
  3005. // Calc distance to the edge.
  3006. const float* va = &bestTile->verts[bestPoly->verts[link->edge]*3];
  3007. const float* vb = &bestTile->verts[bestPoly->verts[(link->edge+1) % bestPoly->vertCount]*3];
  3008. float tseg;
  3009. float distSqr = dtDistancePtSegSqr2D(centerPos, va, vb, tseg);
  3010. // If the circle is not touching the next polygon, skip it.
  3011. if (distSqr > radiusSqr)
  3012. continue;
  3013. if (!filter->passFilter(neighbourRef, neighbourTile, neighbourPoly))
  3014. continue;
  3015. dtNode* neighbourNode = m_nodePool->getNode(neighbourRef);
  3016. if (!neighbourNode)
  3017. {
  3018. status |= DT_OUT_OF_NODES;
  3019. continue;
  3020. }
  3021. if (neighbourNode->flags & DT_NODE_CLOSED)
  3022. continue;
  3023. // Cost
  3024. if (neighbourNode->flags == 0)
  3025. {
  3026. getEdgeMidPoint(bestRef, bestPoly, bestTile,
  3027. neighbourRef, neighbourPoly, neighbourTile, neighbourNode->pos);
  3028. }
  3029. const float total = bestNode->total + dtVdist(bestNode->pos, neighbourNode->pos);
  3030. // The node is already in open list and the new result is worse, skip.
  3031. if ((neighbourNode->flags & DT_NODE_OPEN) && total >= neighbourNode->total)
  3032. continue;
  3033. neighbourNode->id = neighbourRef;
  3034. neighbourNode->flags = (neighbourNode->flags & ~DT_NODE_CLOSED);
  3035. neighbourNode->pidx = m_nodePool->getNodeIdx(bestNode);
  3036. neighbourNode->total = total;
  3037. if (neighbourNode->flags & DT_NODE_OPEN)
  3038. {
  3039. m_openList->modify(neighbourNode);
  3040. }
  3041. else
  3042. {
  3043. neighbourNode->flags |= DT_NODE_OPEN;
  3044. m_openList->push(neighbourNode);
  3045. }
  3046. }
  3047. }
  3048. // Calc hit normal.
  3049. dtVsub(hitNormal, centerPos, hitPos);
  3050. dtVnormalize(hitNormal);
  3051. *hitDist = dtMathSqrtf(radiusSqr);
  3052. return status;
  3053. }
  3054. bool dtNavMeshQuery::isValidPolyRef(dtPolyRef ref, const dtQueryFilter* filter) const
  3055. {
  3056. const dtMeshTile* tile = 0;
  3057. const dtPoly* poly = 0;
  3058. dtStatus status = m_nav->getTileAndPolyByRef(ref, &tile, &poly);
  3059. // If cannot get polygon, assume it does not exists and boundary is invalid.
  3060. if (dtStatusFailed(status))
  3061. return false;
  3062. // If cannot pass filter, assume flags has changed and boundary is invalid.
  3063. if (!filter->passFilter(ref, tile, poly))
  3064. return false;
  3065. return true;
  3066. }
  3067. /// @par
  3068. ///
  3069. /// The closed list is the list of polygons that were fully evaluated during
  3070. /// the last navigation graph search. (A* or Dijkstra)
  3071. ///
  3072. bool dtNavMeshQuery::isInClosedList(dtPolyRef ref) const
  3073. {
  3074. if (!m_nodePool) return false;
  3075. dtNode* nodes[DT_MAX_STATES_PER_NODE];
  3076. int n= m_nodePool->findNodes(ref, nodes, DT_MAX_STATES_PER_NODE);
  3077. for (int i=0; i<n; i++)
  3078. {
  3079. if (nodes[i]->flags & DT_NODE_CLOSED)
  3080. return true;
  3081. }
  3082. return false;
  3083. }