DetourNavMeshQuery.cpp 92 KB

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