/// <summary> /// Legalizes triangles around given edge. /// </summary> private int Legalize(int a) { var b = halfedges[a]; var a0 = a - a % 3; var b0 = b - b % 3; var al = a0 + (a + 1) % 3; var ar = a0 + (a + 2) % 3; var bl = b0 + (b + 2) % 3; var p0 = triangles[ar]; var pr = triangles[a]; var pl = triangles[al]; var p1 = triangles[bl]; var illegal = GeoMath.IsPointInCircumcircle(p0.CartesianPoint, pr.CartesianPoint, pl.CartesianPoint, p1.CartesianPoint); if (illegal && b != -1) { triangles[a] = p1; triangles[b] = p0; Link(a, halfedges[bl]); Link(b, halfedges[ar]); Link(ar, bl); var br = b0 + (b + 1) % 3; Legalize(a); return(Legalize(br)); } return(ar); }
/// <summary> /// Calculates Delaunay triangulation via a naive implementation of the incremental Bowyer-Waston algorithm. /// Expected runtime is O(n²). /// </summary> /// <remarks> /// https://www.maths.tcd.ie/~martins7/Voro/Sean_Martin_Poster.pdf /// https://en.wikipedia.org/wiki/Bowyer%E2%80%93Watson_algorithm /// https://www.codeguru.com/cpp/cpp/algorithms/general/article.php/c8901/Delaunay-Triangles.htm /// https://eclass.uoa.gr/modules/document/file.php/D42/%CE%94%CE%B9%CE%B1%CF%86%CE%AC%CE%BD%CE%B5%CE%B9%CE%B5%CF%82/2a.delaunay.pdf - Slide 40+ /// </remarks> public override void CalculateDelaunay() { if (!CheckDelaunayConditions()) { return; } var triangulation = new HashSet <Triangle>(); // Start with the supertriangle, which contains all available points var supertriangle = CalculateSupertriangle(); triangulation.Add(supertriangle); // Keep a list of triangles where the point is within its circumcircle var conflictingTriangles = new List <Triangle>(); var polygonEdges = new List <Edge>(); // Incrementally add points to existing set of triangles foreach (var p in Points) { // Find triangles where given point is in its circumcircle (conflicting) foreach (var tri in triangulation) { if (GeoMath.IsPointInCircumcircle(tri, p)) { conflictingTriangles.Add(tri); // Remove neighbouring edges of conflicting triangles // Edge A var edgeA = tri.GetEdgeA(); if (polygonEdges.Contains(edgeA)) { polygonEdges.Remove(edgeA); } else { polygonEdges.Add(edgeA); } // Edge B var edgeB = tri.GetEdgeB(); if (polygonEdges.Contains(edgeB)) { polygonEdges.Remove(edgeB); } else { polygonEdges.Add(edgeB); } // Edge C var edgeC = tri.GetEdgeC(); if (polygonEdges.Contains(edgeC)) { polygonEdges.Remove(edgeC); } else { polygonEdges.Add(edgeC); } } } // Remove conflicting triangles from hashset foreach (var tri in conflictingTriangles) { triangulation.Remove(tri); } // Create new triangles by connecting all polygon vertices to the newly added vertex foreach (var edge in polygonEdges) { triangulation.Add(new Triangle(edge.Start, edge.End, p)); } conflictingTriangles.Clear(); polygonEdges.Clear(); } // Only add triangles to final triangulation result which do not share a vertex with the super-triangle var delaunay = new List <Triangle>(triangulation.Count); foreach (var tri in triangulation) { if (!supertriangle.HasVertex(tri.A) && !supertriangle.HasVertex(tri.B) && !supertriangle.HasVertex(tri.C)) { delaunay.Add(tri); } } SetDelaunayResult(delaunay); }