DetourCommon.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. //
  2. // Copyright (c) 2009 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. #include <math.h>
  19. #include "DetourCommon.h"
  20. void closestPtPointTriangle(float* closest, const float* p,
  21. const float* a, const float* b, const float* c)
  22. {
  23. // Check if P in vertex region outside A
  24. float ab[3], ac[3], ap[3];
  25. vsub(ab, b, a);
  26. vsub(ac, c, a);
  27. vsub(ap, p, a);
  28. float d1 = vdot(ab, ap);
  29. float d2 = vdot(ac, ap);
  30. if (d1 <= 0.0f && d2 <= 0.0f)
  31. {
  32. // barycentric coordinates (1,0,0)
  33. vcopy(closest, a);
  34. return;
  35. }
  36. // Check if P in vertex region outside B
  37. float bp[3];
  38. vsub(bp, p, b);
  39. float d3 = vdot(ab, bp);
  40. float d4 = vdot(ac, bp);
  41. if (d3 >= 0.0f && d4 <= d3)
  42. {
  43. // barycentric coordinates (0,1,0)
  44. vcopy(closest, b);
  45. return;
  46. }
  47. // Check if P in edge region of AB, if so return projection of P onto AB
  48. float vc = d1*d4 - d3*d2;
  49. if (vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f)
  50. {
  51. // barycentric coordinates (1-v,v,0)
  52. float v = d1 / (d1 - d3);
  53. closest[0] = a[0] + v * ab[0];
  54. closest[1] = a[1] + v * ab[1];
  55. closest[2] = a[2] + v * ab[2];
  56. return;
  57. }
  58. // Check if P in vertex region outside C
  59. float cp[3];
  60. vsub(cp, p, c);
  61. float d5 = vdot(ab, cp);
  62. float d6 = vdot(ac, cp);
  63. if (d6 >= 0.0f && d5 <= d6)
  64. {
  65. // barycentric coordinates (0,0,1)
  66. vcopy(closest, c);
  67. return;
  68. }
  69. // Check if P in edge region of AC, if so return projection of P onto AC
  70. float vb = d5*d2 - d1*d6;
  71. if (vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f)
  72. {
  73. // barycentric coordinates (1-w,0,w)
  74. float w = d2 / (d2 - d6);
  75. closest[0] = a[0] + w * ac[0];
  76. closest[1] = a[1] + w * ac[1];
  77. closest[2] = a[2] + w * ac[2];
  78. return;
  79. }
  80. // Check if P in edge region of BC, if so return projection of P onto BC
  81. float va = d3*d6 - d5*d4;
  82. if (va <= 0.0f && (d4 - d3) >= 0.0f && (d5 - d6) >= 0.0f)
  83. {
  84. // barycentric coordinates (0,1-w,w)
  85. float w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
  86. closest[0] = b[0] + w * (c[0] - b[0]);
  87. closest[1] = b[1] + w * (c[1] - b[1]);
  88. closest[2] = b[2] + w * (c[2] - b[2]);
  89. return;
  90. }
  91. // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
  92. float denom = 1.0f / (va + vb + vc);
  93. float v = vb * denom;
  94. float w = vc * denom;
  95. closest[0] = a[0] + ab[0] * v + ac[0] * w;
  96. closest[1] = a[1] + ab[1] * v + ac[1] * w;
  97. closest[2] = a[2] + ab[2] * v + ac[2] * w;
  98. }
  99. bool intersectSegmentPoly2D(const float* p0, const float* p1,
  100. const float* verts, int nverts,
  101. float& tmin, float& tmax,
  102. int& segMin, int& segMax)
  103. {
  104. static const float EPS = 0.00000001f;
  105. tmin = 0;
  106. tmax = 1;
  107. segMin = -1;
  108. segMax = -1;
  109. float dir[3];
  110. vsub(dir, p1, p0);
  111. for (int i = 0, j = nverts-1; i < nverts; j=i++)
  112. {
  113. float edge[3], diff[3];
  114. vsub(edge, &verts[i*3], &verts[j*3]);
  115. vsub(diff, p0, &verts[j*3]);
  116. float n = vperp2D(edge, diff);
  117. float d = -vperp2D(edge, dir);
  118. if (fabs(d) < EPS)
  119. {
  120. // S is nearly parallel to this edge
  121. if (n < 0)
  122. return false;
  123. else
  124. continue;
  125. }
  126. float t = n / d;
  127. if (d < 0)
  128. {
  129. // segment S is entering across this edge
  130. if (t > tmin)
  131. {
  132. tmin = t;
  133. segMin = j;
  134. // S enters after leaving polygon
  135. if (tmin > tmax)
  136. return false;
  137. }
  138. }
  139. else
  140. {
  141. // segment S is leaving across this edge
  142. if (t < tmax)
  143. {
  144. tmax = t;
  145. segMax = j;
  146. // S leaves before entering polygon
  147. if (tmax < tmin)
  148. return false;
  149. }
  150. }
  151. }
  152. return true;
  153. }
  154. float distancePtSegSqr2D(const float* pt, const float* p, const float* q, float& t)
  155. {
  156. float pqx = q[0] - p[0];
  157. float pqz = q[2] - p[2];
  158. float dx = pt[0] - p[0];
  159. float dz = pt[2] - p[2];
  160. float d = pqx*pqx + pqz*pqz;
  161. t = pqx*dx + pqz*dz;
  162. if (d > 0)
  163. t /= d;
  164. if (t < 0)
  165. t = 0;
  166. else if (t > 1)
  167. t = 1;
  168. dx = p[0] + t*pqx - pt[0];
  169. dz = p[2] + t*pqz - pt[2];
  170. return dx*dx + dz*dz;
  171. }
  172. void calcPolyCenter(float* tc, const unsigned short* idx, int nidx, const float* verts)
  173. {
  174. tc[0] = 0.0f;
  175. tc[1] = 0.0f;
  176. tc[2] = 0.0f;
  177. for (int j = 0; j < nidx; ++j)
  178. {
  179. const float* v = &verts[idx[j]*3];
  180. tc[0] += v[0];
  181. tc[1] += v[1];
  182. tc[2] += v[2];
  183. }
  184. const float s = 1.0f / nidx;
  185. tc[0] *= s;
  186. tc[1] *= s;
  187. tc[2] *= s;
  188. }
  189. inline float vdot2(const float* a, const float* b)
  190. {
  191. return a[0]*b[0] + a[2]*b[2];
  192. }
  193. #include <stdio.h>
  194. bool closestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h)
  195. {
  196. float v0[3], v1[3], v2[3];
  197. vsub(v0, c,a);
  198. vsub(v1, b,a);
  199. vsub(v2, p,a);
  200. const float dot00 = vdot2(v0, v0);
  201. const float dot01 = vdot2(v0, v1);
  202. const float dot02 = vdot2(v0, v2);
  203. const float dot11 = vdot2(v1, v1);
  204. const float dot12 = vdot2(v1, v2);
  205. // Compute barycentric coordinates
  206. float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
  207. float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
  208. float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
  209. // The (sloppy) epsilon is needed to allow to get height of points which
  210. // are interpolated along the edges of the triangles.
  211. static const float EPS = 1e-4f;
  212. // If point lies inside the triangle, return interpolated ycoord.
  213. if (u >= -EPS && v >= -EPS && (u+v) <= 1+EPS)
  214. {
  215. h = a[1] + v0[1]*u + v1[1]*v;
  216. return true;
  217. }
  218. return false;
  219. }