AstarMath.cs 66 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703
  1. using PF;
  2. using System.Collections.Generic;
  3. using System;
  4. namespace PF {
  5. /** Contains various spline functions.
  6. * \ingroup utils
  7. */
  8. static class AstarSplines {
  9. public static Vector3 CatmullRom (Vector3 previous, Vector3 start, Vector3 end, Vector3 next, float elapsedTime) {
  10. // References used:
  11. // p.266 GemsV1
  12. //
  13. // tension is often set to 0.5 but you can use any reasonable value:
  14. // http://www.cs.cmu.edu/~462/projects/assn2/assn2/catmullRom.pdf
  15. //
  16. // bias and tension controls:
  17. // http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/interpolation/
  18. float percentComplete = elapsedTime;
  19. float percentCompleteSquared = percentComplete * percentComplete;
  20. float percentCompleteCubed = percentCompleteSquared * percentComplete;
  21. return
  22. previous * (-0.5F*percentCompleteCubed +
  23. percentCompleteSquared -
  24. 0.5F*percentComplete) +
  25. start *
  26. (1.5F*percentCompleteCubed +
  27. -2.5F*percentCompleteSquared + 1.0F) +
  28. end *
  29. (-1.5F*percentCompleteCubed +
  30. 2.0F*percentCompleteSquared +
  31. 0.5F*percentComplete) +
  32. next *
  33. (0.5F*percentCompleteCubed -
  34. 0.5F*percentCompleteSquared);
  35. }
  36. [System.Obsolete("Use CatmullRom")]
  37. public static Vector3 CatmullRomOLD (Vector3 previous, Vector3 start, Vector3 end, Vector3 next, float elapsedTime) {
  38. return CatmullRom(previous, start, end, next, elapsedTime);
  39. }
  40. /** Returns a point on a cubic bezier curve. \a t is clamped between 0 and 1 */
  41. public static Vector3 CubicBezier (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
  42. t = Mathf.Clamp01(t);
  43. float t2 = 1-t;
  44. return t2*t2*t2 * p0 + 3 * t2*t2 * t * p1 + 3 * t2 * t*t * p2 + t*t*t * p3;
  45. }
  46. /** Returns the derivative for a point on a cubic bezier curve. \a t is clamped between 0 and 1 */
  47. public static Vector3 CubicBezierDerivative (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
  48. t = Mathf.Clamp01(t);
  49. float t2 = 1-t;
  50. return 3*t2*t2*(p1-p0) + 6*t2*t*(p2 - p1) + 3*t*t*(p3 - p2);
  51. }
  52. /** Returns the second derivative for a point on a cubic bezier curve. \a t is clamped between 0 and 1 */
  53. public static Vector3 CubicBezierSecondDerivative (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
  54. t = Mathf.Clamp01(t);
  55. float t2 = 1-t;
  56. return 6*t2*(p2 - 2*p1 + p0) + 6*t*(p3 - 2*p2 + p1);
  57. }
  58. }
  59. /** Various vector math utility functions.
  60. * \version A lot of functions in the Polygon class have been moved to this class
  61. * the names have changed slightly and everything now consistently assumes a left handed
  62. * coordinate system now instead of sometimes using a left handed one and sometimes
  63. * using a right handed one. This is why the 'Left' methods in the Polygon class redirect
  64. * to methods named 'Right'. The functionality is exactly the same.
  65. *
  66. * Note the difference between segments and lines. Lines are infinitely
  67. * long but segments have only a finite length.
  68. *
  69. * \ingroup utils
  70. */
  71. public static class VectorMath {
  72. /** Complex number multiplication.
  73. * \returns a * b
  74. *
  75. * Used to rotate vectors in an efficient way.
  76. *
  77. * \see https://en.wikipedia.org/wiki/Complex_number#Multiplication_and_division
  78. */
  79. public static Vector2 ComplexMultiply (Vector2 a, Vector2 b) {
  80. return new Vector2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
  81. }
  82. /** Complex number multiplication.
  83. * \returns a * conjugate(b)
  84. *
  85. * Used to rotate vectors in an efficient way.
  86. *
  87. * \see https://en.wikipedia.org/wiki/Complex_number#Multiplication_and_division
  88. * \see https://en.wikipedia.org/wiki/Complex_conjugate
  89. */
  90. public static Vector2 ComplexMultiplyConjugate (Vector2 a, Vector2 b) {
  91. return new Vector2(a.x * b.x + a.y * b.y, a.y * b.x - a.x * b.y);
  92. }
  93. /** Returns the closest point on the line.
  94. * The line is treated as infinite.
  95. * \see ClosestPointOnSegment
  96. * \see ClosestPointOnLineFactor
  97. */
  98. public static Vector3 ClosestPointOnLine (Vector3 lineStart, Vector3 lineEnd, Vector3 point) {
  99. Vector3 lineDirection = Vector3.Normalize(lineEnd - lineStart);
  100. float dot = Vector3.Dot(point - lineStart, lineDirection);
  101. return lineStart + (dot*lineDirection);
  102. }
  103. /** Factor along the line which is closest to the point.
  104. * Returned value is in the range [0,1] if the point lies on the segment otherwise it just lies on the line.
  105. * The closest point can be calculated using (end-start)*factor + start.
  106. *
  107. * \see ClosestPointOnLine
  108. * \see ClosestPointOnSegment
  109. */
  110. public static float ClosestPointOnLineFactor (Vector3 lineStart, Vector3 lineEnd, Vector3 point) {
  111. var dir = lineEnd - lineStart;
  112. float sqrMagn = dir.sqrMagnitude;
  113. if (sqrMagn <= 0.000001) return 0;
  114. return Vector3.Dot(point - lineStart, dir) / sqrMagn;
  115. }
  116. /** Factor along the line which is closest to the point.
  117. * Returned value is in the range [0,1] if the point lies on the segment otherwise it just lies on the line.
  118. * The closest point can be calculated using (end-start)*factor + start
  119. */
  120. public static float ClosestPointOnLineFactor (Int3 lineStart, Int3 lineEnd, Int3 point) {
  121. var lineDirection = lineEnd - lineStart;
  122. float magn = lineDirection.sqrMagnitude;
  123. float closestPoint = Int3.Dot((point - lineStart), lineDirection);
  124. if (magn != 0) closestPoint /= magn;
  125. return closestPoint;
  126. }
  127. /** Factor of the nearest point on the segment.
  128. * Returned value is in the range [0,1] if the point lies on the segment otherwise it just lies on the line.
  129. * The closest point can be calculated using (end-start)*factor + start;
  130. */
  131. public static float ClosestPointOnLineFactor (Int2 lineStart, Int2 lineEnd, Int2 point) {
  132. var lineDirection = lineEnd - lineStart;
  133. double magn = lineDirection.sqrMagnitudeLong;
  134. double closestPoint = Int2.DotLong(point - lineStart, lineDirection);
  135. if (magn != 0) closestPoint /= magn;
  136. return (float)closestPoint;
  137. }
  138. /** Returns the closest point on the segment.
  139. * The segment is NOT treated as infinite.
  140. * \see ClosestPointOnLine
  141. * \see ClosestPointOnSegmentXZ
  142. */
  143. public static Vector3 ClosestPointOnSegment (Vector3 lineStart, Vector3 lineEnd, Vector3 point) {
  144. var dir = lineEnd - lineStart;
  145. float sqrMagn = dir.sqrMagnitude;
  146. if (sqrMagn <= 0.000001) return lineStart;
  147. float factor = Vector3.Dot(point - lineStart, dir) / sqrMagn;
  148. return lineStart + Mathf.Clamp01(factor)*dir;
  149. }
  150. /** Returns the closest point on the segment in the XZ plane.
  151. * The y coordinate of the result will be the same as the y coordinate of the \a point parameter.
  152. *
  153. * The segment is NOT treated as infinite.
  154. * \see ClosestPointOnSegment
  155. * \see ClosestPointOnLine
  156. */
  157. public static Vector3 ClosestPointOnSegmentXZ (Vector3 lineStart, Vector3 lineEnd, Vector3 point) {
  158. lineStart.y = point.y;
  159. lineEnd.y = point.y;
  160. Vector3 fullDirection = lineEnd-lineStart;
  161. Vector3 fullDirection2 = fullDirection;
  162. fullDirection2.y = 0;
  163. float magn = fullDirection2.magnitude;
  164. Vector3 lineDirection = magn > float.Epsilon ? fullDirection2/magn : Vector3.zero;
  165. float closestPoint = Vector3.Dot((point-lineStart), lineDirection);
  166. return lineStart+(Mathf.Clamp(closestPoint, 0.0f, fullDirection2.magnitude)*lineDirection);
  167. }
  168. /** Returns the approximate shortest squared distance between x,z and the segment p-q.
  169. * The segment is not considered infinite.
  170. * This function is not entirely exact, but it is about twice as fast as DistancePointSegment2.
  171. * \todo Is this actually approximate? It looks exact.
  172. */
  173. public static float SqrDistancePointSegmentApproximate (int x, int z, int px, int pz, int qx, int qz) {
  174. float pqx = (float)(qx - px);
  175. float pqz = (float)(qz - pz);
  176. float dx = (float)(x - px);
  177. float dz = (float)(z - pz);
  178. float d = pqx*pqx + pqz*pqz;
  179. float t = pqx*dx + pqz*dz;
  180. if (d > 0)
  181. t /= d;
  182. if (t < 0)
  183. t = 0;
  184. else if (t > 1)
  185. t = 1;
  186. dx = px + t*pqx - x;
  187. dz = pz + t*pqz - z;
  188. return dx*dx + dz*dz;
  189. }
  190. /** Returns the approximate shortest squared distance between x,z and the segment p-q.
  191. * The segment is not considered infinite.
  192. * This function is not entirely exact, but it is about twice as fast as DistancePointSegment2.
  193. * \todo Is this actually approximate? It looks exact.
  194. */
  195. public static float SqrDistancePointSegmentApproximate (Int3 a, Int3 b, Int3 p) {
  196. float pqx = (float)(b.x - a.x);
  197. float pqz = (float)(b.z - a.z);
  198. float dx = (float)(p.x - a.x);
  199. float dz = (float)(p.z - a.z);
  200. float d = pqx*pqx + pqz*pqz;
  201. float t = pqx*dx + pqz*dz;
  202. if (d > 0)
  203. t /= d;
  204. if (t < 0)
  205. t = 0;
  206. else if (t > 1)
  207. t = 1;
  208. dx = a.x + t*pqx - p.x;
  209. dz = a.z + t*pqz - p.z;
  210. return dx*dx + dz*dz;
  211. }
  212. /** Returns the squared distance between p and the segment a-b.
  213. * The line is not considered infinite.
  214. */
  215. public static float SqrDistancePointSegment (Vector3 a, Vector3 b, Vector3 p) {
  216. var nearest = ClosestPointOnSegment(a, b, p);
  217. return (nearest-p).sqrMagnitude;
  218. }
  219. /** 3D minimum distance between 2 segments.
  220. * Input: two 3D line segments S1 and S2
  221. * \returns the shortest squared distance between S1 and S2
  222. */
  223. public static float SqrDistanceSegmentSegment (Vector3 s1, Vector3 e1, Vector3 s2, Vector3 e2) {
  224. Vector3 u = e1 - s1;
  225. Vector3 v = e2 - s2;
  226. Vector3 w = s1 - s2;
  227. float a = Vector3.Dot(u, u); // always >= 0
  228. float b = Vector3.Dot(u, v);
  229. float c = Vector3.Dot(v, v); // always >= 0
  230. float d = Vector3.Dot(u, w);
  231. float e = Vector3.Dot(v, w);
  232. float D = a*c - b*b; // always >= 0
  233. float sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0
  234. float tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
  235. // compute the line parameters of the two closest points
  236. if (D < 0.000001f) { // the lines are almost parallel
  237. sN = 0.0f; // force using point P0 on segment S1
  238. sD = 1.0f; // to prevent possible division by 0.0 later
  239. tN = e;
  240. tD = c;
  241. } else { // get the closest points on the infinite lines
  242. sN = (b*e - c*d);
  243. tN = (a*e - b*d);
  244. if (sN < 0.0f) { // sc < 0 => the s=0 edge is visible
  245. sN = 0.0f;
  246. tN = e;
  247. tD = c;
  248. } else if (sN > sD) { // sc > 1 => the s=1 edge is visible
  249. sN = sD;
  250. tN = e + b;
  251. tD = c;
  252. }
  253. }
  254. if (tN < 0.0f) { // tc < 0 => the t=0 edge is visible
  255. tN = 0.0f;
  256. // recompute sc for this edge
  257. if (-d < 0.0f)
  258. sN = 0.0f;
  259. else if (-d > a)
  260. sN = sD;
  261. else {
  262. sN = -d;
  263. sD = a;
  264. }
  265. } else if (tN > tD) { // tc > 1 => the t=1 edge is visible
  266. tN = tD;
  267. // recompute sc for this edge
  268. if ((-d + b) < 0.0f)
  269. sN = 0;
  270. else if ((-d + b) > a)
  271. sN = sD;
  272. else {
  273. sN = (-d + b);
  274. sD = a;
  275. }
  276. }
  277. // finally do the division to get sc and tc
  278. sc = (Math.Abs(sN) < 0.000001f ? 0.0f : sN / sD);
  279. tc = (Math.Abs(tN) < 0.000001f ? 0.0f : tN / tD);
  280. // get the difference of the two closest points
  281. Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
  282. return dP.sqrMagnitude; // return the closest distance
  283. }
  284. /** Squared distance between two points in the XZ plane */
  285. public static float SqrDistanceXZ (Vector3 a, Vector3 b) {
  286. var delta = a-b;
  287. return delta.x*delta.x+delta.z*delta.z;
  288. }
  289. /** Signed area of a triangle in the XZ plane multiplied by 2.
  290. * This will be negative for clockwise triangles and positive for counter-clockwise ones
  291. */
  292. public static long SignedTriangleAreaTimes2XZ (Int3 a, Int3 b, Int3 c) {
  293. return (long)(b.x - a.x) * (long)(c.z - a.z) - (long)(c.x - a.x) * (long)(b.z - a.z);
  294. }
  295. /** Signed area of a triangle in the XZ plane multiplied by 2.
  296. * This will be negative for clockwise triangles and positive for counter-clockwise ones.
  297. */
  298. public static float SignedTriangleAreaTimes2XZ (Vector3 a, Vector3 b, Vector3 c) {
  299. return (b.x - a.x) * (c.z - a.z) - (c.x - a.x) * (b.z - a.z);
  300. }
  301. /** Returns if \a p lies on the right side of the line \a a - \a b.
  302. * Uses XZ space. Does not return true if the points are colinear.
  303. */
  304. public static bool RightXZ (Vector3 a, Vector3 b, Vector3 p) {
  305. return (b.x - a.x) * (p.z - a.z) - (p.x - a.x) * (b.z - a.z) < -float.Epsilon;
  306. }
  307. /** Returns if \a p lies on the right side of the line \a a - \a b.
  308. * Uses XZ space. Does not return true if the points are colinear.
  309. */
  310. public static bool RightXZ (Int3 a, Int3 b, Int3 p) {
  311. return (long)(b.x - a.x) * (long)(p.z - a.z) - (long)(p.x - a.x) * (long)(b.z - a.z) < 0;
  312. }
  313. /** Returns which side of the line \a a - \a b that \a p lies on.
  314. * Uses XZ space.
  315. */
  316. public static Side SideXZ (Int3 a, Int3 b, Int3 p) {
  317. var s = (long)(b.x - a.x) * (long)(p.z - a.z) - (long)(p.x - a.x) * (long)(b.z - a.z);
  318. return s > 0 ? Side.Left : (s < 0 ? Side.Right : Side.Colinear);
  319. }
  320. /** Returns if \a p lies on the right side of the line \a a - \a b.
  321. * Also returns true if the points are colinear.
  322. */
  323. public static bool RightOrColinear (Vector2 a, Vector2 b, Vector2 p) {
  324. return (b.x - a.x) * (p.y - a.y) - (p.x - a.x) * (b.y - a.y) <= 0;
  325. }
  326. /** Returns if \a p lies on the right side of the line \a a - \a b.
  327. * Also returns true if the points are colinear.
  328. */
  329. public static bool RightOrColinear (Int2 a, Int2 b, Int2 p) {
  330. return (long)(b.x - a.x) * (long)(p.y - a.y) - (long)(p.x - a.x) * (long)(b.y - a.y) <= 0;
  331. }
  332. /** Returns if \a p lies on the left side of the line \a a - \a b.
  333. * Uses XZ space. Also returns true if the points are colinear.
  334. */
  335. public static bool RightOrColinearXZ (Vector3 a, Vector3 b, Vector3 p) {
  336. return (b.x - a.x) * (p.z - a.z) - (p.x - a.x) * (b.z - a.z) <= 0;
  337. }
  338. /** Returns if \a p lies on the left side of the line \a a - \a b.
  339. * Uses XZ space. Also returns true if the points are colinear.
  340. */
  341. public static bool RightOrColinearXZ (Int3 a, Int3 b, Int3 p) {
  342. return (long)(b.x - a.x) * (long)(p.z - a.z) - (long)(p.x - a.x) * (long)(b.z - a.z) <= 0;
  343. }
  344. /** Returns if the points a in a clockwise order.
  345. * Will return true even if the points are colinear or very slightly counter-clockwise
  346. * (if the signed area of the triangle formed by the points has an area less than or equals to float.Epsilon) */
  347. public static bool IsClockwiseMarginXZ (Vector3 a, Vector3 b, Vector3 c) {
  348. return (b.x-a.x)*(c.z-a.z)-(c.x-a.x)*(b.z-a.z) <= float.Epsilon;
  349. }
  350. /** Returns if the points a in a clockwise order */
  351. public static bool IsClockwiseXZ (Vector3 a, Vector3 b, Vector3 c) {
  352. return (b.x-a.x)*(c.z-a.z)-(c.x-a.x)*(b.z-a.z) < 0;
  353. }
  354. /** Returns if the points a in a clockwise order */
  355. public static bool IsClockwiseXZ (Int3 a, Int3 b, Int3 c) {
  356. return RightXZ(a, b, c);
  357. }
  358. /** Returns true if the points a in a clockwise order or if they are colinear */
  359. public static bool IsClockwiseOrColinearXZ (Int3 a, Int3 b, Int3 c) {
  360. return RightOrColinearXZ(a, b, c);
  361. }
  362. /** Returns true if the points a in a clockwise order or if they are colinear */
  363. public static bool IsClockwiseOrColinear (Int2 a, Int2 b, Int2 c) {
  364. return RightOrColinear(a, b, c);
  365. }
  366. /** Returns if the points are colinear (lie on a straight line) */
  367. public static bool IsColinear (Vector3 a, Vector3 b, Vector3 c) {
  368. var lhs = b - a;
  369. var rhs = c - a;
  370. // Take the cross product of lhs and rhs
  371. // The magnitude of the cross product will be zero if the points a,b,c are colinear
  372. float x = lhs.y * rhs.z - lhs.z * rhs.y;
  373. float y = lhs.z * rhs.x - lhs.x * rhs.z;
  374. float z = lhs.x * rhs.y - lhs.y * rhs.x;
  375. float v = x*x + y*y + z*z;
  376. // Epsilon not chosen with much thought, just that float.Epsilon was a bit too small.
  377. return v <= 0.0000001f;
  378. }
  379. /** Returns if the points are colinear (lie on a straight line) */
  380. public static bool IsColinear (Vector2 a, Vector2 b, Vector2 c) {
  381. float v = (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
  382. // Epsilon not chosen with much thought, just that float.Epsilon was a bit too small.
  383. return v <= 0.0000001f && v >= -0.0000001f;
  384. }
  385. /** Returns if the points are colinear (lie on a straight line) */
  386. public static bool IsColinearXZ (Int3 a, Int3 b, Int3 c) {
  387. return (long)(b.x - a.x) * (long)(c.z - a.z) - (long)(c.x - a.x) * (long)(b.z - a.z) == 0;
  388. }
  389. /** Returns if the points are colinear (lie on a straight line) */
  390. public static bool IsColinearXZ (Vector3 a, Vector3 b, Vector3 c) {
  391. float v = (b.x-a.x)*(c.z-a.z)-(c.x-a.x)*(b.z-a.z);
  392. // Epsilon not chosen with much thought, just that float.Epsilon was a bit too small.
  393. return v <= 0.0000001f && v >= -0.0000001f;
  394. }
  395. /** Returns if the points are colinear (lie on a straight line) */
  396. public static bool IsColinearAlmostXZ (Int3 a, Int3 b, Int3 c) {
  397. long v = (long)(b.x - a.x) * (long)(c.z - a.z) - (long)(c.x - a.x) * (long)(b.z - a.z);
  398. return v > -1 && v < 1;
  399. }
  400. /** Returns if the line segment \a start2 - \a end2 intersects the line segment \a start1 - \a end1.
  401. * If only the endpoints coincide, the result is undefined (may be true or false).
  402. */
  403. public static bool SegmentsIntersect (Int2 start1, Int2 end1, Int2 start2, Int2 end2) {
  404. return RightOrColinear(start1, end1, start2) != RightOrColinear(start1, end1, end2) && RightOrColinear(start2, end2, start1) != RightOrColinear(start2, end2, end1);
  405. }
  406. /** Returns if the line segment \a start2 - \a end2 intersects the line segment \a start1 - \a end1.
  407. * If only the endpoints coincide, the result is undefined (may be true or false).
  408. *
  409. * \note XZ space
  410. */
  411. public static bool SegmentsIntersectXZ (Int3 start1, Int3 end1, Int3 start2, Int3 end2) {
  412. return RightOrColinearXZ(start1, end1, start2) != RightOrColinearXZ(start1, end1, end2) && RightOrColinearXZ(start2, end2, start1) != RightOrColinearXZ(start2, end2, end1);
  413. }
  414. /** Returns if the two line segments intersects. The lines are NOT treated as infinite (just for clarification)
  415. * \see IntersectionPoint
  416. */
  417. public static bool SegmentsIntersectXZ (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2) {
  418. Vector3 dir1 = end1-start1;
  419. Vector3 dir2 = end2-start2;
  420. float den = dir2.z*dir1.x - dir2.x * dir1.z;
  421. if (den == 0) {
  422. return false;
  423. }
  424. float nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  425. float nom2 = dir1.x*(start1.z-start2.z) - dir1.z * (start1.x - start2.x);
  426. float u = nom/den;
  427. float u2 = nom2/den;
  428. if (u < 0F || u > 1F || u2 < 0F || u2 > 1F) {
  429. return false;
  430. }
  431. return true;
  432. }
  433. /** Intersection point between two infinite lines.
  434. * Note that start points and directions are taken as parameters instead of start and end points.
  435. * Lines are treated as infinite. If the lines are parallel 'start1' will be returned.
  436. * Intersections are calculated on the XZ plane.
  437. *
  438. * \see LineIntersectionPointXZ
  439. */
  440. public static Vector3 LineDirIntersectionPointXZ (Vector3 start1, Vector3 dir1, Vector3 start2, Vector3 dir2) {
  441. float den = dir2.z*dir1.x - dir2.x * dir1.z;
  442. if (den == 0) {
  443. return start1;
  444. }
  445. float nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  446. float u = nom/den;
  447. return start1 + dir1*u;
  448. }
  449. /** Intersection point between two infinite lines.
  450. * Note that start points and directions are taken as parameters instead of start and end points.
  451. * Lines are treated as infinite. If the lines are parallel 'start1' will be returned.
  452. * Intersections are calculated on the XZ plane.
  453. *
  454. * \see LineIntersectionPointXZ
  455. */
  456. public static Vector3 LineDirIntersectionPointXZ (Vector3 start1, Vector3 dir1, Vector3 start2, Vector3 dir2, out bool intersects) {
  457. float den = dir2.z*dir1.x - dir2.x * dir1.z;
  458. if (den == 0) {
  459. intersects = false;
  460. return start1;
  461. }
  462. float nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  463. float u = nom/den;
  464. intersects = true;
  465. return start1 + dir1*u;
  466. }
  467. /** Returns if the ray (start1, end1) intersects the segment (start2, end2).
  468. * false is returned if the lines are parallel.
  469. * Only the XZ coordinates are used.
  470. * \todo Double check that this actually works
  471. */
  472. public static bool RaySegmentIntersectXZ (Int3 start1, Int3 end1, Int3 start2, Int3 end2) {
  473. Int3 dir1 = end1-start1;
  474. Int3 dir2 = end2-start2;
  475. long den = dir2.z*dir1.x - dir2.x * dir1.z;
  476. if (den == 0) {
  477. return false;
  478. }
  479. long nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  480. long nom2 = dir1.x*(start1.z-start2.z) - dir1.z * (start1.x - start2.x);
  481. //factor1 < 0
  482. // If both have the same sign, then nom/den < 0 and thus the segment cuts the ray before the ray starts
  483. if (!(nom < 0 ^ den < 0)) {
  484. return false;
  485. }
  486. //factor2 < 0
  487. if (!(nom2 < 0 ^ den < 0)) {
  488. return false;
  489. }
  490. if ((den >= 0 && nom2 > den) || (den < 0 && nom2 <= den)) {
  491. return false;
  492. }
  493. return true;
  494. }
  495. /** Returns the intersection factors for line 1 and line 2. The intersection factors is a distance along the line \a start - \a end where the other line intersects it.\n
  496. * \code intersectionPoint = start1 + factor1 * (end1-start1) \endcode
  497. * \code intersectionPoint2 = start2 + factor2 * (end2-start2) \endcode
  498. * Lines are treated as infinite.\n
  499. * false is returned if the lines are parallel and true if they are not.
  500. * Only the XZ coordinates are used.
  501. */
  502. public static bool LineIntersectionFactorXZ (Int3 start1, Int3 end1, Int3 start2, Int3 end2, out float factor1, out float factor2) {
  503. Int3 dir1 = end1-start1;
  504. Int3 dir2 = end2-start2;
  505. long den = dir2.z*dir1.x - dir2.x * dir1.z;
  506. if (den == 0) {
  507. factor1 = 0;
  508. factor2 = 0;
  509. return false;
  510. }
  511. long nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  512. long nom2 = dir1.x*(start1.z-start2.z) - dir1.z * (start1.x - start2.x);
  513. factor1 = (float)nom/den;
  514. factor2 = (float)nom2/den;
  515. return true;
  516. }
  517. /** Returns the intersection factors for line 1 and line 2. The intersection factors is a distance along the line \a start - \a end where the other line intersects it.\n
  518. * \code intersectionPoint = start1 + factor1 * (end1-start1) \endcode
  519. * \code intersectionPoint2 = start2 + factor2 * (end2-start2) \endcode
  520. * Lines are treated as infinite.\n
  521. * false is returned if the lines are parallel and true if they are not.
  522. * Only the XZ coordinates are used.
  523. */
  524. public static bool LineIntersectionFactorXZ (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2, out float factor1, out float factor2) {
  525. Vector3 dir1 = end1-start1;
  526. Vector3 dir2 = end2-start2;
  527. float den = dir2.z*dir1.x - dir2.x * dir1.z;
  528. if (den <= 0.00001f && den >= -0.00001f) {
  529. factor1 = 0;
  530. factor2 = 0;
  531. return false;
  532. }
  533. float nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  534. float nom2 = dir1.x*(start1.z-start2.z) - dir1.z * (start1.x - start2.x);
  535. float u = nom/den;
  536. float u2 = nom2/den;
  537. factor1 = u;
  538. factor2 = u2;
  539. return true;
  540. }
  541. /** Returns the intersection factor for line 1 with ray 2.
  542. * The intersection factors is a factor distance along the line \a start - \a end where the other line intersects it.\n
  543. * \code intersectionPoint = start1 + factor * (end1-start1) \endcode
  544. * Lines are treated as infinite.\n
  545. *
  546. * The second "line" is treated as a ray, meaning only matches on start2 or forwards towards end2 (and beyond) will be returned
  547. * If the point lies on the wrong side of the ray start, Nan will be returned.
  548. *
  549. * NaN is returned if the lines are parallel. */
  550. public static float LineRayIntersectionFactorXZ (Int3 start1, Int3 end1, Int3 start2, Int3 end2) {
  551. Int3 dir1 = end1-start1;
  552. Int3 dir2 = end2-start2;
  553. int den = dir2.z*dir1.x - dir2.x * dir1.z;
  554. if (den == 0) {
  555. return float.NaN;
  556. }
  557. int nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  558. int nom2 = dir1.x*(start1.z-start2.z) - dir1.z * (start1.x - start2.x);
  559. if ((float)nom2/den < 0) {
  560. return float.NaN;
  561. }
  562. return (float)nom/den;
  563. }
  564. /** Returns the intersection factor for line 1 with line 2.
  565. * The intersection factor is a distance along the line \a start1 - \a end1 where the line \a start2 - \a end2 intersects it.\n
  566. * \code intersectionPoint = start1 + intersectionFactor * (end1-start1) \endcode.
  567. * Lines are treated as infinite.\n
  568. * -1 is returned if the lines are parallel (note that this is a valid return value if they are not parallel too) */
  569. public static float LineIntersectionFactorXZ (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2) {
  570. Vector3 dir1 = end1-start1;
  571. Vector3 dir2 = end2-start2;
  572. float den = dir2.z*dir1.x - dir2.x * dir1.z;
  573. if (den == 0) {
  574. return -1;
  575. }
  576. float nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  577. float u = nom/den;
  578. return u;
  579. }
  580. /** Returns the intersection point between the two lines. Lines are treated as infinite. \a start1 is returned if the lines are parallel */
  581. public static Vector3 LineIntersectionPointXZ (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2) {
  582. bool s;
  583. return LineIntersectionPointXZ(start1, end1, start2, end2, out s);
  584. }
  585. /** Returns the intersection point between the two lines. Lines are treated as infinite. \a start1 is returned if the lines are parallel */
  586. public static Vector3 LineIntersectionPointXZ (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2, out bool intersects) {
  587. Vector3 dir1 = end1-start1;
  588. Vector3 dir2 = end2-start2;
  589. float den = dir2.z*dir1.x - dir2.x * dir1.z;
  590. if (den == 0) {
  591. intersects = false;
  592. return start1;
  593. }
  594. float nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  595. float u = nom/den;
  596. intersects = true;
  597. return start1 + dir1*u;
  598. }
  599. /** Returns the intersection point between the two lines. Lines are treated as infinite. \a start1 is returned if the lines are parallel */
  600. public static Vector2 LineIntersectionPoint (Vector2 start1, Vector2 end1, Vector2 start2, Vector2 end2) {
  601. bool s;
  602. return LineIntersectionPoint(start1, end1, start2, end2, out s);
  603. }
  604. /** Returns the intersection point between the two lines. Lines are treated as infinite. \a start1 is returned if the lines are parallel */
  605. public static Vector2 LineIntersectionPoint (Vector2 start1, Vector2 end1, Vector2 start2, Vector2 end2, out bool intersects) {
  606. Vector2 dir1 = end1-start1;
  607. Vector2 dir2 = end2-start2;
  608. float den = dir2.y*dir1.x - dir2.x * dir1.y;
  609. if (den == 0) {
  610. intersects = false;
  611. return start1;
  612. }
  613. float nom = dir2.x*(start1.y-start2.y)- dir2.y*(start1.x-start2.x);
  614. float u = nom/den;
  615. intersects = true;
  616. return start1 + dir1*u;
  617. }
  618. /** Returns the intersection point between the two line segments in XZ space.
  619. * Lines are NOT treated as infinite. \a start1 is returned if the line segments do not intersect
  620. * The point will be returned along the line [start1, end1] (this matters only for the y coordinate).
  621. */
  622. public static Vector3 SegmentIntersectionPointXZ (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2, out bool intersects) {
  623. Vector3 dir1 = end1-start1;
  624. Vector3 dir2 = end2-start2;
  625. float den = dir2.z * dir1.x - dir2.x * dir1.z;
  626. if (den == 0) {
  627. intersects = false;
  628. return start1;
  629. }
  630. float nom = dir2.x*(start1.z-start2.z)- dir2.z*(start1.x-start2.x);
  631. float nom2 = dir1.x*(start1.z-start2.z) - dir1.z*(start1.x-start2.x);
  632. float u = nom/den;
  633. float u2 = nom2/den;
  634. if (u < 0F || u > 1F || u2 < 0F || u2 > 1F) {
  635. intersects = false;
  636. return start1;
  637. }
  638. intersects = true;
  639. return start1 + dir1*u;
  640. }
  641. /** Intersection of a line and a circle.
  642. * Returns the greatest t such that segmentStart+t*(segmentEnd-segmentStart) lies on the circle.
  643. *
  644. * In case the line does not intersect with the circle, the closest point on the line
  645. * to the circle will be returned.
  646. *
  647. * \note Works for line and sphere in 3D space as well.
  648. *
  649. * \see http://mathworld.wolfram.com/Circle-LineIntersection.html
  650. * \see https://en.wikipedia.org/wiki/Intersection_(Euclidean_geometry)#A_line_and_a_circle
  651. */
  652. public static float LineCircleIntersectionFactor (Vector3 circleCenter, Vector3 linePoint1, Vector3 linePoint2, float radius) {
  653. float segmentLength;
  654. var normalizedDirection = Normalize(linePoint2 - linePoint1, out segmentLength);
  655. var dirToStart = linePoint1 - circleCenter;
  656. var dot = Vector3.Dot(dirToStart, normalizedDirection);
  657. var discriminant = dot * dot - (dirToStart.sqrMagnitude - radius*radius);
  658. if (discriminant < 0) {
  659. // No intersection, pick closest point on segment
  660. discriminant = 0;
  661. }
  662. var t = -dot + Mathf.Sqrt(discriminant);
  663. // Note: the default value of 1 is important for the PathInterpolator.MoveToCircleIntersection2D
  664. // method to work properly. Maybe find some better abstraction where this default value is more obvious.
  665. return segmentLength > 0.00001f ? t / segmentLength : 1f;
  666. }
  667. /** Normalize vector and also return the magnitude.
  668. * This is more efficient than calculating the magnitude and normalizing separately
  669. */
  670. public static Vector3 Normalize (Vector3 v, out float magnitude) {
  671. magnitude = v.magnitude;
  672. // This is the same constant that Unity uses
  673. if (magnitude > 1E-05f) {
  674. return v / magnitude;
  675. } else {
  676. return Vector3.zero;
  677. }
  678. }
  679. /** Normalize vector and also return the magnitude.
  680. * This is more efficient than calculating the magnitude and normalizing separately
  681. */
  682. public static Vector2 Normalize (Vector2 v, out float magnitude) {
  683. magnitude = v.magnitude;
  684. // This is the same constant that Unity uses
  685. if (magnitude > 1E-05f) {
  686. return v / magnitude;
  687. } else {
  688. return Vector2.zero;
  689. }
  690. }
  691. /* Clamp magnitude along the X and Z axes.
  692. * The y component will not be changed.
  693. */
  694. public static Vector3 ClampMagnitudeXZ (Vector3 v, float maxMagnitude) {
  695. float squaredMagnitudeXZ = v.x*v.x + v.z*v.z;
  696. if (squaredMagnitudeXZ > maxMagnitude*maxMagnitude && maxMagnitude > 0) {
  697. var factor = maxMagnitude / Mathf.Sqrt(squaredMagnitudeXZ);
  698. v.x *= factor;
  699. v.z *= factor;
  700. }
  701. return v;
  702. }
  703. /* Magnitude in the XZ plane */
  704. public static float MagnitudeXZ (Vector3 v) {
  705. return Mathf.Sqrt(v.x*v.x + v.z*v.z);
  706. }
  707. }
  708. /** Utility functions for working with numbers and strings.
  709. * \ingroup utils
  710. * \see Polygon
  711. * \see VectorMath
  712. */
  713. public static class AstarMath {
  714. /** Returns the closest point on the line. The line is treated as infinite.
  715. * \see NearestPointStrict
  716. */
  717. [System.Obsolete("Use VectorMath.ClosestPointOnLine instead")]
  718. public static Vector3 NearestPoint (Vector3 lineStart, Vector3 lineEnd, Vector3 point) {
  719. return VectorMath.ClosestPointOnLine(lineStart, lineEnd, point);
  720. }
  721. [System.Obsolete("Use VectorMath.ClosestPointOnLineFactor instead")]
  722. public static float NearestPointFactor (Vector3 lineStart, Vector3 lineEnd, Vector3 point) {
  723. return VectorMath.ClosestPointOnLineFactor(lineStart, lineEnd, point);
  724. }
  725. /** Factor of the nearest point on the segment.
  726. * Returned value is in the range [0,1] if the point lies on the segment otherwise it just lies on the line.
  727. * The closest point can be got by (end-start)*factor + start;
  728. */
  729. [System.Obsolete("Use VectorMath.ClosestPointOnLineFactor instead")]
  730. public static float NearestPointFactor (Int3 lineStart, Int3 lineEnd, Int3 point) {
  731. return VectorMath.ClosestPointOnLineFactor(lineStart, lineEnd, point);
  732. }
  733. /** Factor of the nearest point on the segment.
  734. * Returned value is in the range [0,1] if the point lies on the segment otherwise it just lies on the line.
  735. * The closest point can be got by (end-start)*factor + start;
  736. */
  737. [System.Obsolete("Use VectorMath.ClosestPointOnLineFactor instead")]
  738. public static float NearestPointFactor (Int2 lineStart, Int2 lineEnd, Int2 point) {
  739. return VectorMath.ClosestPointOnLineFactor(lineStart, lineEnd, point);
  740. }
  741. /** Returns the closest point on the line segment. The line is NOT treated as infinite.
  742. * \see NearestPoint
  743. */
  744. [System.Obsolete("Use VectorMath.ClosestPointOnSegment instead")]
  745. public static Vector3 NearestPointStrict (Vector3 lineStart, Vector3 lineEnd, Vector3 point) {
  746. return VectorMath.ClosestPointOnSegment(lineStart, lineEnd, point);
  747. }
  748. /** Returns the closest point on the line segment on the XZ plane. The line is NOT treated as infinite.
  749. * \see NearestPoint
  750. */
  751. [System.Obsolete("Use VectorMath.ClosestPointOnSegmentXZ instead")]
  752. public static Vector3 NearestPointStrictXZ (Vector3 lineStart, Vector3 lineEnd, Vector3 point) {
  753. return VectorMath.ClosestPointOnSegmentXZ(lineStart, lineEnd, point);
  754. }
  755. /** Returns the approximate shortest squared distance between x,z and the line p-q.
  756. * The line is considered infinite.
  757. * This function is not entirely exact, but it is about twice as fast as DistancePointSegment2.
  758. */
  759. [System.Obsolete("Use VectorMath.SqrDistancePointSegmentApproximate instead")]
  760. public static float DistancePointSegment (int x, int z, int px, int pz, int qx, int qz) {
  761. return VectorMath.SqrDistancePointSegmentApproximate(x, z, px, pz, qx, qz);
  762. }
  763. /** Returns the approximate shortest squared distance between x,z and the line p-q.
  764. * The line is considered infinite.
  765. * This function is not entirely exact, but it is about twice as fast as DistancePointSegment2.
  766. */
  767. [System.Obsolete("Use VectorMath.SqrDistancePointSegmentApproximate instead")]
  768. public static float DistancePointSegment (Int3 a, Int3 b, Int3 p) {
  769. return VectorMath.SqrDistancePointSegmentApproximate(a, b, p);
  770. }
  771. /** Returns the squared distance between c and the line a-b. The line is not considered infinite. */
  772. [System.Obsolete("Use VectorMath.SqrDistancePointSegment instead")]
  773. public static float DistancePointSegmentStrict (Vector3 a, Vector3 b, Vector3 p) {
  774. return VectorMath.SqrDistancePointSegment(a, b, p);
  775. }
  776. /** Returns a point on a cubic bezier curve. \a t is clamped between 0 and 1 */
  777. [System.Obsolete("Use AstarSplines.CubicBezier instead")]
  778. public static Vector3 CubicBezier (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
  779. return AstarSplines.CubicBezier(p0, p1, p2, p3, t);
  780. }
  781. /** Maps a value between startMin and startMax to be between 0 and 1 */
  782. [System.Obsolete("Use Mathf.InverseLerp instead")]
  783. public static float MapTo (float startMin, float startMax, float value) {
  784. return Mathf.InverseLerp(startMin, startMax, value);
  785. }
  786. /** Maps a value between startMin and startMax to be between targetMin and targetMax */
  787. public static float MapTo (float startMin, float startMax, float targetMin, float targetMax, float value) {
  788. return Mathf.Lerp(targetMin, targetMax, Mathf.InverseLerp(startMin, startMax, value));
  789. }
  790. /** Returns a nicely formatted string for the number of bytes (KiB, MiB, GiB etc). Uses decimal names (KB, Mb - 1000) but calculates using binary values (KiB, MiB - 1024) */
  791. public static string FormatBytesBinary (int bytes) {
  792. double sign = bytes >= 0 ? 1D : -1D;
  793. bytes = Mathf.Abs(bytes);
  794. if (bytes < 1024) {
  795. return (bytes*sign)+" bytes";
  796. } else if (bytes < 1024*1024) {
  797. return ((bytes/1024D)*sign).ToString("0.0") + " KiB";
  798. } else if (bytes < 1024*1024*1024) {
  799. return ((bytes/(1024D*1024D))*sign).ToString("0.0") +" MiB";
  800. }
  801. return ((bytes/(1024D*1024D*1024D))*sign).ToString("0.0") +" GiB";
  802. }
  803. }
  804. /** Utility functions for working with polygons, lines, and other vector math.
  805. * All functions which accepts Vector3s but work in 2D space uses the XZ space if nothing else is said.
  806. *
  807. * \version A lot of functions in this class have been moved to the VectorMath class
  808. * the names have changed slightly and everything now consistently assumes a left handed
  809. * coordinate system now instead of sometimes using a left handed one and sometimes
  810. * using a right handed one. This is why the 'Left' methods redirect to methods
  811. * named 'Right'. The functionality is exactly the same.
  812. *
  813. * \ingroup utils
  814. */
  815. public static class Polygon {
  816. /** Returns if the triangle \a ABC contains the point \a p in XZ space.
  817. * The triangle vertices are assumed to be laid out in clockwise order.
  818. */
  819. public static bool ContainsPointXZ (Vector3 a, Vector3 b, Vector3 c, Vector3 p) {
  820. return VectorMath.IsClockwiseMarginXZ(a, b, p) && VectorMath.IsClockwiseMarginXZ(b, c, p) && VectorMath.IsClockwiseMarginXZ(c, a, p);
  821. }
  822. /** Returns if the triangle \a ABC contains the point \a p.
  823. * The triangle vertices are assumed to be laid out in clockwise order.
  824. */
  825. public static bool ContainsPointXZ (Int3 a, Int3 b, Int3 c, Int3 p) {
  826. return VectorMath.IsClockwiseOrColinearXZ(a, b, p) && VectorMath.IsClockwiseOrColinearXZ(b, c, p) && VectorMath.IsClockwiseOrColinearXZ(c, a, p);
  827. }
  828. /** Returns if the triangle \a ABC contains the point \a p.
  829. * The triangle vertices are assumed to be laid out in clockwise order.
  830. */
  831. public static bool ContainsPoint (Int2 a, Int2 b, Int2 c, Int2 p) {
  832. return VectorMath.IsClockwiseOrColinear(a, b, p) && VectorMath.IsClockwiseOrColinear(b, c, p) && VectorMath.IsClockwiseOrColinear(c, a, p);
  833. }
  834. /** Checks if \a p is inside the polygon.
  835. * \author http://unifycommunity.com/wiki/index.php?title=PolyContainsPoint (Eric5h5)
  836. */
  837. public static bool ContainsPoint (Vector2[] polyPoints, Vector2 p) {
  838. int j = polyPoints.Length-1;
  839. bool inside = false;
  840. for (int i = 0; i < polyPoints.Length; j = i++) {
  841. if (((polyPoints[i].y <= p.y && p.y < polyPoints[j].y) || (polyPoints[j].y <= p.y && p.y < polyPoints[i].y)) &&
  842. (p.x < (polyPoints[j].x - polyPoints[i].x) * (p.y - polyPoints[i].y) / (polyPoints[j].y - polyPoints[i].y) + polyPoints[i].x))
  843. inside = !inside;
  844. }
  845. return inside;
  846. }
  847. /** Checks if \a p is inside the polygon (XZ space).
  848. * \author http://unifycommunity.com/wiki/index.php?title=PolyContainsPoint (Eric5h5)
  849. */
  850. public static bool ContainsPointXZ (Vector3[] polyPoints, Vector3 p) {
  851. int j = polyPoints.Length-1;
  852. bool inside = false;
  853. for (int i = 0; i < polyPoints.Length; j = i++) {
  854. if (((polyPoints[i].z <= p.z && p.z < polyPoints[j].z) || (polyPoints[j].z <= p.z && p.z < polyPoints[i].z)) &&
  855. (p.x < (polyPoints[j].x - polyPoints[i].x) * (p.z - polyPoints[i].z) / (polyPoints[j].z - polyPoints[i].z) + polyPoints[i].x))
  856. inside = !inside;
  857. }
  858. return inside;
  859. }
  860. /** Sample Y coordinate of the triangle (p1, p2, p3) at the point p in XZ space.
  861. * The y coordinate of \a p is ignored.
  862. *
  863. * \returns The interpolated y coordinate unless the triangle is degenerate in which case a DivisionByZeroException will be thrown
  864. *
  865. * \see https://en.wikipedia.org/wiki/Barycentric_coordinate_system
  866. */
  867. public static int SampleYCoordinateInTriangle (Int3 p1, Int3 p2, Int3 p3, Int3 p) {
  868. double det = ((double)(p2.z - p3.z)) * (p1.x - p3.x) + ((double)(p3.x - p2.x)) * (p1.z - p3.z);
  869. double lambda1 = ((((double)(p2.z - p3.z)) * (p.x - p3.x) + ((double)(p3.x - p2.x)) * (p.z - p3.z)) / det);
  870. double lambda2 = ((((double)(p3.z - p1.z)) * (p.x - p3.x) + ((double)(p1.x - p3.x)) * (p.z - p3.z)) / det);
  871. return (int)Math.Round(lambda1 * p1.y + lambda2 * p2.y + (1 - lambda1 - lambda2) * p3.y);
  872. }
  873. /** Returns if \a p lies on the left side of the line \a a - \a b. Uses XZ space.
  874. * Does not return true if the points are colinear.
  875. * \deprecated Use VectorMath.RightXZ instead. Note that it now uses a left handed coordinate system (same as Unity)
  876. */
  877. [System.Obsolete("Use VectorMath.RightXZ instead. Note that it now uses a left handed coordinate system (same as Unity)")]
  878. public static bool LeftNotColinear (Vector3 a, Vector3 b, Vector3 p) {
  879. return VectorMath.RightXZ(a, b, p);
  880. }
  881. /** Returns if \a p lies on the left side of the line \a a - \a b. Uses XZ space. Also returns true if the points are colinear
  882. * \deprecated Use VectorMath.RightOrColinearXZ instead. Note that it now uses a left handed coordinate system (same as Unity)
  883. */
  884. [System.Obsolete("Use VectorMath.RightOrColinearXZ instead. Note that it now uses a left handed coordinate system (same as Unity)")]
  885. public static bool Left (Vector3 a, Vector3 b, Vector3 p) {
  886. return VectorMath.RightOrColinearXZ(a, b, p);
  887. }
  888. /** Returns if \a p lies on the left side of the line \a a - \a b. Also returns true if the points are colinear
  889. * \deprecated Use VectorMath.RightOrColinear instead. Note that it now uses a left handed coordinate system (same as Unity)
  890. */
  891. [System.Obsolete("Use VectorMath.RightOrColinear instead. Note that it now uses a left handed coordinate system (same as Unity)")]
  892. public static bool Left (Vector2 a, Vector2 b, Vector2 p) {
  893. return VectorMath.RightOrColinear(a, b, p);
  894. }
  895. /** Returns if \a p lies on the left side of the line \a a - \a b. Uses XZ space. Also returns true if the points are colinear
  896. * \deprecated Use VectorMath.RightOrColinearXZ instead. Note that it now uses a left handed coordinate system (same as Unity)
  897. */
  898. [System.Obsolete("Use VectorMath.RightOrColinearXZ instead. Note that it now uses a left handed coordinate system (same as Unity)")]
  899. public static bool Left (Int3 a, Int3 b, Int3 p) {
  900. return VectorMath.RightOrColinearXZ(a, b, p);
  901. }
  902. /** Returns if \a p lies on the left side of the line \a a - \a b. Uses XZ space.
  903. * \deprecated Use VectorMath.RightXZ instead. Note that it now uses a left handed coordinate system (same as Unity)
  904. */
  905. [System.Obsolete("Use VectorMath.RightXZ instead. Note that it now uses a left handed coordinate system (same as Unity)")]
  906. public static bool LeftNotColinear (Int3 a, Int3 b, Int3 p) {
  907. return VectorMath.RightXZ(a, b, p);
  908. }
  909. /** Returns if \a p lies on the left side of the line \a a - \a b. Also returns true if the points are colinear
  910. * \deprecated Use VectorMath.RightOrColinear instead. Note that it now uses a left handed coordinate system (same as Unity)
  911. */
  912. [System.Obsolete("Use VectorMath.RightOrColinear instead. Note that it now uses a left handed coordinate system (same as Unity)")]
  913. public static bool Left (Int2 a, Int2 b, Int2 p) {
  914. return VectorMath.RightOrColinear(a, b, p);
  915. }
  916. /** Returns if the points a in a clockwise order.
  917. * Will return true even if the points are colinear or very slightly counter-clockwise
  918. * (if the signed area of the triangle formed by the points has an area less than or equals to float.Epsilon)
  919. * \deprecated Use VectorMath.IsClockwiseMarginXZ instead
  920. */
  921. [System.Obsolete("Use VectorMath.IsClockwiseMarginXZ instead")]
  922. public static bool IsClockwiseMargin (Vector3 a, Vector3 b, Vector3 c) {
  923. return VectorMath.IsClockwiseMarginXZ(a, b, c);
  924. }
  925. /** Returns if the points a in a clockwise order
  926. * \deprecated Use VectorMath.IsClockwiseXZ instead
  927. */
  928. [System.Obsolete("Use VectorMath.IsClockwiseXZ instead")]
  929. public static bool IsClockwise (Vector3 a, Vector3 b, Vector3 c) {
  930. return VectorMath.IsClockwiseXZ(a, b, c);
  931. }
  932. /** Returns if the points a in a clockwise order
  933. * \deprecated Use VectorMath.IsClockwiseXZ instead
  934. */
  935. [System.Obsolete("Use VectorMath.IsClockwiseXZ instead")]
  936. public static bool IsClockwise (Int3 a, Int3 b, Int3 c) {
  937. return VectorMath.IsClockwiseXZ(a, b, c);
  938. }
  939. /** Returns true if the points a in a clockwise order or if they are colinear
  940. * \deprecated Use VectorMath.IsClockwiseOrColinearXZ instead
  941. */
  942. [System.Obsolete("Use VectorMath.IsClockwiseOrColinearXZ instead")]
  943. public static bool IsClockwiseMargin (Int3 a, Int3 b, Int3 c) {
  944. return VectorMath.IsClockwiseOrColinearXZ(a, b, c);
  945. }
  946. /** Returns true if the points a in a clockwise order or if they are colinear
  947. * \deprecated Use VectorMath.IsClockwiseOrColinear instead
  948. */
  949. [System.Obsolete("Use VectorMath.IsClockwiseOrColinear instead")]
  950. public static bool IsClockwiseMargin (Int2 a, Int2 b, Int2 c) {
  951. return VectorMath.IsClockwiseOrColinear(a, b, c);
  952. }
  953. /** Returns if the points are colinear (lie on a straight line)
  954. * \deprecated Use VectorMath.IsColinearXZ instead
  955. */
  956. [System.Obsolete("Use VectorMath.IsColinearXZ instead")]
  957. public static bool IsColinear (Int3 a, Int3 b, Int3 c) {
  958. return VectorMath.IsColinearXZ(a, b, c);
  959. }
  960. /** Returns if the points are colinear (lie on a straight line)
  961. * \deprecated Use VectorMath.IsColinearAlmostXZ instead
  962. */
  963. [System.Obsolete("Use VectorMath.IsColinearAlmostXZ instead")]
  964. public static bool IsColinearAlmost (Int3 a, Int3 b, Int3 c) {
  965. return VectorMath.IsColinearAlmostXZ(a, b, c);
  966. }
  967. /** Returns if the points are colinear (lie on a straight line)
  968. * \deprecated Use VectorMath.IsColinearXZ instead
  969. */
  970. [System.Obsolete("Use VectorMath.IsColinearXZ instead")]
  971. public static bool IsColinear (Vector3 a, Vector3 b, Vector3 c) {
  972. return VectorMath.IsColinearXZ(a, b, c);
  973. }
  974. /** Returns if the line segment \a a2 - \a b2 intersects the infinite line \a a - \a b. a-b is infinite, a2-b2 is not infinite */
  975. [System.Obsolete("Marked for removal since it is not used by any part of the A* Pathfinding Project")]
  976. public static bool IntersectsUnclamped (Vector3 a, Vector3 b, Vector3 a2, Vector3 b2) {
  977. return VectorMath.RightOrColinearXZ(a, b, a2) != VectorMath.RightOrColinearXZ(a, b, b2);
  978. }
  979. /** Returns if the line segment \a a2 - \a b2 intersects the line segment \a a - \a b.
  980. * If only the endpoints coincide, the result is undefined (may be true or false).
  981. *
  982. * \deprecated Use VectorMath.SegmentsIntersect instead */
  983. [System.Obsolete("Use VectorMath.SegmentsIntersect instead")]
  984. public static bool Intersects (Int2 start1, Int2 end1, Int2 start2, Int2 end2) {
  985. return VectorMath.SegmentsIntersect(start1, end1, start2, end2);
  986. }
  987. /** Returns if the line segment \a a2 - \a b2 intersects the line segment \a a - \a b.
  988. * If only the endpoints coincide, the result is undefined (may be true or false).
  989. *
  990. * \note XZ space
  991. *
  992. * \deprecated Use VectorMath.SegmentsIntersectXZ instead */
  993. [System.Obsolete("Use VectorMath.SegmentsIntersectXZ instead")]
  994. public static bool Intersects (Int3 start1, Int3 end1, Int3 start2, Int3 end2) {
  995. return VectorMath.SegmentsIntersectXZ(start1, end1, start2, end2);
  996. }
  997. /** Returns if the two line segments intersects. The lines are NOT treated as infinite (just for clarification)
  998. * \see IntersectionPoint
  999. *
  1000. * \deprecated Use VectorMath.SegmentsIntersectXZ instead */
  1001. [System.Obsolete("Use VectorMath.SegmentsIntersectXZ instead")]
  1002. public static bool Intersects (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2) {
  1003. return VectorMath.SegmentsIntersectXZ(start1, end1, start2, end2);
  1004. }
  1005. /** Intersection point between two infinite lines.
  1006. * Lines are treated as infinite. If the lines are parallel 'start1' will be returned. Intersections are calculated on the XZ plane.
  1007. *
  1008. * \deprecated Use VectorMath.LineDirIntersectionPointXZ instead */
  1009. [System.Obsolete("Use VectorMath.LineDirIntersectionPointXZ instead")]
  1010. public static Vector3 IntersectionPointOptimized (Vector3 start1, Vector3 dir1, Vector3 start2, Vector3 dir2) {
  1011. return VectorMath.LineDirIntersectionPointXZ(start1, dir1, start2, dir2);
  1012. }
  1013. /** Intersection point between two infinite lines.
  1014. * Lines are treated as infinite. If the lines are parallel 'start1' will be returned. Intersections are calculated on the XZ plane.
  1015. *
  1016. * \deprecated Use VectorMath.LineDirIntersectionPointXZ instead */
  1017. [System.Obsolete("Use VectorMath.LineDirIntersectionPointXZ instead")]
  1018. public static Vector3 IntersectionPointOptimized (Vector3 start1, Vector3 dir1, Vector3 start2, Vector3 dir2, out bool intersects) {
  1019. return VectorMath.LineDirIntersectionPointXZ(start1, dir1, start2, dir2, out intersects);
  1020. }
  1021. /** Returns if the ray (start1, end1) intersects the segment (start2, end2).
  1022. * false is returned if the lines are parallel.
  1023. * Only the XZ coordinates are used.
  1024. * \todo Double check that this actually works
  1025. *
  1026. * \deprecated Use VectorMath.RaySegmentIntersectXZ instead */
  1027. [System.Obsolete("Use VectorMath.RaySegmentIntersectXZ instead")]
  1028. public static bool IntersectionFactorRaySegment (Int3 start1, Int3 end1, Int3 start2, Int3 end2) {
  1029. return VectorMath.RaySegmentIntersectXZ(start1, end1, start2, end2);
  1030. }
  1031. /** Returns the intersection factors for line 1 and line 2. The intersection factors is a distance along the line \a start - \a end where the other line intersects it.\n
  1032. * \code intersectionPoint = start1 + factor1 * (end1-start1) \endcode
  1033. * \code intersectionPoint2 = start2 + factor2 * (end2-start2) \endcode
  1034. * Lines are treated as infinite.\n
  1035. * false is returned if the lines are parallel and true if they are not.
  1036. * Only the XZ coordinates are used.
  1037. *
  1038. * \deprecated Use VectorMath.LineIntersectionFactorXZ instead */
  1039. [System.Obsolete("Use VectorMath.LineIntersectionFactorXZ instead")]
  1040. public static bool IntersectionFactor (Int3 start1, Int3 end1, Int3 start2, Int3 end2, out float factor1, out float factor2) {
  1041. return VectorMath.LineIntersectionFactorXZ(start1, end1, start2, end2, out factor1, out factor2);
  1042. }
  1043. /** Returns the intersection factors for line 1 and line 2. The intersection factors is a distance along the line \a start - \a end where the other line intersects it.\n
  1044. * \code intersectionPoint = start1 + factor1 * (end1-start1) \endcode
  1045. * \code intersectionPoint2 = start2 + factor2 * (end2-start2) \endcode
  1046. * Lines are treated as infinite.\n
  1047. * false is returned if the lines are parallel and true if they are not.
  1048. * Only the XZ coordinates are used.
  1049. *
  1050. * \deprecated Use VectorMath.LineIntersectionFactorXZ instead */
  1051. [System.Obsolete("Use VectorMath.LineIntersectionFactorXZ instead")]
  1052. public static bool IntersectionFactor (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2, out float factor1, out float factor2) {
  1053. return VectorMath.LineIntersectionFactorXZ(start1, end1, start2, end2, out factor1, out factor2);
  1054. }
  1055. /** Returns the intersection factor for line 1 with ray 2.
  1056. * The intersection factors is a factor distance along the line \a start - \a end where the other line intersects it.\n
  1057. * \code intersectionPoint = start1 + factor * (end1-start1) \endcode
  1058. * Lines are treated as infinite.\n
  1059. *
  1060. * The second "line" is treated as a ray, meaning only matches on start2 or forwards towards end2 (and beyond) will be returned
  1061. * If the point lies on the wrong side of the ray start, Nan will be returned.
  1062. *
  1063. * NaN is returned if the lines are parallel. *
  1064. * \deprecated Use VectorMath.LineRayIntersectionFactorXZ instead */
  1065. [System.Obsolete("Use VectorMath.LineRayIntersectionFactorXZ instead")]
  1066. public static float IntersectionFactorRay (Int3 start1, Int3 end1, Int3 start2, Int3 end2) {
  1067. return VectorMath.LineRayIntersectionFactorXZ(start1, end1, start2, end2);
  1068. }
  1069. /** Returns the intersection factor for line 1 with line 2.
  1070. * The intersection factor is a distance along the line \a start1 - \a end1 where the line \a start2 - \a end2 intersects it.\n
  1071. * \code intersectionPoint = start1 + intersectionFactor * (end1-start1) \endcode.
  1072. * Lines are treated as infinite.\n
  1073. * -1 is returned if the lines are parallel (note that this is a valid return value if they are not parallel too) *
  1074. * \deprecated Use VectorMath.LineIntersectionFactorXZ instead */
  1075. [System.Obsolete("Use VectorMath.LineIntersectionFactorXZ instead")]
  1076. public static float IntersectionFactor (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2) {
  1077. return VectorMath.LineIntersectionFactorXZ(start1, end1, start2, end2);
  1078. }
  1079. /** Returns the intersection point between the two lines. Lines are treated as infinite. \a start1 is returned if the lines are parallel
  1080. * \deprecated Use VectorMath.LineIntersectionPointXZ instead */
  1081. [System.Obsolete("Use VectorMath.LineIntersectionPointXZ instead")]
  1082. public static Vector3 IntersectionPoint (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2) {
  1083. return VectorMath.LineIntersectionPointXZ(start1, end1, start2, end2);
  1084. }
  1085. /** Returns the intersection point between the two lines. Lines are treated as infinite. \a start1 is returned if the lines are parallel
  1086. * \deprecated Use VectorMath.LineIntersectionPointXZ instead */
  1087. [System.Obsolete("Use VectorMath.LineIntersectionPointXZ instead")]
  1088. public static Vector3 IntersectionPoint (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2, out bool intersects) {
  1089. return VectorMath.LineIntersectionPointXZ(start1, end1, start2, end2, out intersects);
  1090. }
  1091. /** Returns the intersection point between the two lines. Lines are treated as infinite. \a start1 is returned if the lines are parallel
  1092. * \deprecated Use VectorMath.LineIntersectionPoint instead */
  1093. [System.Obsolete("Use VectorMath.LineIntersectionPoint instead")]
  1094. public static Vector2 IntersectionPoint (Vector2 start1, Vector2 end1, Vector2 start2, Vector2 end2) {
  1095. return VectorMath.LineIntersectionPoint(start1, end1, start2, end2);
  1096. }
  1097. /** Returns the intersection point between the two lines. Lines are treated as infinite. \a start1 is returned if the lines are parallel
  1098. * \deprecated Use VectorMath.LineIntersectionPoint instead */
  1099. [System.Obsolete("Use VectorMath.LineIntersectionPoint instead")]
  1100. public static Vector2 IntersectionPoint (Vector2 start1, Vector2 end1, Vector2 start2, Vector2 end2, out bool intersects) {
  1101. return VectorMath.LineIntersectionPoint(start1, end1, start2, end2, out intersects);
  1102. }
  1103. /** Returns the intersection point between the two line segments in XZ space.
  1104. * Lines are NOT treated as infinite. \a start1 is returned if the line segments do not intersect
  1105. * The point will be returned along the line [start1, end1] (this matters only for the y coordinate).
  1106. *
  1107. * \deprecated Use VectorMath.SegmentIntersectionPointXZ instead */
  1108. [System.Obsolete("Use VectorMath.SegmentIntersectionPointXZ instead")]
  1109. public static Vector3 SegmentIntersectionPoint (Vector3 start1, Vector3 end1, Vector3 start2, Vector3 end2, out bool intersects) {
  1110. return VectorMath.SegmentIntersectionPointXZ(start1, end1, start2, end2, out intersects);
  1111. }
  1112. /** Calculates convex hull in XZ space for the points.
  1113. * Implemented using the very simple Gift Wrapping Algorithm
  1114. * which has a complexity of O(nh) where \a n is the number of points and \a h is the number of points on the hull,
  1115. * so it is in the worst case quadratic.
  1116. *
  1117. * \deprecated Use ConvexHullXZ instead
  1118. */
  1119. [System.Obsolete("Use ConvexHullXZ instead")]
  1120. public static Vector3[] ConvexHull (Vector3[] points) {
  1121. return ConvexHullXZ(points);
  1122. }
  1123. /** Calculates convex hull in XZ space for the points.
  1124. * Implemented using the very simple Gift Wrapping Algorithm
  1125. * which has a complexity of O(nh) where \a n is the number of points and \a h is the number of points on the hull,
  1126. * so it is in the worst case quadratic.
  1127. */
  1128. public static Vector3[] ConvexHullXZ (Vector3[] points) {
  1129. if (points.Length == 0) return new Vector3[0];
  1130. var hull = ListPool<Vector3>.Claim();
  1131. int pointOnHull = 0;
  1132. for (int i = 1; i < points.Length; i++) if (points[i].x < points[pointOnHull].x) pointOnHull = i;
  1133. int startpoint = pointOnHull;
  1134. int counter = 0;
  1135. do {
  1136. hull.Add(points[pointOnHull]);
  1137. int endpoint = 0;
  1138. for (int i = 0; i < points.Length; i++) if (endpoint == pointOnHull || !VectorMath.RightOrColinearXZ(points[pointOnHull], points[endpoint], points[i])) endpoint = i;
  1139. pointOnHull = endpoint;
  1140. counter++;
  1141. if (counter > 10000) {
  1142. #if !SERVER
  1143. UnityEngine.Debug.LogWarning("Infinite Loop in Convex Hull Calculation");
  1144. #endif
  1145. break;
  1146. }
  1147. } while (pointOnHull != startpoint);
  1148. var result = hull.ToArray();
  1149. // Return to pool
  1150. ListPool<Vector3>.Release(hull);
  1151. return result;
  1152. }
  1153. /** Closest point on the triangle \a abc to the point \a p.
  1154. * \see 'Real Time Collision Detection' by Christer Ericson, chapter 5.1, page 141
  1155. */
  1156. public static Vector2 ClosestPointOnTriangle (Vector2 a, Vector2 b, Vector2 c, Vector2 p) {
  1157. // Check if p is in vertex region outside A
  1158. var ab = b - a;
  1159. var ac = c - a;
  1160. var ap = p - a;
  1161. var d1 = Vector2.Dot(ab, ap);
  1162. var d2 = Vector2.Dot(ac, ap);
  1163. // Barycentric coordinates (1,0,0)
  1164. if (d1 <= 0 && d2 <= 0) {
  1165. return a;
  1166. }
  1167. // Check if p is in vertex region outside B
  1168. var bp = p - b;
  1169. var d3 = Vector2.Dot(ab, bp);
  1170. var d4 = Vector2.Dot(ac, bp);
  1171. // Barycentric coordinates (0,1,0)
  1172. if (d3 >= 0 && d4 <= d3) {
  1173. return b;
  1174. }
  1175. // Check if p is in edge region outside AB, if so return a projection of p onto AB
  1176. if (d1 >= 0 && d3 <= 0) {
  1177. var vc = d1 * d4 - d3 * d2;
  1178. if (vc <= 0) {
  1179. // Barycentric coordinates (1-v, v, 0)
  1180. var v = d1 / (d1 - d3);
  1181. return a + ab*v;
  1182. }
  1183. }
  1184. // Check if p is in vertex region outside C
  1185. var cp = p - c;
  1186. var d5 = Vector2.Dot(ab, cp);
  1187. var d6 = Vector2.Dot(ac, cp);
  1188. // Barycentric coordinates (0,0,1)
  1189. if (d6 >= 0 && d5 <= d6) {
  1190. return c;
  1191. }
  1192. // Check if p is in edge region of AC, if so return a projection of p onto AC
  1193. if (d2 >= 0 && d6 <= 0) {
  1194. var vb = d5 * d2 - d1 * d6;
  1195. if (vb <= 0) {
  1196. // Barycentric coordinates (1-v, 0, v)
  1197. var v = d2 / (d2 - d6);
  1198. return a + ac*v;
  1199. }
  1200. }
  1201. // Check if p is in edge region of BC, if so return projection of p onto BC
  1202. if ((d4 - d3) >= 0 && (d5 - d6) >= 0) {
  1203. var va = d3 * d6 - d5 * d4;
  1204. if (va <= 0) {
  1205. var v = (d4 - d3) / ((d4 - d3) + (d5 - d6));
  1206. return b + (c - b) * v;
  1207. }
  1208. }
  1209. return p;
  1210. }
  1211. /** Closest point on the triangle \a abc to the point \a p when seen from above.
  1212. * \see 'Real Time Collision Detection' by Christer Ericson, chapter 5.1, page 141
  1213. */
  1214. public static Vector3 ClosestPointOnTriangleXZ (Vector3 a, Vector3 b, Vector3 c, Vector3 p) {
  1215. // Check if p is in vertex region outside A
  1216. var ab = new Vector2(b.x - a.x, b.z - a.z);
  1217. var ac = new Vector2(c.x - a.x, c.z - a.z);
  1218. var ap = new Vector2(p.x - a.x, p.z - a.z);
  1219. var d1 = Vector2.Dot(ab, ap);
  1220. var d2 = Vector2.Dot(ac, ap);
  1221. // Barycentric coordinates (1,0,0)
  1222. if (d1 <= 0 && d2 <= 0) {
  1223. return a;
  1224. }
  1225. // Check if p is in vertex region outside B
  1226. var bp = new Vector2(p.x - b.x, p.z - b.z);
  1227. var d3 = Vector2.Dot(ab, bp);
  1228. var d4 = Vector2.Dot(ac, bp);
  1229. // Barycentric coordinates (0,1,0)
  1230. if (d3 >= 0 && d4 <= d3) {
  1231. return b;
  1232. }
  1233. // Check if p is in edge region outside AB, if so return a projection of p onto AB
  1234. var vc = d1 * d4 - d3 * d2;
  1235. if (d1 >= 0 && d3 <= 0 && vc <= 0) {
  1236. // Barycentric coordinates (1-v, v, 0)
  1237. var v = d1 / (d1 - d3);
  1238. return (1-v)*a + v*b;
  1239. }
  1240. // Check if p is in vertex region outside C
  1241. var cp = new Vector2(p.x - c.x, p.z - c.z);
  1242. var d5 = Vector2.Dot(ab, cp);
  1243. var d6 = Vector2.Dot(ac, cp);
  1244. // Barycentric coordinates (0,0,1)
  1245. if (d6 >= 0 && d5 <= d6) {
  1246. return c;
  1247. }
  1248. // Check if p is in edge region of AC, if so return a projection of p onto AC
  1249. var vb = d5 * d2 - d1 * d6;
  1250. if (d2 >= 0 && d6 <= 0 && vb <= 0) {
  1251. // Barycentric coordinates (1-v, 0, v)
  1252. var v = d2 / (d2 - d6);
  1253. return (1-v)*a + v*c;
  1254. }
  1255. // Check if p is in edge region of BC, if so return projection of p onto BC
  1256. var va = d3 * d6 - d5 * d4;
  1257. if ((d4 - d3) >= 0 && (d5 - d6) >= 0 && va <= 0) {
  1258. var v = (d4 - d3) / ((d4 - d3) + (d5 - d6));
  1259. return b + (c - b) * v;
  1260. } else {
  1261. // P is inside the face region. Compute the point using its barycentric coordinates (u, v, w)
  1262. // Note that the x and z coordinates will be exactly the same as P's x and z coordinates
  1263. var denom = 1f / (va + vb + vc);
  1264. var v = vb * denom;
  1265. var w = vc * denom;
  1266. return new Vector3(p.x, (1 - v - w)*a.y + v*b.y + w*c.y, p.z);
  1267. }
  1268. }
  1269. /** Closest point on the triangle \a abc to the point \a p.
  1270. * \see 'Real Time Collision Detection' by Christer Ericson, chapter 5.1, page 141
  1271. */
  1272. public static Vector3 ClosestPointOnTriangle (Vector3 a, Vector3 b, Vector3 c, Vector3 p) {
  1273. // Check if p is in vertex region outside A
  1274. var ab = b - a;
  1275. var ac = c - a;
  1276. var ap = p - a;
  1277. var d1 = Vector3.Dot(ab, ap);
  1278. var d2 = Vector3.Dot(ac, ap);
  1279. // Barycentric coordinates (1,0,0)
  1280. if (d1 <= 0 && d2 <= 0)
  1281. return a;
  1282. // Check if p is in vertex region outside B
  1283. var bp = p - b;
  1284. var d3 = Vector3.Dot(ab, bp);
  1285. var d4 = Vector3.Dot(ac, bp);
  1286. // Barycentric coordinates (0,1,0)
  1287. if (d3 >= 0 && d4 <= d3)
  1288. return b;
  1289. // Check if p is in edge region outside AB, if so return a projection of p onto AB
  1290. var vc = d1 * d4 - d3 * d2;
  1291. if (d1 >= 0 && d3 <= 0 && vc <= 0) {
  1292. // Barycentric coordinates (1-v, v, 0)
  1293. var v = d1 / (d1 - d3);
  1294. return a + ab * v;
  1295. }
  1296. // Check if p is in vertex region outside C
  1297. var cp = p - c;
  1298. var d5 = Vector3.Dot(ab, cp);
  1299. var d6 = Vector3.Dot(ac, cp);
  1300. // Barycentric coordinates (0,0,1)
  1301. if (d6 >= 0 && d5 <= d6)
  1302. return c;
  1303. // Check if p is in edge region of AC, if so return a projection of p onto AC
  1304. var vb = d5 * d2 - d1 * d6;
  1305. if (d2 >= 0 && d6 <= 0 && vb <= 0) {
  1306. // Barycentric coordinates (1-v, 0, v)
  1307. var v = d2 / (d2 - d6);
  1308. return a + ac * v;
  1309. }
  1310. // Check if p is in edge region of BC, if so return projection of p onto BC
  1311. var va = d3 * d6 - d5 * d4;
  1312. if ((d4 - d3) >= 0 && (d5 - d6) >= 0 && va <= 0) {
  1313. var v = (d4 - d3) / ((d4 - d3) + (d5 - d6));
  1314. return b + (c - b) * v;
  1315. } else {
  1316. // P is inside the face region. Compute the point using its barycentric coordinates (u, v, w)
  1317. var denom = 1f / (va + vb + vc);
  1318. var v = vb * denom;
  1319. var w = vc * denom;
  1320. // This is equal to: u*a + v*b + w*c, u = va*denom = 1 - v - w;
  1321. return a + ab * v + ac * w;
  1322. }
  1323. }
  1324. /** Get the 3D minimum distance between 2 segments
  1325. * Input: two 3D line segments S1 and S2
  1326. * \returns the shortest squared distance between S1 and S2
  1327. *
  1328. * \deprecated Use VectorMath.SqrDistanceSegmentSegment instead
  1329. */
  1330. [System.Obsolete("Use VectorMath.SqrDistanceSegmentSegment instead")]
  1331. public static float DistanceSegmentSegment3D (Vector3 s1, Vector3 e1, Vector3 s2, Vector3 e2) {
  1332. return VectorMath.SqrDistanceSegmentSegment(s1, e1, s2, e2);
  1333. }
  1334. /** Cached dictionary to avoid excessive allocations */
  1335. static readonly Dictionary<Int3, int> cached_Int3_int_dict = new Dictionary<Int3, int>();
  1336. /** Compress the mesh by removing duplicate vertices.
  1337. *
  1338. * \param vertices Vertices of the input mesh
  1339. * \param triangles Triangles of the input mesh
  1340. * \param outVertices Vertices of the output mesh.
  1341. * \param outTriangles Triangles of the output mesh.
  1342. *
  1343. * Vertices that differ by only 1 along the y coordinate will also be merged together.
  1344. * \warning This function is not threadsafe. It uses some cached structures to reduce allocations.
  1345. */
  1346. public static void CompressMesh (List<Int3> vertices, List<int> triangles, out Int3[] outVertices, out int[] outTriangles) {
  1347. Dictionary<Int3, int> firstVerts = cached_Int3_int_dict;
  1348. firstVerts.Clear();
  1349. // Use cached array to reduce memory allocations
  1350. int[] compressedPointers = ArrayPool<int>.Claim(vertices.Count);
  1351. // Map positions to the first index they were encountered at
  1352. int count = 0;
  1353. for (int i = 0; i < vertices.Count; i++) {
  1354. // Check if the vertex position has already been added
  1355. // Also check one position up and one down because rounding errors can cause vertices
  1356. // that should end up in the same position to be offset 1 unit from each other
  1357. // TODO: Check along X and Z axes as well?
  1358. int ind;
  1359. if (!firstVerts.TryGetValue(vertices[i], out ind) && !firstVerts.TryGetValue(vertices[i] + new Int3(0, 1, 0), out ind) && !firstVerts.TryGetValue(vertices[i] + new Int3(0, -1, 0), out ind)) {
  1360. firstVerts.Add(vertices[i], count);
  1361. compressedPointers[i] = count;
  1362. vertices[count] = vertices[i];
  1363. count++;
  1364. } else {
  1365. compressedPointers[i] = ind;
  1366. }
  1367. }
  1368. // Create the triangle array or reuse the existing buffer
  1369. outTriangles = new int[triangles.Count];
  1370. // Remap the triangles to the new compressed indices
  1371. for (int i = 0; i < outTriangles.Length; i++) {
  1372. outTriangles[i] = compressedPointers[triangles[i]];
  1373. }
  1374. // Create the vertex array or reuse the existing buffer
  1375. outVertices = new Int3[count];
  1376. for (int i = 0; i < count; i++)
  1377. outVertices[i] = vertices[i];
  1378. ArrayPool<int>.Release(ref compressedPointers);
  1379. }
  1380. /** Given a set of edges between vertices, follows those edges and returns them as chains and cycles.
  1381. * \param outline outline[a] = b if there is an edge from \a a to \a b.
  1382. * \param hasInEdge \a hasInEdge should contain \a b if outline[a] = b for any key \a a.
  1383. * \param results Will be called once for each contour with the contour as a parameter as well as a boolean indicating if the contour is a cycle or a chain (see image).
  1384. *
  1385. * \shadowimage{grid_contour_compressed.png}
  1386. */
  1387. public static void TraceContours (Dictionary<int, int> outline, HashSet<int> hasInEdge, System.Action<List<int>, bool> results) {
  1388. // Iterate through chains of the navmesh outline.
  1389. // I.e segments of the outline that are not loops
  1390. // we need to start these at the beginning of the chain.
  1391. // Then iterate over all the loops of the outline.
  1392. // Since they are loops, we can start at any point.
  1393. var obstacleVertices = ListPool<int>.Claim();
  1394. var outlineKeys = ListPool<int>.Claim();
  1395. outlineKeys.AddRange(outline.Keys);
  1396. for (int k = 0; k <= 1; k++) {
  1397. bool cycles = k == 1;
  1398. for (int i = 0; i < outlineKeys.Count; i++) {
  1399. var startIndex = outlineKeys[i];
  1400. // Chains (not cycles) need to start at the start of the chain
  1401. // Cycles can start at any point
  1402. if (!cycles && hasInEdge.Contains(startIndex)) {
  1403. continue;
  1404. }
  1405. var index = startIndex;
  1406. obstacleVertices.Clear();
  1407. obstacleVertices.Add(index);
  1408. while (outline.ContainsKey(index)) {
  1409. var next = outline[index];
  1410. outline.Remove(index);
  1411. obstacleVertices.Add(next);
  1412. // We traversed a full cycle
  1413. if (next == startIndex) break;
  1414. index = next;
  1415. }
  1416. if (obstacleVertices.Count > 1) {
  1417. results(obstacleVertices, cycles);
  1418. }
  1419. }
  1420. }
  1421. ListPool<int>.Release(ref outlineKeys);
  1422. ListPool<int>.Release(ref obstacleVertices);
  1423. }
  1424. /** Divides each segment in the list into \a subSegments segments and fills the result list with the new points */
  1425. public static void Subdivide (List<Vector3> points, List<Vector3> result, int subSegments) {
  1426. for (int i = 0; i < points.Count-1; i++)
  1427. for (int j = 0; j < subSegments; j++)
  1428. result.Add(Vector3.Lerp(points[i], points[i+1], j / (float)subSegments));
  1429. result.Add(points[points.Count-1]);
  1430. }
  1431. }
  1432. }