DetourNavMeshQuery.cpp 92 KB

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