DetourNavMeshQuery.cpp 90 KB

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