Dwyer.cs 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. // -----------------------------------------------------------------------
  2. // <copyright file="Dwyer.cs">
  3. // Original Triangle code by Jonathan Richard Shewchuk, http://www.cs.cmu.edu/~quake/triangle.html
  4. // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
  5. // </copyright>
  6. // -----------------------------------------------------------------------
  7. namespace UnityEngine.U2D.Animation.TriangleNet
  8. .Meshing.Algorithm
  9. {
  10. using System;
  11. using System.Collections.Generic;
  12. using Animation.TriangleNet.Geometry;
  13. using Animation.TriangleNet.Tools;
  14. using Animation.TriangleNet.Topology;
  15. /// <summary>
  16. /// Builds a delaunay triangulation using the divide-and-conquer algorithm.
  17. /// </summary>
  18. /// <remarks>
  19. /// The divide-and-conquer bounding box
  20. ///
  21. /// I originally implemented the divide-and-conquer and incremental Delaunay
  22. /// triangulations using the edge-based data structure presented by Guibas
  23. /// and Stolfi. Switching to a triangle-based data structure doubled the
  24. /// speed. However, I had to think of a few extra tricks to maintain the
  25. /// elegance of the original algorithms.
  26. ///
  27. /// The "bounding box" used by my variant of the divide-and-conquer
  28. /// algorithm uses one triangle for each edge of the convex hull of the
  29. /// triangulation. These bounding triangles all share a common apical
  30. /// vertex, which is represented by NULL and which represents nothing.
  31. /// The bounding triangles are linked in a circular fan about this NULL
  32. /// vertex, and the edges on the convex hull of the triangulation appear
  33. /// opposite the NULL vertex. You might find it easiest to imagine that
  34. /// the NULL vertex is a point in 3D space behind the center of the
  35. /// triangulation, and that the bounding triangles form a sort of cone.
  36. ///
  37. /// This bounding box makes it easy to represent degenerate cases. For
  38. /// instance, the triangulation of two vertices is a single edge. This edge
  39. /// is represented by two bounding box triangles, one on each "side" of the
  40. /// edge. These triangles are also linked together in a fan about the NULL
  41. /// vertex.
  42. ///
  43. /// The bounding box also makes it easy to traverse the convex hull, as the
  44. /// divide-and-conquer algorithm needs to do.
  45. /// </remarks>
  46. internal class Dwyer : ITriangulator
  47. {
  48. // Random is not threadsafe, so don't make this static.
  49. // Random rand = new Random(DateTime.Now.Millisecond);
  50. IPredicates predicates;
  51. public bool UseDwyer = true;
  52. Vertex[] sortarray;
  53. Mesh mesh;
  54. /// <summary>
  55. /// Form a Delaunay triangulation by the divide-and-conquer method.
  56. /// </summary>
  57. /// <returns></returns>
  58. /// <remarks>
  59. /// Sorts the vertices, calls a recursive procedure to triangulate them, and
  60. /// removes the bounding box, setting boundary markers as appropriate.
  61. /// </remarks>
  62. public IMesh Triangulate(IList<Vertex> points, Configuration config)
  63. {
  64. this.predicates = config.Predicates();
  65. this.mesh = new Mesh(config);
  66. this.mesh.TransferNodes(points);
  67. Otri hullleft = default(Otri), hullright = default(Otri);
  68. int i, j, n = points.Count;
  69. // Allocate an array of pointers to vertices for sorting.
  70. this.sortarray = new Vertex[n];
  71. i = 0;
  72. foreach (var v in points)
  73. {
  74. sortarray[i++] = v;
  75. }
  76. // Sort the vertices.
  77. VertexSorter.Sort(sortarray);
  78. // Discard duplicate vertices, which can really mess up the algorithm.
  79. i = 0;
  80. for (j = 1; j < n; j++)
  81. {
  82. if ((sortarray[i].x == sortarray[j].x) && (sortarray[i].y == sortarray[j].y))
  83. {
  84. if (Log.Verbose)
  85. {
  86. Log.Instance.Warning(
  87. String.Format("A duplicate vertex appeared and was ignored (ID {0}).", sortarray[j].id),
  88. "Dwyer.Triangulate()");
  89. }
  90. sortarray[j].type = VertexType.UndeadVertex;
  91. mesh.undeads++;
  92. }
  93. else
  94. {
  95. i++;
  96. sortarray[i] = sortarray[j];
  97. }
  98. }
  99. i++;
  100. if (UseDwyer)
  101. {
  102. // Re-sort the array of vertices to accommodate alternating cuts.
  103. VertexSorter.Alternate(sortarray, i);
  104. }
  105. // Form the Delaunay triangulation.
  106. DivconqRecurse(0, i - 1, 0, ref hullleft, ref hullright);
  107. this.mesh.hullsize = RemoveGhosts(ref hullleft);
  108. return this.mesh;
  109. }
  110. /// <summary>
  111. /// Merge two adjacent Delaunay triangulations into a single Delaunay triangulation.
  112. /// </summary>
  113. /// <param name="farleft">Bounding triangles of the left triangulation.</param>
  114. /// <param name="innerleft">Bounding triangles of the left triangulation.</param>
  115. /// <param name="innerright">Bounding triangles of the right triangulation.</param>
  116. /// <param name="farright">Bounding triangles of the right triangulation.</param>
  117. /// <param name="axis"></param>
  118. /// <remarks>
  119. /// This is similar to the algorithm given by Guibas and Stolfi, but uses
  120. /// a triangle-based, rather than edge-based, data structure.
  121. ///
  122. /// The algorithm walks up the gap between the two triangulations, knitting
  123. /// them together. As they are merged, some of their bounding triangles
  124. /// are converted into real triangles of the triangulation. The procedure
  125. /// pulls each hull's bounding triangles apart, then knits them together
  126. /// like the teeth of two gears. The Delaunay property determines, at each
  127. /// step, whether the next "tooth" is a bounding triangle of the left hull
  128. /// or the right. When a bounding triangle becomes real, its apex is
  129. /// changed from NULL to a real vertex.
  130. ///
  131. /// Only two new triangles need to be allocated. These become new bounding
  132. /// triangles at the top and bottom of the seam. They are used to connect
  133. /// the remaining bounding triangles (those that have not been converted
  134. /// into real triangles) into a single fan.
  135. ///
  136. /// On label, 'farleft' and 'innerleft' are bounding triangles of the left
  137. /// triangulation. The origin of 'farleft' is the leftmost vertex, and
  138. /// the destination of 'innerleft' is the rightmost vertex of the
  139. /// triangulation. Similarly, 'innerright' and 'farright' are bounding
  140. /// triangles of the right triangulation. The origin of 'innerright' and
  141. /// destination of 'farright' are the leftmost and rightmost vertices.
  142. ///
  143. /// On completion, the origin of 'farleft' is the leftmost vertex of the
  144. /// merged triangulation, and the destination of 'farright' is the rightmost
  145. /// vertex.
  146. /// </remarks>
  147. void MergeHulls(ref Otri farleft, ref Otri innerleft, ref Otri innerright,
  148. ref Otri farright, int axis)
  149. {
  150. Otri leftcand = default(Otri), rightcand = default(Otri);
  151. Otri nextedge = default(Otri);
  152. Otri sidecasing = default(Otri), topcasing = default(Otri), outercasing = default(Otri);
  153. Otri checkedge = default(Otri);
  154. Otri baseedge = default(Otri);
  155. Vertex innerleftdest;
  156. Vertex innerrightorg;
  157. Vertex innerleftapex, innerrightapex;
  158. Vertex farleftpt, farrightpt;
  159. Vertex farleftapex, farrightapex;
  160. Vertex lowerleft, lowerright;
  161. Vertex upperleft, upperright;
  162. Vertex nextapex;
  163. Vertex checkvertex;
  164. bool changemade;
  165. bool badedge;
  166. bool leftfinished, rightfinished;
  167. innerleftdest = innerleft.Dest();
  168. innerleftapex = innerleft.Apex();
  169. innerrightorg = innerright.Org();
  170. innerrightapex = innerright.Apex();
  171. // Special treatment for horizontal cuts.
  172. if (UseDwyer && (axis == 1))
  173. {
  174. farleftpt = farleft.Org();
  175. farleftapex = farleft.Apex();
  176. farrightpt = farright.Dest();
  177. farrightapex = farright.Apex();
  178. // The pointers to the extremal vertices are shifted to point to the
  179. // topmost and bottommost vertex of each hull, rather than the
  180. // leftmost and rightmost vertices.
  181. while (farleftapex.y < farleftpt.y)
  182. {
  183. farleft.Lnext();
  184. farleft.Sym();
  185. farleftpt = farleftapex;
  186. farleftapex = farleft.Apex();
  187. }
  188. innerleft.Sym(ref checkedge);
  189. checkvertex = checkedge.Apex();
  190. while (checkvertex.y > innerleftdest.y)
  191. {
  192. checkedge.Lnext(ref innerleft);
  193. innerleftapex = innerleftdest;
  194. innerleftdest = checkvertex;
  195. innerleft.Sym(ref checkedge);
  196. checkvertex = checkedge.Apex();
  197. }
  198. while (innerrightapex.y < innerrightorg.y)
  199. {
  200. innerright.Lnext();
  201. innerright.Sym();
  202. innerrightorg = innerrightapex;
  203. innerrightapex = innerright.Apex();
  204. }
  205. farright.Sym(ref checkedge);
  206. checkvertex = checkedge.Apex();
  207. while (checkvertex.y > farrightpt.y)
  208. {
  209. checkedge.Lnext(ref farright);
  210. farrightapex = farrightpt;
  211. farrightpt = checkvertex;
  212. farright.Sym(ref checkedge);
  213. checkvertex = checkedge.Apex();
  214. }
  215. }
  216. // Find a line tangent to and below both hulls.
  217. do
  218. {
  219. changemade = false;
  220. // Make innerleftdest the "bottommost" vertex of the left hull.
  221. if (predicates.CounterClockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0)
  222. {
  223. innerleft.Lprev();
  224. innerleft.Sym();
  225. innerleftdest = innerleftapex;
  226. innerleftapex = innerleft.Apex();
  227. changemade = true;
  228. }
  229. // Make innerrightorg the "bottommost" vertex of the right hull.
  230. if (predicates.CounterClockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0)
  231. {
  232. innerright.Lnext();
  233. innerright.Sym();
  234. innerrightorg = innerrightapex;
  235. innerrightapex = innerright.Apex();
  236. changemade = true;
  237. }
  238. }
  239. while (changemade);
  240. // Find the two candidates to be the next "gear tooth."
  241. innerleft.Sym(ref leftcand);
  242. innerright.Sym(ref rightcand);
  243. // Create the bottom new bounding triangle.
  244. mesh.MakeTriangle(ref baseedge);
  245. // Connect it to the bounding boxes of the left and right triangulations.
  246. baseedge.Bond(ref innerleft);
  247. baseedge.Lnext();
  248. baseedge.Bond(ref innerright);
  249. baseedge.Lnext();
  250. baseedge.SetOrg(innerrightorg);
  251. baseedge.SetDest(innerleftdest);
  252. // Apex is intentionally left NULL.
  253. // Fix the extreme triangles if necessary.
  254. farleftpt = farleft.Org();
  255. if (innerleftdest == farleftpt)
  256. {
  257. baseedge.Lnext(ref farleft);
  258. }
  259. farrightpt = farright.Dest();
  260. if (innerrightorg == farrightpt)
  261. {
  262. baseedge.Lprev(ref farright);
  263. }
  264. // The vertices of the current knitting edge.
  265. lowerleft = innerleftdest;
  266. lowerright = innerrightorg;
  267. // The candidate vertices for knitting.
  268. upperleft = leftcand.Apex();
  269. upperright = rightcand.Apex();
  270. // Walk up the gap between the two triangulations, knitting them together.
  271. while (true)
  272. {
  273. // Have we reached the top? (This isn't quite the right question,
  274. // because even though the left triangulation might seem finished now,
  275. // moving up on the right triangulation might reveal a new vertex of
  276. // the left triangulation. And vice-versa.)
  277. leftfinished = predicates.CounterClockwise(upperleft, lowerleft, lowerright) <= 0.0;
  278. rightfinished = predicates.CounterClockwise(upperright, lowerleft, lowerright) <= 0.0;
  279. if (leftfinished && rightfinished)
  280. {
  281. // Create the top new bounding triangle.
  282. mesh.MakeTriangle(ref nextedge);
  283. nextedge.SetOrg(lowerleft);
  284. nextedge.SetDest(lowerright);
  285. // Apex is intentionally left NULL.
  286. // Connect it to the bounding boxes of the two triangulations.
  287. nextedge.Bond(ref baseedge);
  288. nextedge.Lnext();
  289. nextedge.Bond(ref rightcand);
  290. nextedge.Lnext();
  291. nextedge.Bond(ref leftcand);
  292. // Special treatment for horizontal cuts.
  293. if (UseDwyer && (axis == 1))
  294. {
  295. farleftpt = farleft.Org();
  296. farleftapex = farleft.Apex();
  297. farrightpt = farright.Dest();
  298. farrightapex = farright.Apex();
  299. farleft.Sym(ref checkedge);
  300. checkvertex = checkedge.Apex();
  301. // The pointers to the extremal vertices are restored to the
  302. // leftmost and rightmost vertices (rather than topmost and
  303. // bottommost).
  304. while (checkvertex.x < farleftpt.x)
  305. {
  306. checkedge.Lprev(ref farleft);
  307. farleftapex = farleftpt;
  308. farleftpt = checkvertex;
  309. farleft.Sym(ref checkedge);
  310. checkvertex = checkedge.Apex();
  311. }
  312. while (farrightapex.x > farrightpt.x)
  313. {
  314. farright.Lprev();
  315. farright.Sym();
  316. farrightpt = farrightapex;
  317. farrightapex = farright.Apex();
  318. }
  319. }
  320. return;
  321. }
  322. // Consider eliminating edges from the left triangulation.
  323. if (!leftfinished)
  324. {
  325. // What vertex would be exposed if an edge were deleted?
  326. leftcand.Lprev(ref nextedge);
  327. nextedge.Sym();
  328. nextapex = nextedge.Apex();
  329. // If nextapex is NULL, then no vertex would be exposed; the
  330. // triangulation would have been eaten right through.
  331. if (nextapex != null)
  332. {
  333. // Check whether the edge is Delaunay.
  334. badedge = predicates.InCircle(lowerleft, lowerright, upperleft, nextapex) > 0.0;
  335. while (badedge)
  336. {
  337. // Eliminate the edge with an edge flip. As a result, the
  338. // left triangulation will have one more boundary triangle.
  339. nextedge.Lnext();
  340. nextedge.Sym(ref topcasing);
  341. nextedge.Lnext();
  342. nextedge.Sym(ref sidecasing);
  343. nextedge.Bond(ref topcasing);
  344. leftcand.Bond(ref sidecasing);
  345. leftcand.Lnext();
  346. leftcand.Sym(ref outercasing);
  347. nextedge.Lprev();
  348. nextedge.Bond(ref outercasing);
  349. // Correct the vertices to reflect the edge flip.
  350. leftcand.SetOrg(lowerleft);
  351. leftcand.SetDest(null);
  352. leftcand.SetApex(nextapex);
  353. nextedge.SetOrg(null);
  354. nextedge.SetDest(upperleft);
  355. nextedge.SetApex(nextapex);
  356. // Consider the newly exposed vertex.
  357. upperleft = nextapex;
  358. // What vertex would be exposed if another edge were deleted?
  359. sidecasing.Copy(ref nextedge);
  360. nextapex = nextedge.Apex();
  361. if (nextapex != null)
  362. {
  363. // Check whether the edge is Delaunay.
  364. badedge = predicates.InCircle(lowerleft, lowerright, upperleft, nextapex) > 0.0;
  365. }
  366. else
  367. {
  368. // Avoid eating right through the triangulation.
  369. badedge = false;
  370. }
  371. }
  372. }
  373. }
  374. // Consider eliminating edges from the right triangulation.
  375. if (!rightfinished)
  376. {
  377. // What vertex would be exposed if an edge were deleted?
  378. rightcand.Lnext(ref nextedge);
  379. nextedge.Sym();
  380. nextapex = nextedge.Apex();
  381. // If nextapex is NULL, then no vertex would be exposed; the
  382. // triangulation would have been eaten right through.
  383. if (nextapex != null)
  384. {
  385. // Check whether the edge is Delaunay.
  386. badedge = predicates.InCircle(lowerleft, lowerright, upperright, nextapex) > 0.0;
  387. while (badedge)
  388. {
  389. // Eliminate the edge with an edge flip. As a result, the
  390. // right triangulation will have one more boundary triangle.
  391. nextedge.Lprev();
  392. nextedge.Sym(ref topcasing);
  393. nextedge.Lprev();
  394. nextedge.Sym(ref sidecasing);
  395. nextedge.Bond(ref topcasing);
  396. rightcand.Bond(ref sidecasing);
  397. rightcand.Lprev();
  398. rightcand.Sym(ref outercasing);
  399. nextedge.Lnext();
  400. nextedge.Bond(ref outercasing);
  401. // Correct the vertices to reflect the edge flip.
  402. rightcand.SetOrg(null);
  403. rightcand.SetDest(lowerright);
  404. rightcand.SetApex(nextapex);
  405. nextedge.SetOrg(upperright);
  406. nextedge.SetDest(null);
  407. nextedge.SetApex(nextapex);
  408. // Consider the newly exposed vertex.
  409. upperright = nextapex;
  410. // What vertex would be exposed if another edge were deleted?
  411. sidecasing.Copy(ref nextedge);
  412. nextapex = nextedge.Apex();
  413. if (nextapex != null)
  414. {
  415. // Check whether the edge is Delaunay.
  416. badedge = predicates.InCircle(lowerleft, lowerright, upperright, nextapex) > 0.0;
  417. }
  418. else
  419. {
  420. // Avoid eating right through the triangulation.
  421. badedge = false;
  422. }
  423. }
  424. }
  425. }
  426. if (leftfinished || (!rightfinished &&
  427. (predicates.InCircle(upperleft, lowerleft, lowerright, upperright) > 0.0)))
  428. {
  429. // Knit the triangulations, adding an edge from 'lowerleft'
  430. // to 'upperright'.
  431. baseedge.Bond(ref rightcand);
  432. rightcand.Lprev(ref baseedge);
  433. baseedge.SetDest(lowerleft);
  434. lowerright = upperright;
  435. baseedge.Sym(ref rightcand);
  436. upperright = rightcand.Apex();
  437. }
  438. else
  439. {
  440. // Knit the triangulations, adding an edge from 'upperleft'
  441. // to 'lowerright'.
  442. baseedge.Bond(ref leftcand);
  443. leftcand.Lnext(ref baseedge);
  444. baseedge.SetOrg(lowerright);
  445. lowerleft = upperleft;
  446. baseedge.Sym(ref leftcand);
  447. upperleft = leftcand.Apex();
  448. }
  449. }
  450. }
  451. /// <summary>
  452. /// Recursively form a Delaunay triangulation by the divide-and-conquer method.
  453. /// </summary>
  454. /// <param name="left"></param>
  455. /// <param name="right"></param>
  456. /// <param name="axis"></param>
  457. /// <param name="farleft"></param>
  458. /// <param name="farright"></param>
  459. /// <remarks>
  460. /// Recursively breaks down the problem into smaller pieces, which are
  461. /// knitted together by mergehulls(). The base cases (problems of two or
  462. /// three vertices) are handled specially here.
  463. ///
  464. /// On completion, 'farleft' and 'farright' are bounding triangles such that
  465. /// the origin of 'farleft' is the leftmost vertex (breaking ties by
  466. /// choosing the highest leftmost vertex), and the destination of
  467. /// 'farright' is the rightmost vertex (breaking ties by choosing the
  468. /// lowest rightmost vertex).
  469. /// </remarks>
  470. void DivconqRecurse(int left, int right, int axis,
  471. ref Otri farleft, ref Otri farright)
  472. {
  473. Otri midtri = default(Otri);
  474. Otri tri1 = default(Otri);
  475. Otri tri2 = default(Otri);
  476. Otri tri3 = default(Otri);
  477. Otri innerleft = default(Otri), innerright = default(Otri);
  478. double area;
  479. int vertices = right - left + 1;
  480. int divider;
  481. if (vertices == 2)
  482. {
  483. // The triangulation of two vertices is an edge. An edge is
  484. // represented by two bounding triangles.
  485. mesh.MakeTriangle(ref farleft);
  486. farleft.SetOrg(sortarray[left]);
  487. farleft.SetDest(sortarray[left + 1]);
  488. // The apex is intentionally left NULL.
  489. mesh.MakeTriangle(ref farright);
  490. farright.SetOrg(sortarray[left + 1]);
  491. farright.SetDest(sortarray[left]);
  492. // The apex is intentionally left NULL.
  493. farleft.Bond(ref farright);
  494. farleft.Lprev();
  495. farright.Lnext();
  496. farleft.Bond(ref farright);
  497. farleft.Lprev();
  498. farright.Lnext();
  499. farleft.Bond(ref farright);
  500. // Ensure that the origin of 'farleft' is sortarray[0].
  501. farright.Lprev(ref farleft);
  502. return;
  503. }
  504. else if (vertices == 3)
  505. {
  506. // The triangulation of three vertices is either a triangle (with
  507. // three bounding triangles) or two edges (with four bounding
  508. // triangles). In either case, four triangles are created.
  509. mesh.MakeTriangle(ref midtri);
  510. mesh.MakeTriangle(ref tri1);
  511. mesh.MakeTriangle(ref tri2);
  512. mesh.MakeTriangle(ref tri3);
  513. area = predicates.CounterClockwise(sortarray[left], sortarray[left + 1], sortarray[left + 2]);
  514. if (area == 0.0)
  515. {
  516. // Three collinear vertices; the triangulation is two edges.
  517. midtri.SetOrg(sortarray[left]);
  518. midtri.SetDest(sortarray[left + 1]);
  519. tri1.SetOrg(sortarray[left + 1]);
  520. tri1.SetDest(sortarray[left]);
  521. tri2.SetOrg(sortarray[left + 2]);
  522. tri2.SetDest(sortarray[left + 1]);
  523. tri3.SetOrg(sortarray[left + 1]);
  524. tri3.SetDest(sortarray[left + 2]);
  525. // All apices are intentionally left NULL.
  526. midtri.Bond(ref tri1);
  527. tri2.Bond(ref tri3);
  528. midtri.Lnext();
  529. tri1.Lprev();
  530. tri2.Lnext();
  531. tri3.Lprev();
  532. midtri.Bond(ref tri3);
  533. tri1.Bond(ref tri2);
  534. midtri.Lnext();
  535. tri1.Lprev();
  536. tri2.Lnext();
  537. tri3.Lprev();
  538. midtri.Bond(ref tri1);
  539. tri2.Bond(ref tri3);
  540. // Ensure that the origin of 'farleft' is sortarray[0].
  541. tri1.Copy(ref farleft);
  542. // Ensure that the destination of 'farright' is sortarray[2].
  543. tri2.Copy(ref farright);
  544. }
  545. else
  546. {
  547. // The three vertices are not collinear; the triangulation is one
  548. // triangle, namely 'midtri'.
  549. midtri.SetOrg(sortarray[left]);
  550. tri1.SetDest(sortarray[left]);
  551. tri3.SetOrg(sortarray[left]);
  552. // Apices of tri1, tri2, and tri3 are left NULL.
  553. if (area > 0.0)
  554. {
  555. // The vertices are in counterclockwise order.
  556. midtri.SetDest(sortarray[left + 1]);
  557. tri1.SetOrg(sortarray[left + 1]);
  558. tri2.SetDest(sortarray[left + 1]);
  559. midtri.SetApex(sortarray[left + 2]);
  560. tri2.SetOrg(sortarray[left + 2]);
  561. tri3.SetDest(sortarray[left + 2]);
  562. }
  563. else
  564. {
  565. // The vertices are in clockwise order.
  566. midtri.SetDest(sortarray[left + 2]);
  567. tri1.SetOrg(sortarray[left + 2]);
  568. tri2.SetDest(sortarray[left + 2]);
  569. midtri.SetApex(sortarray[left + 1]);
  570. tri2.SetOrg(sortarray[left + 1]);
  571. tri3.SetDest(sortarray[left + 1]);
  572. }
  573. // The topology does not depend on how the vertices are ordered.
  574. midtri.Bond(ref tri1);
  575. midtri.Lnext();
  576. midtri.Bond(ref tri2);
  577. midtri.Lnext();
  578. midtri.Bond(ref tri3);
  579. tri1.Lprev();
  580. tri2.Lnext();
  581. tri1.Bond(ref tri2);
  582. tri1.Lprev();
  583. tri3.Lprev();
  584. tri1.Bond(ref tri3);
  585. tri2.Lnext();
  586. tri3.Lprev();
  587. tri2.Bond(ref tri3);
  588. // Ensure that the origin of 'farleft' is sortarray[0].
  589. tri1.Copy(ref farleft);
  590. // Ensure that the destination of 'farright' is sortarray[2].
  591. if (area > 0.0)
  592. {
  593. tri2.Copy(ref farright);
  594. }
  595. else
  596. {
  597. farleft.Lnext(ref farright);
  598. }
  599. }
  600. return;
  601. }
  602. else
  603. {
  604. // Split the vertices in half.
  605. divider = vertices >> 1;
  606. // Recursively triangulate each half.
  607. DivconqRecurse(left, left + divider - 1, 1 - axis, ref farleft, ref innerleft);
  608. DivconqRecurse(left + divider, right, 1 - axis, ref innerright, ref farright);
  609. // Merge the two triangulations into one.
  610. MergeHulls(ref farleft, ref innerleft, ref innerright, ref farright, axis);
  611. }
  612. }
  613. /// <summary>
  614. /// Removes ghost triangles.
  615. /// </summary>
  616. /// <param name="startghost"></param>
  617. /// <returns>Number of vertices on the hull.</returns>
  618. int RemoveGhosts(ref Otri startghost)
  619. {
  620. Otri searchedge = default(Otri);
  621. Otri dissolveedge = default(Otri);
  622. Otri deadtriangle = default(Otri);
  623. Vertex markorg;
  624. int hullsize;
  625. bool noPoly = !mesh.behavior.Poly;
  626. // Find an edge on the convex hull to start point location from.
  627. startghost.Lprev(ref searchedge);
  628. searchedge.Sym();
  629. mesh.dummytri.neighbors[0] = searchedge;
  630. // Remove the bounding box and count the convex hull edges.
  631. startghost.Copy(ref dissolveedge);
  632. hullsize = 0;
  633. do
  634. {
  635. hullsize++;
  636. dissolveedge.Lnext(ref deadtriangle);
  637. dissolveedge.Lprev();
  638. dissolveedge.Sym();
  639. // If no PSLG is involved, set the boundary markers of all the vertices
  640. // on the convex hull. If a PSLG is used, this step is done later.
  641. if (noPoly)
  642. {
  643. // Watch out for the case where all the input vertices are collinear.
  644. if (dissolveedge.tri.id != Mesh.DUMMY)
  645. {
  646. markorg = dissolveedge.Org();
  647. if (markorg.label == 0)
  648. {
  649. markorg.label = 1;
  650. }
  651. }
  652. }
  653. // Remove a bounding triangle from a convex hull triangle.
  654. dissolveedge.Dissolve(mesh.dummytri);
  655. // Find the next bounding triangle.
  656. deadtriangle.Sym(ref dissolveedge);
  657. // Delete the bounding triangle.
  658. mesh.TriangleDealloc(deadtriangle.tri);
  659. }
  660. while (!dissolveedge.Equals(startghost));
  661. return hullsize;
  662. }
  663. }
  664. }