DetourNavMeshQuery.cpp 102 KB

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