DetourCommon.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #ifndef DETOURCOMMON_H
  19. #define DETOURCOMMON_H
  20. #include "DetourMath.h"
  21. #include <stddef.h>
  22. /**
  23. @defgroup detour Detour
  24. Members in this module are used to create, manipulate, and query navigation
  25. meshes.
  26. @note This is a summary list of members. Use the index or search
  27. feature to find minor members.
  28. */
  29. /// @name General helper functions
  30. /// @{
  31. /// Used to ignore a function parameter. VS complains about unused parameters
  32. /// and this silences the warning.
  33. /// @param [in] _ Unused parameter
  34. template<class T> void dtIgnoreUnused(const T&) { }
  35. /// Swaps the values of the two parameters.
  36. /// @param[in,out] a Value A
  37. /// @param[in,out] b Value B
  38. template<class T> inline void dtSwap(T& a, T& b) { T t = a; a = b; b = t; }
  39. /// Returns the minimum of two values.
  40. /// @param[in] a Value A
  41. /// @param[in] b Value B
  42. /// @return The minimum of the two values.
  43. template<class T> inline T dtMin(T a, T b) { return a < b ? a : b; }
  44. /// Returns the maximum of two values.
  45. /// @param[in] a Value A
  46. /// @param[in] b Value B
  47. /// @return The maximum of the two values.
  48. template<class T> inline T dtMax(T a, T b) { return a > b ? a : b; }
  49. /// Returns the absolute value.
  50. /// @param[in] a The value.
  51. /// @return The absolute value of the specified value.
  52. template<class T> inline T dtAbs(T a) { return a < 0 ? -a : a; }
  53. /// Returns the square of the value.
  54. /// @param[in] a The value.
  55. /// @return The square of the value.
  56. template<class T> inline T dtSqr(T a) { return a*a; }
  57. /// Clamps the value to the specified range.
  58. /// @param[in] v The value to clamp.
  59. /// @param[in] mn The minimum permitted return value.
  60. /// @param[in] mx The maximum permitted return value.
  61. /// @return The value, clamped to the specified range.
  62. template<class T> inline T dtClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); }
  63. /// @}
  64. /// @name Vector helper functions.
  65. /// @{
  66. /// Derives the cross product of two vectors. (@p v1 x @p v2)
  67. /// @param[out] dest The cross product. [(x, y, z)]
  68. /// @param[in] v1 A Vector [(x, y, z)]
  69. /// @param[in] v2 A vector [(x, y, z)]
  70. inline void dtVcross(float* dest, const float* v1, const float* v2)
  71. {
  72. dest[0] = v1[1]*v2[2] - v1[2]*v2[1];
  73. dest[1] = v1[2]*v2[0] - v1[0]*v2[2];
  74. dest[2] = v1[0]*v2[1] - v1[1]*v2[0];
  75. }
  76. /// Derives the dot product of two vectors. (@p v1 . @p v2)
  77. /// @param[in] v1 A Vector [(x, y, z)]
  78. /// @param[in] v2 A vector [(x, y, z)]
  79. /// @return The dot product.
  80. inline float dtVdot(const float* v1, const float* v2)
  81. {
  82. return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
  83. }
  84. /// Performs a scaled vector addition. (@p v1 + (@p v2 * @p s))
  85. /// @param[out] dest The result vector. [(x, y, z)]
  86. /// @param[in] v1 The base vector. [(x, y, z)]
  87. /// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)]
  88. /// @param[in] s The amount to scale @p v2 by before adding to @p v1.
  89. inline void dtVmad(float* dest, const float* v1, const float* v2, const float s)
  90. {
  91. dest[0] = v1[0]+v2[0]*s;
  92. dest[1] = v1[1]+v2[1]*s;
  93. dest[2] = v1[2]+v2[2]*s;
  94. }
  95. /// Performs a linear interpolation between two vectors. (@p v1 toward @p v2)
  96. /// @param[out] dest The result vector. [(x, y, x)]
  97. /// @param[in] v1 The starting vector.
  98. /// @param[in] v2 The destination vector.
  99. /// @param[in] t The interpolation factor. [Limits: 0 <= value <= 1.0]
  100. inline void dtVlerp(float* dest, const float* v1, const float* v2, const float t)
  101. {
  102. dest[0] = v1[0]+(v2[0]-v1[0])*t;
  103. dest[1] = v1[1]+(v2[1]-v1[1])*t;
  104. dest[2] = v1[2]+(v2[2]-v1[2])*t;
  105. }
  106. /// Performs a vector addition. (@p v1 + @p v2)
  107. /// @param[out] dest The result vector. [(x, y, z)]
  108. /// @param[in] v1 The base vector. [(x, y, z)]
  109. /// @param[in] v2 The vector to add to @p v1. [(x, y, z)]
  110. inline void dtVadd(float* dest, const float* v1, const float* v2)
  111. {
  112. dest[0] = v1[0]+v2[0];
  113. dest[1] = v1[1]+v2[1];
  114. dest[2] = v1[2]+v2[2];
  115. }
  116. /// Performs a vector subtraction. (@p v1 - @p v2)
  117. /// @param[out] dest The result vector. [(x, y, z)]
  118. /// @param[in] v1 The base vector. [(x, y, z)]
  119. /// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)]
  120. inline void dtVsub(float* dest, const float* v1, const float* v2)
  121. {
  122. dest[0] = v1[0]-v2[0];
  123. dest[1] = v1[1]-v2[1];
  124. dest[2] = v1[2]-v2[2];
  125. }
  126. /// Scales the vector by the specified value. (@p v * @p t)
  127. /// @param[out] dest The result vector. [(x, y, z)]
  128. /// @param[in] v The vector to scale. [(x, y, z)]
  129. /// @param[in] t The scaling factor.
  130. inline void dtVscale(float* dest, const float* v, const float t)
  131. {
  132. dest[0] = v[0]*t;
  133. dest[1] = v[1]*t;
  134. dest[2] = v[2]*t;
  135. }
  136. /// Selects the minimum value of each element from the specified vectors.
  137. /// @param[in,out] mn A vector. (Will be updated with the result.) [(x, y, z)]
  138. /// @param[in] v A vector. [(x, y, z)]
  139. inline void dtVmin(float* mn, const float* v)
  140. {
  141. mn[0] = dtMin(mn[0], v[0]);
  142. mn[1] = dtMin(mn[1], v[1]);
  143. mn[2] = dtMin(mn[2], v[2]);
  144. }
  145. /// Selects the maximum value of each element from the specified vectors.
  146. /// @param[in,out] mx A vector. (Will be updated with the result.) [(x, y, z)]
  147. /// @param[in] v A vector. [(x, y, z)]
  148. inline void dtVmax(float* mx, const float* v)
  149. {
  150. mx[0] = dtMax(mx[0], v[0]);
  151. mx[1] = dtMax(mx[1], v[1]);
  152. mx[2] = dtMax(mx[2], v[2]);
  153. }
  154. /// Sets the vector elements to the specified values.
  155. /// @param[out] dest The result vector. [(x, y, z)]
  156. /// @param[in] x The x-value of the vector.
  157. /// @param[in] y The y-value of the vector.
  158. /// @param[in] z The z-value of the vector.
  159. inline void dtVset(float* dest, const float x, const float y, const float z)
  160. {
  161. dest[0] = x; dest[1] = y; dest[2] = z;
  162. }
  163. /// Performs a vector copy.
  164. /// @param[out] dest The result. [(x, y, z)]
  165. /// @param[in] a The vector to copy. [(x, y, z)]
  166. inline void dtVcopy(float* dest, const float* a)
  167. {
  168. dest[0] = a[0];
  169. dest[1] = a[1];
  170. dest[2] = a[2];
  171. }
  172. /// Derives the scalar length of the vector.
  173. /// @param[in] v The vector. [(x, y, z)]
  174. /// @return The scalar length of the vector.
  175. inline float dtVlen(const float* v)
  176. {
  177. return dtMathSqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  178. }
  179. /// Derives the square of the scalar length of the vector. (len * len)
  180. /// @param[in] v The vector. [(x, y, z)]
  181. /// @return The square of the scalar length of the vector.
  182. inline float dtVlenSqr(const float* v)
  183. {
  184. return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
  185. }
  186. /// Returns the distance between two points.
  187. /// @param[in] v1 A point. [(x, y, z)]
  188. /// @param[in] v2 A point. [(x, y, z)]
  189. /// @return The distance between the two points.
  190. inline float dtVdist(const float* v1, const float* v2)
  191. {
  192. const float dx = v2[0] - v1[0];
  193. const float dy = v2[1] - v1[1];
  194. const float dz = v2[2] - v1[2];
  195. return dtMathSqrtf(dx*dx + dy*dy + dz*dz);
  196. }
  197. /// Returns the square of the distance between two points.
  198. /// @param[in] v1 A point. [(x, y, z)]
  199. /// @param[in] v2 A point. [(x, y, z)]
  200. /// @return The square of the distance between the two points.
  201. inline float dtVdistSqr(const float* v1, const float* v2)
  202. {
  203. const float dx = v2[0] - v1[0];
  204. const float dy = v2[1] - v1[1];
  205. const float dz = v2[2] - v1[2];
  206. return dx*dx + dy*dy + dz*dz;
  207. }
  208. /// Derives the distance between the specified points on the xz-plane.
  209. /// @param[in] v1 A point. [(x, y, z)]
  210. /// @param[in] v2 A point. [(x, y, z)]
  211. /// @return The distance between the point on the xz-plane.
  212. ///
  213. /// The vectors are projected onto the xz-plane, so the y-values are ignored.
  214. inline float dtVdist2D(const float* v1, const float* v2)
  215. {
  216. const float dx = v2[0] - v1[0];
  217. const float dz = v2[2] - v1[2];
  218. return dtMathSqrtf(dx*dx + dz*dz);
  219. }
  220. /// Derives the square of the distance between the specified points on the xz-plane.
  221. /// @param[in] v1 A point. [(x, y, z)]
  222. /// @param[in] v2 A point. [(x, y, z)]
  223. /// @return The square of the distance between the point on the xz-plane.
  224. inline float dtVdist2DSqr(const float* v1, const float* v2)
  225. {
  226. const float dx = v2[0] - v1[0];
  227. const float dz = v2[2] - v1[2];
  228. return dx*dx + dz*dz;
  229. }
  230. /// Normalizes the vector.
  231. /// @param[in,out] v The vector to normalize. [(x, y, z)]
  232. inline void dtVnormalize(float* v)
  233. {
  234. float d = 1.0f / dtMathSqrtf(dtSqr(v[0]) + dtSqr(v[1]) + dtSqr(v[2]));
  235. v[0] *= d;
  236. v[1] *= d;
  237. v[2] *= d;
  238. }
  239. /// Performs a 'sloppy' colocation check of the specified points.
  240. /// @param[in] p0 A point. [(x, y, z)]
  241. /// @param[in] p1 A point. [(x, y, z)]
  242. /// @return True if the points are considered to be at the same location.
  243. ///
  244. /// Basically, this function will return true if the specified points are
  245. /// close enough to eachother to be considered colocated.
  246. inline bool dtVequal(const float* p0, const float* p1)
  247. {
  248. static const float thr = dtSqr(1.0f/16384.0f);
  249. const float d = dtVdistSqr(p0, p1);
  250. return d < thr;
  251. }
  252. /// Checks that the specified vector's components are all finite.
  253. /// @param[in] v A point. [(x, y, z)]
  254. /// @return True if all of the point's components are finite, i.e. not NaN
  255. /// or any of the infinities.
  256. inline bool dtVisfinite(const float* v)
  257. {
  258. bool result =
  259. dtMathIsfinite(v[0]) &&
  260. dtMathIsfinite(v[1]) &&
  261. dtMathIsfinite(v[2]);
  262. return result;
  263. }
  264. /// Checks that the specified vector's 2D components are finite.
  265. /// @param[in] v A point. [(x, y, z)]
  266. inline bool dtVisfinite2D(const float* v)
  267. {
  268. bool result = dtMathIsfinite(v[0]) && dtMathIsfinite(v[2]);
  269. return result;
  270. }
  271. /// Derives the dot product of two vectors on the xz-plane. (@p u . @p v)
  272. /// @param[in] u A vector [(x, y, z)]
  273. /// @param[in] v A vector [(x, y, z)]
  274. /// @return The dot product on the xz-plane.
  275. ///
  276. /// The vectors are projected onto the xz-plane, so the y-values are ignored.
  277. inline float dtVdot2D(const float* u, const float* v)
  278. {
  279. return u[0]*v[0] + u[2]*v[2];
  280. }
  281. /// Derives the xz-plane 2D perp product of the two vectors. (uz*vx - ux*vz)
  282. /// @param[in] u The LHV vector [(x, y, z)]
  283. /// @param[in] v The RHV vector [(x, y, z)]
  284. /// @return The dot product on the xz-plane.
  285. ///
  286. /// The vectors are projected onto the xz-plane, so the y-values are ignored.
  287. inline float dtVperp2D(const float* u, const float* v)
  288. {
  289. return u[2]*v[0] - u[0]*v[2];
  290. }
  291. /// @}
  292. /// @name Computational geometry helper functions.
  293. /// @{
  294. /// Derives the signed xz-plane area of the triangle ABC, or the relationship of line AB to point C.
  295. /// @param[in] a Vertex A. [(x, y, z)]
  296. /// @param[in] b Vertex B. [(x, y, z)]
  297. /// @param[in] c Vertex C. [(x, y, z)]
  298. /// @return The signed xz-plane area of the triangle.
  299. inline float dtTriArea2D(const float* a, const float* b, const float* c)
  300. {
  301. const float abx = b[0] - a[0];
  302. const float abz = b[2] - a[2];
  303. const float acx = c[0] - a[0];
  304. const float acz = c[2] - a[2];
  305. return acx*abz - abx*acz;
  306. }
  307. /// Determines if two axis-aligned bounding boxes overlap.
  308. /// @param[in] amin Minimum bounds of box A. [(x, y, z)]
  309. /// @param[in] amax Maximum bounds of box A. [(x, y, z)]
  310. /// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
  311. /// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
  312. /// @return True if the two AABB's overlap.
  313. /// @see dtOverlapBounds
  314. inline bool dtOverlapQuantBounds(const unsigned short amin[3], const unsigned short amax[3],
  315. const unsigned short bmin[3], const unsigned short bmax[3])
  316. {
  317. bool overlap = true;
  318. overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
  319. overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
  320. overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
  321. return overlap;
  322. }
  323. /// Determines if two axis-aligned bounding boxes overlap.
  324. /// @param[in] amin Minimum bounds of box A. [(x, y, z)]
  325. /// @param[in] amax Maximum bounds of box A. [(x, y, z)]
  326. /// @param[in] bmin Minimum bounds of box B. [(x, y, z)]
  327. /// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
  328. /// @return True if the two AABB's overlap.
  329. /// @see dtOverlapQuantBounds
  330. inline bool dtOverlapBounds(const float* amin, const float* amax,
  331. const float* bmin, const float* bmax)
  332. {
  333. bool overlap = true;
  334. overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
  335. overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
  336. overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
  337. return overlap;
  338. }
  339. /// Derives the closest point on a triangle from the specified reference point.
  340. /// @param[out] closest The closest point on the triangle.
  341. /// @param[in] p The reference point from which to test. [(x, y, z)]
  342. /// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
  343. /// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
  344. /// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
  345. void dtClosestPtPointTriangle(float* closest, const float* p,
  346. const float* a, const float* b, const float* c);
  347. /// Derives the y-axis height of the closest point on the triangle from the specified reference point.
  348. /// @param[in] p The reference point from which to test. [(x, y, z)]
  349. /// @param[in] a Vertex A of triangle ABC. [(x, y, z)]
  350. /// @param[in] b Vertex B of triangle ABC. [(x, y, z)]
  351. /// @param[in] c Vertex C of triangle ABC. [(x, y, z)]
  352. /// @param[out] h The resulting height.
  353. bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h);
  354. bool dtIntersectSegmentPoly2D(const float* p0, const float* p1,
  355. const float* verts, int nverts,
  356. float& tmin, float& tmax,
  357. int& segMin, int& segMax);
  358. bool dtIntersectSegSeg2D(const float* ap, const float* aq,
  359. const float* bp, const float* bq,
  360. float& s, float& t);
  361. /// Determines if the specified point is inside the convex polygon on the xz-plane.
  362. /// @param[in] pt The point to check. [(x, y, z)]
  363. /// @param[in] verts The polygon vertices. [(x, y, z) * @p nverts]
  364. /// @param[in] nverts The number of vertices. [Limit: >= 3]
  365. /// @return True if the point is inside the polygon.
  366. bool dtPointInPolygon(const float* pt, const float* verts, const int nverts);
  367. bool dtDistancePtPolyEdgesSqr(const float* pt, const float* verts, const int nverts,
  368. float* ed, float* et);
  369. float dtDistancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t);
  370. /// Derives the centroid of a convex polygon.
  371. /// @param[out] tc The centroid of the polgyon. [(x, y, z)]
  372. /// @param[in] idx The polygon indices. [(vertIndex) * @p nidx]
  373. /// @param[in] nidx The number of indices in the polygon. [Limit: >= 3]
  374. /// @param[in] verts The polygon vertices. [(x, y, z) * vertCount]
  375. void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts);
  376. /// Determines if the two convex polygons overlap on the xz-plane.
  377. /// @param[in] polya Polygon A vertices. [(x, y, z) * @p npolya]
  378. /// @param[in] npolya The number of vertices in polygon A.
  379. /// @param[in] polyb Polygon B vertices. [(x, y, z) * @p npolyb]
  380. /// @param[in] npolyb The number of vertices in polygon B.
  381. /// @return True if the two polygons overlap.
  382. bool dtOverlapPolyPoly2D(const float* polya, const int npolya,
  383. const float* polyb, const int npolyb);
  384. /// @}
  385. /// @name Miscellanious functions.
  386. /// @{
  387. inline unsigned int dtNextPow2(unsigned int v)
  388. {
  389. v--;
  390. v |= v >> 1;
  391. v |= v >> 2;
  392. v |= v >> 4;
  393. v |= v >> 8;
  394. v |= v >> 16;
  395. v++;
  396. return v;
  397. }
  398. inline unsigned int dtIlog2(unsigned int v)
  399. {
  400. unsigned int r;
  401. unsigned int shift;
  402. r = (v > 0xffff) << 4; v >>= r;
  403. shift = (v > 0xff) << 3; v >>= shift; r |= shift;
  404. shift = (v > 0xf) << 2; v >>= shift; r |= shift;
  405. shift = (v > 0x3) << 1; v >>= shift; r |= shift;
  406. r |= (v >> 1);
  407. return r;
  408. }
  409. inline int dtAlign4(int x) { return (x+3) & ~3; }
  410. inline int dtOppositeTile(int side) { return (side+4) & 0x7; }
  411. inline void dtSwapByte(unsigned char* a, unsigned char* b)
  412. {
  413. unsigned char tmp = *a;
  414. *a = *b;
  415. *b = tmp;
  416. }
  417. inline void dtSwapEndian(unsigned short* v)
  418. {
  419. unsigned char* x = (unsigned char*)v;
  420. dtSwapByte(x+0, x+1);
  421. }
  422. inline void dtSwapEndian(short* v)
  423. {
  424. unsigned char* x = (unsigned char*)v;
  425. dtSwapByte(x+0, x+1);
  426. }
  427. inline void dtSwapEndian(unsigned int* v)
  428. {
  429. unsigned char* x = (unsigned char*)v;
  430. dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
  431. }
  432. inline void dtSwapEndian(int* v)
  433. {
  434. unsigned char* x = (unsigned char*)v;
  435. dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
  436. }
  437. inline void dtSwapEndian(float* v)
  438. {
  439. unsigned char* x = (unsigned char*)v;
  440. dtSwapByte(x+0, x+3); dtSwapByte(x+1, x+2);
  441. }
  442. void dtRandomPointInConvexPoly(const float* pts, const int npts, float* areas,
  443. const float s, const float t, float* out);
  444. template<typename TypeToRetrieveAs>
  445. TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(const unsigned char*& buffer, const size_t distanceToAdvance)
  446. {
  447. TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
  448. buffer += distanceToAdvance;
  449. return returnPointer;
  450. }
  451. template<typename TypeToRetrieveAs>
  452. TypeToRetrieveAs* dtGetThenAdvanceBufferPointer(unsigned char*& buffer, const size_t distanceToAdvance)
  453. {
  454. TypeToRetrieveAs* returnPointer = reinterpret_cast<TypeToRetrieveAs*>(buffer);
  455. buffer += distanceToAdvance;
  456. return returnPointer;
  457. }
  458. /// @}
  459. #endif // DETOURCOMMON_H
  460. ///////////////////////////////////////////////////////////////////////////
  461. // This section contains detailed documentation for members that don't have
  462. // a source file. It reduces clutter in the main section of the header.
  463. /**
  464. @fn float dtTriArea2D(const float* a, const float* b, const float* c)
  465. @par
  466. The vertices are projected onto the xz-plane, so the y-values are ignored.
  467. This is a low cost function than can be used for various purposes. Its main purpose
  468. is for point/line relationship testing.
  469. In all cases: A value of zero indicates that all vertices are collinear or represent the same point.
  470. (On the xz-plane.)
  471. When used for point/line relationship tests, AB usually represents a line against which
  472. the C point is to be tested. In this case:
  473. A positive value indicates that point C is to the left of line AB, looking from A toward B.<br/>
  474. A negative value indicates that point C is to the right of lineAB, looking from A toward B.
  475. When used for evaluating a triangle:
  476. The absolute value of the return value is two times the area of the triangle when it is
  477. projected onto the xz-plane.
  478. A positive return value indicates:
  479. <ul>
  480. <li>The vertices are wrapped in the normal Detour wrap direction.</li>
  481. <li>The triangle's 3D face normal is in the general up direction.</li>
  482. </ul>
  483. A negative return value indicates:
  484. <ul>
  485. <li>The vertices are reverse wrapped. (Wrapped opposite the normal Detour wrap direction.)</li>
  486. <li>The triangle's 3D face normal is in the general down direction.</li>
  487. </ul>
  488. */