Incremental.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // -----------------------------------------------------------------------
  2. // <copyright file="Incremental.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.Collections.Generic;
  11. using Animation.TriangleNet.Topology;
  12. using Animation.TriangleNet.Geometry;
  13. /// <summary>
  14. /// Builds a delaunay triangulation using the incremental algorithm.
  15. /// </summary>
  16. internal class Incremental : ITriangulator
  17. {
  18. Mesh mesh;
  19. /// <summary>
  20. /// Form a Delaunay triangulation by incrementally inserting vertices.
  21. /// </summary>
  22. /// <returns>Returns the number of edges on the convex hull of the
  23. /// triangulation.</returns>
  24. public IMesh Triangulate(IList<Vertex> points, Configuration config)
  25. {
  26. this.mesh = new Mesh(config);
  27. this.mesh.TransferNodes(points);
  28. Otri starttri = new Otri();
  29. // Create a triangular bounding box.
  30. GetBoundingBox();
  31. foreach (var v in mesh.vertices.Values)
  32. {
  33. starttri.tri = mesh.dummytri;
  34. Osub tmp = default(Osub);
  35. if (mesh.InsertVertex(v, ref starttri, ref tmp, false, false) == InsertVertexResult.Duplicate)
  36. {
  37. if (Log.Verbose)
  38. {
  39. Log.Instance.Warning("A duplicate vertex appeared and was ignored.",
  40. "Incremental.Triangulate()");
  41. }
  42. v.type = VertexType.UndeadVertex;
  43. mesh.undeads++;
  44. }
  45. }
  46. // Remove the bounding box.
  47. this.mesh.hullsize = RemoveBox();
  48. return this.mesh;
  49. }
  50. /// <summary>
  51. /// Form an "infinite" bounding triangle to insert vertices into.
  52. /// </summary>
  53. /// <remarks>
  54. /// The vertices at "infinity" are assigned finite coordinates, which are
  55. /// used by the point location routines, but (mostly) ignored by the
  56. /// Delaunay edge flip routines.
  57. /// </remarks>
  58. void GetBoundingBox()
  59. {
  60. Otri inftri = default(Otri); // Handle for the triangular bounding box.
  61. Rectangle box = mesh.bounds;
  62. // Find the width (or height, whichever is larger) of the triangulation.
  63. double width = box.Width;
  64. if (box.Height > width)
  65. {
  66. width = box.Height;
  67. }
  68. if (width == 0.0)
  69. {
  70. width = 1.0;
  71. }
  72. // Create the vertices of the bounding box.
  73. mesh.infvertex1 = new Vertex(box.Left - 50.0 * width, box.Bottom - 40.0 * width);
  74. mesh.infvertex2 = new Vertex(box.Right + 50.0 * width, box.Bottom - 40.0 * width);
  75. mesh.infvertex3 = new Vertex(0.5 * (box.Left + box.Right), box.Top + 60.0 * width);
  76. // Create the bounding box.
  77. mesh.MakeTriangle(ref inftri);
  78. inftri.SetOrg(mesh.infvertex1);
  79. inftri.SetDest(mesh.infvertex2);
  80. inftri.SetApex(mesh.infvertex3);
  81. // Link dummytri to the bounding box so we can always find an
  82. // edge to begin searching (point location) from.
  83. mesh.dummytri.neighbors[0] = inftri;
  84. }
  85. /// <summary>
  86. /// Remove the "infinite" bounding triangle, setting boundary markers as appropriate.
  87. /// </summary>
  88. /// <returns>Returns the number of edges on the convex hull of the triangulation.</returns>
  89. /// <remarks>
  90. /// The triangular bounding box has three boundary triangles (one for each
  91. /// side of the bounding box), and a bunch of triangles fanning out from
  92. /// the three bounding box vertices (one triangle for each edge of the
  93. /// convex hull of the inner mesh). This routine removes these triangles.
  94. /// </remarks>
  95. int RemoveBox()
  96. {
  97. Otri deadtriangle = default(Otri);
  98. Otri searchedge = default(Otri);
  99. Otri checkedge = default(Otri);
  100. Otri nextedge = default(Otri), finaledge = default(Otri), dissolveedge = default(Otri);
  101. Vertex markorg;
  102. int hullsize;
  103. bool noPoly = !mesh.behavior.Poly;
  104. // Find a boundary triangle.
  105. nextedge.tri = mesh.dummytri;
  106. nextedge.orient = 0;
  107. nextedge.Sym();
  108. // Mark a place to stop.
  109. nextedge.Lprev(ref finaledge);
  110. nextedge.Lnext();
  111. nextedge.Sym();
  112. // Find a triangle (on the boundary of the vertex set) that isn't
  113. // a bounding box triangle.
  114. nextedge.Lprev(ref searchedge);
  115. searchedge.Sym();
  116. // Check whether nextedge is another boundary triangle
  117. // adjacent to the first one.
  118. nextedge.Lnext(ref checkedge);
  119. checkedge.Sym();
  120. if (checkedge.tri.id == Mesh.DUMMY)
  121. {
  122. // Go on to the next triangle. There are only three boundary
  123. // triangles, and this next triangle cannot be the third one,
  124. // so it's safe to stop here.
  125. searchedge.Lprev();
  126. searchedge.Sym();
  127. }
  128. // Find a new boundary edge to search from, as the current search
  129. // edge lies on a bounding box triangle and will be deleted.
  130. mesh.dummytri.neighbors[0] = searchedge;
  131. hullsize = -2;
  132. while (!nextedge.Equals(finaledge))
  133. {
  134. hullsize++;
  135. nextedge.Lprev(ref dissolveedge);
  136. dissolveedge.Sym();
  137. // If not using a PSLG, the vertices should be marked now.
  138. // (If using a PSLG, markhull() will do the job.)
  139. if (noPoly)
  140. {
  141. // Be careful! One must check for the case where all the input
  142. // vertices are collinear, and thus all the triangles are part of
  143. // the bounding box. Otherwise, the setvertexmark() call below
  144. // will cause a bad pointer reference.
  145. if (dissolveedge.tri.id != Mesh.DUMMY)
  146. {
  147. markorg = dissolveedge.Org();
  148. if (markorg.label == 0)
  149. {
  150. markorg.label = 1;
  151. }
  152. }
  153. }
  154. // Disconnect the bounding box triangle from the mesh triangle.
  155. dissolveedge.Dissolve(mesh.dummytri);
  156. nextedge.Lnext(ref deadtriangle);
  157. deadtriangle.Sym(ref nextedge);
  158. // Get rid of the bounding box triangle.
  159. mesh.TriangleDealloc(deadtriangle.tri);
  160. // Do we need to turn the corner?
  161. if (nextedge.tri.id == Mesh.DUMMY)
  162. {
  163. // Turn the corner.
  164. dissolveedge.Copy(ref nextedge);
  165. }
  166. }
  167. mesh.TriangleDealloc(finaledge.tri);
  168. return hullsize;
  169. }
  170. }
  171. }