DelaunayTriangle.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /* Poly2Tri
  2. * Copyright (c) 2009-2010, Poly2Tri Contributors
  3. * http://code.google.com/p/poly2tri/
  4. *
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted provided that the following conditions are met:
  9. *
  10. * * Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. * * Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation
  14. * and/or other materials provided with the distribution.
  15. * * Neither the name of Poly2Tri nor the names of its contributors may be
  16. * used to endorse or promote products derived from this software without specific
  17. * prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. // Changes from the Java version
  32. // attributification
  33. // Future possibilities
  34. // Flattening out the number of indirections
  35. // Replacing arrays of 3 with fixed-length arrays?
  36. // Replacing bool[3] with a bit array of some sort?
  37. // Bundling everything into an AoS mess?
  38. // Hardcode them all as ABC ?
  39. using System;
  40. using System.Collections.Generic;
  41. using System.Diagnostics;
  42. using Poly2Tri.Triangulation.Delaunay.Sweep;
  43. using Poly2Tri.Triangulation.Util;
  44. namespace Poly2Tri.Triangulation.Delaunay
  45. {
  46. public class DelaunayTriangle
  47. {
  48. /** Neighbor pointers */
  49. /** Flags to determine if an edge is a Delauney edge */
  50. public FixedBitArray3 EdgeIsConstrained;
  51. /** Flags to determine if an edge is a Constrained edge */
  52. public FixedBitArray3 EdgeIsDelaunay;
  53. public FixedArray3<DelaunayTriangle> Neighbors;
  54. /** Has this triangle been marked as an interior triangle? */
  55. public FixedArray3<TriangulationPoint> Points;
  56. public DelaunayTriangle(TriangulationPoint p1, TriangulationPoint p2, TriangulationPoint p3)
  57. {
  58. Points[0] = p1;
  59. Points[1] = p2;
  60. Points[2] = p3;
  61. }
  62. public bool IsInterior { get; set; }
  63. public int IndexOf(TriangulationPoint p)
  64. {
  65. int i = Points.IndexOf(p);
  66. if (i == -1) throw new Exception("Calling index with a point that doesn't exist in triangle");
  67. return i;
  68. }
  69. //TODO: Port note - different implementation
  70. public int IndexCW(TriangulationPoint p)
  71. {
  72. int index = IndexOf(p);
  73. switch (index)
  74. {
  75. case 0:
  76. return 2;
  77. case 1:
  78. return 0;
  79. default:
  80. return 1;
  81. }
  82. }
  83. //TODO: Port note - different implementation
  84. public int IndexCCW(TriangulationPoint p)
  85. {
  86. int index = IndexOf(p);
  87. switch (index)
  88. {
  89. case 0:
  90. return 1;
  91. case 1:
  92. return 2;
  93. default:
  94. return 0;
  95. }
  96. }
  97. public bool Contains(TriangulationPoint p)
  98. {
  99. return (p == Points[0] || p == Points[1] || p == Points[2]);
  100. }
  101. public bool Contains(DTSweepConstraint e)
  102. {
  103. return (Contains(e.P) && Contains(e.Q));
  104. }
  105. public bool Contains(TriangulationPoint p, TriangulationPoint q)
  106. {
  107. return (Contains(p) && Contains(q));
  108. }
  109. /// <summary>
  110. /// Update neighbor pointers
  111. /// </summary>
  112. /// <param name="p1">Point 1 of the shared edge</param>
  113. /// <param name="p2">Point 2 of the shared edge</param>
  114. /// <param name="t">This triangle's new neighbor</param>
  115. private void MarkNeighbor(TriangulationPoint p1, TriangulationPoint p2, DelaunayTriangle t)
  116. {
  117. if ((p1 == Points[2] && p2 == Points[1]) || (p1 == Points[1] && p2 == Points[2]))
  118. {
  119. Neighbors[0] = t;
  120. }
  121. else if ((p1 == Points[0] && p2 == Points[2]) || (p1 == Points[2] && p2 == Points[0]))
  122. {
  123. Neighbors[1] = t;
  124. }
  125. else if ((p1 == Points[0] && p2 == Points[1]) || (p1 == Points[1] && p2 == Points[0]))
  126. {
  127. Neighbors[2] = t;
  128. }
  129. else
  130. {
  131. Debug.WriteLine("Neighbor error, please report!");
  132. // throw new Exception("Neighbor error, please report!");
  133. }
  134. }
  135. /// <summary>
  136. /// Exhaustive search to update neighbor pointers
  137. /// </summary>
  138. public void MarkNeighbor(DelaunayTriangle t)
  139. {
  140. if (t.Contains(Points[1], Points[2]))
  141. {
  142. Neighbors[0] = t;
  143. t.MarkNeighbor(Points[1], Points[2], this);
  144. }
  145. else if (t.Contains(Points[0], Points[2]))
  146. {
  147. Neighbors[1] = t;
  148. t.MarkNeighbor(Points[0], Points[2], this);
  149. }
  150. else if (t.Contains(Points[0], Points[1]))
  151. {
  152. Neighbors[2] = t;
  153. t.MarkNeighbor(Points[0], Points[1], this);
  154. }
  155. else
  156. {
  157. Debug.WriteLine("markNeighbor failed");
  158. }
  159. }
  160. public void ClearNeighbors()
  161. {
  162. Neighbors[0] = Neighbors[1] = Neighbors[2] = null;
  163. }
  164. public void ClearNeighbor(DelaunayTriangle triangle)
  165. {
  166. if (Neighbors[0] == triangle)
  167. {
  168. Neighbors[0] = null;
  169. }
  170. else if (Neighbors[1] == triangle)
  171. {
  172. Neighbors[1] = null;
  173. }
  174. else
  175. {
  176. Neighbors[2] = null;
  177. }
  178. }
  179. /**
  180. * Clears all references to all other triangles and points
  181. */
  182. public void Clear()
  183. {
  184. DelaunayTriangle t;
  185. for (int i = 0; i < 3; i++)
  186. {
  187. t = Neighbors[i];
  188. if (t != null)
  189. {
  190. t.ClearNeighbor(this);
  191. }
  192. }
  193. ClearNeighbors();
  194. Points[0] = Points[1] = Points[2] = null;
  195. }
  196. /// <param name="t">Opposite triangle</param>
  197. /// <param name="p">The point in t that isn't shared between the triangles</param>
  198. public TriangulationPoint OppositePoint(DelaunayTriangle t, TriangulationPoint p)
  199. {
  200. Debug.Assert(t != this, "self-pointer error");
  201. return PointCW(t.PointCW(p));
  202. }
  203. public DelaunayTriangle NeighborCW(TriangulationPoint point)
  204. {
  205. return Neighbors[(Points.IndexOf(point) + 1)%3];
  206. }
  207. public DelaunayTriangle NeighborCCW(TriangulationPoint point)
  208. {
  209. return Neighbors[(Points.IndexOf(point) + 2)%3];
  210. }
  211. public DelaunayTriangle NeighborAcross(TriangulationPoint point)
  212. {
  213. return Neighbors[Points.IndexOf(point)];
  214. }
  215. public TriangulationPoint PointCCW(TriangulationPoint point)
  216. {
  217. return Points[(IndexOf(point) + 1)%3];
  218. }
  219. public TriangulationPoint PointCW(TriangulationPoint point)
  220. {
  221. return Points[(IndexOf(point) + 2)%3];
  222. }
  223. private void RotateCW()
  224. {
  225. var t = Points[2];
  226. Points[2] = Points[1];
  227. Points[1] = Points[0];
  228. Points[0] = t;
  229. }
  230. /// <summary>
  231. /// Legalize triangle by rotating clockwise around oPoint
  232. /// </summary>
  233. /// <param name="oPoint">The origin point to rotate around</param>
  234. /// <param name="nPoint">???</param>
  235. public void Legalize(TriangulationPoint oPoint, TriangulationPoint nPoint)
  236. {
  237. RotateCW();
  238. Points[IndexCCW(oPoint)] = nPoint;
  239. }
  240. public override string ToString()
  241. {
  242. return Points[0] + "," + Points[1] + "," + Points[2];
  243. }
  244. /// <summary>
  245. /// Finalize edge marking
  246. /// </summary>
  247. public void MarkNeighborEdges()
  248. {
  249. for (int i = 0; i < 3; i++)
  250. if (EdgeIsConstrained[i] && Neighbors[i] != null)
  251. {
  252. Neighbors[i].MarkConstrainedEdge(Points[(i + 1)%3], Points[(i + 2)%3]);
  253. }
  254. }
  255. public void MarkEdge(DelaunayTriangle triangle)
  256. {
  257. for (int i = 0; i < 3; i++)
  258. if (EdgeIsConstrained[i])
  259. {
  260. triangle.MarkConstrainedEdge(Points[(i + 1)%3], Points[(i + 2)%3]);
  261. }
  262. }
  263. public void MarkEdge(List<DelaunayTriangle> tList)
  264. {
  265. foreach (DelaunayTriangle t in tList)
  266. for (int i = 0; i < 3; i++)
  267. if (t.EdgeIsConstrained[i])
  268. {
  269. MarkConstrainedEdge(t.Points[(i + 1)%3], t.Points[(i + 2)%3]);
  270. }
  271. }
  272. public void MarkConstrainedEdge(int index)
  273. {
  274. EdgeIsConstrained[index] = true;
  275. }
  276. public void MarkConstrainedEdge(DTSweepConstraint edge)
  277. {
  278. MarkConstrainedEdge(edge.P, edge.Q);
  279. }
  280. /// <summary>
  281. /// Mark edge as constrained
  282. /// </summary>
  283. public void MarkConstrainedEdge(TriangulationPoint p, TriangulationPoint q)
  284. {
  285. int i = EdgeIndex(p, q);
  286. if (i != -1) EdgeIsConstrained[i] = true;
  287. }
  288. public double Area()
  289. {
  290. double b = Points[0].X - Points[1].X;
  291. double h = Points[2].Y - Points[1].Y;
  292. return Math.Abs((b*h*0.5f));
  293. }
  294. public TriangulationPoint Centroid()
  295. {
  296. double cx = (Points[0].X + Points[1].X + Points[2].X)/3f;
  297. double cy = (Points[0].Y + Points[1].Y + Points[2].Y)/3f;
  298. return new TriangulationPoint(cx, cy);
  299. }
  300. /// <summary>
  301. /// Get the index of the neighbor that shares this edge (or -1 if it isn't shared)
  302. /// </summary>
  303. /// <returns>index of the shared edge or -1 if edge isn't shared</returns>
  304. public int EdgeIndex(TriangulationPoint p1, TriangulationPoint p2)
  305. {
  306. int i1 = Points.IndexOf(p1);
  307. int i2 = Points.IndexOf(p2);
  308. // Points of this triangle in the edge p1-p2
  309. bool a = (i1 == 0 || i2 == 0);
  310. bool b = (i1 == 1 || i2 == 1);
  311. bool c = (i1 == 2 || i2 == 2);
  312. if (b && c) return 0;
  313. if (a && c) return 1;
  314. if (a && b) return 2;
  315. return -1;
  316. }
  317. public bool GetConstrainedEdgeCCW(TriangulationPoint p)
  318. {
  319. return EdgeIsConstrained[(IndexOf(p) + 2)%3];
  320. }
  321. public bool GetConstrainedEdgeCW(TriangulationPoint p)
  322. {
  323. return EdgeIsConstrained[(IndexOf(p) + 1)%3];
  324. }
  325. public bool GetConstrainedEdgeAcross(TriangulationPoint p)
  326. {
  327. return EdgeIsConstrained[IndexOf(p)];
  328. }
  329. public void SetConstrainedEdgeCCW(TriangulationPoint p, bool ce)
  330. {
  331. EdgeIsConstrained[(IndexOf(p) + 2)%3] = ce;
  332. }
  333. public void SetConstrainedEdgeCW(TriangulationPoint p, bool ce)
  334. {
  335. EdgeIsConstrained[(IndexOf(p) + 1)%3] = ce;
  336. }
  337. public void SetConstrainedEdgeAcross(TriangulationPoint p, bool ce)
  338. {
  339. EdgeIsConstrained[IndexOf(p)] = ce;
  340. }
  341. public bool GetDelaunayEdgeCCW(TriangulationPoint p)
  342. {
  343. return EdgeIsDelaunay[(IndexOf(p) + 2)%3];
  344. }
  345. public bool GetDelaunayEdgeCW(TriangulationPoint p)
  346. {
  347. return EdgeIsDelaunay[(IndexOf(p) + 1)%3];
  348. }
  349. public bool GetDelaunayEdgeAcross(TriangulationPoint p)
  350. {
  351. return EdgeIsDelaunay[IndexOf(p)];
  352. }
  353. public void SetDelaunayEdgeCCW(TriangulationPoint p, bool ce)
  354. {
  355. EdgeIsDelaunay[(IndexOf(p) + 2)%3] = ce;
  356. }
  357. public void SetDelaunayEdgeCW(TriangulationPoint p, bool ce)
  358. {
  359. EdgeIsDelaunay[(IndexOf(p) + 1)%3] = ce;
  360. }
  361. public void SetDelaunayEdgeAcross(TriangulationPoint p, bool ce)
  362. {
  363. EdgeIsDelaunay[IndexOf(p)] = ce;
  364. }
  365. }
  366. }