protected Triangle CalculateSupertriangle() { // Create a supertriangle which is substantially bigger than the convex plane spanned by the point set // to solve the convexity issue (problem of concave structures occuring in hull). // https://www.codeguru.com/cpp/cpp/algorithms/general/article.php/c8901/Delaunay-Triangles.htm (Point min, Point max) = CalculateBoundaryBox(); if (BuildDiagonstics) { DiagnosticGeometry.Add(new DiagnosticGeometry(DiagGeometryType.Line, DiagColor.Red, min, new Point(min.X, max.Y), new Point(max.X, max.Y), new Point(max.X, max.Y), new Point(max.X, min.Y), min)); } // Create supertriangle var dMax = Math.Max(max.X - min.X, max.Y - min.Y); var xMid = (max.X + min.X) / 2; var yMid = (max.Y + min.Y) / 2; return(new Triangle( new Point(xMid - 20 * dMax, yMid - dMax), new Point(xMid, yMid + 20 * dMax), new Point(xMid + 20 * dMax, yMid - dMax) )); }
protected (Point, Triangle) CalculateOriginSeedTriangle(out int idx1, out int idx2, out int idx3) { idx1 = -1; idx2 = -1; idx3 = -1; // Calculate origin point (Point min, Point max) = CalculateBoundaryBox(); var origin = new Point((min.X + max.X) / 2, (min.Y + max.Y) / 2); // Find first seed point closest to origin { var minDist = double.MaxValue; for (var i = 0; i < Points.Length; i++) { var dist = GeoMath.EuclideanDistance2(Points[i], origin); if (dist < minDist) { idx1 = i; minDist = dist; } } } // Find point closest to seed point { var minDist = double.MaxValue; for (var i = 0; i < Points.Length; i++) { if (i == idx1) { continue; } var dist = GeoMath.EuclideanDistance2(Points[i], Points[idx1]); if (dist < minDist) { idx2 = i; minDist = dist; } } } // Find point which creates the smallest circumcircle { var minCircRadius2 = double.MaxValue; for (var i = 0; i < Points.Length; i++) { if (i == idx1 || i == idx2) { continue; } var circRadius2 = GeoMath.Circumradius2(Points[idx1], Points[idx2], Points[i]); if (circRadius2 < minCircRadius2) { idx3 = i; minCircRadius2 = circRadius2; } } if (idx3 == -1) { idx1 = -1; idx2 = -1; return(new Point(), Triangle.Zero); // No Delaunay triangulation exists } } // Make sure seed triangle points are oriented counter-clockwise if (GeoMath.TriangleAreaDeterminant(Points[idx1], Points[idx2], Points[idx3]) > 0) { var tmp = idx2; idx2 = idx3; idx3 = tmp; } // Update origin to represent midpoint of seed triangle origin = GeoMath.CalculateMidpoint(Points[idx1], Points[idx2], Points[idx3]); var seed = new Triangle(Points[idx1], Points[idx2], Points[idx3]); if (BuildDiagonstics) { // Add boundary box and seed point/triangle to diagnostics DiagnosticGeometry.Add(new DiagnosticGeometry(DiagGeometryType.Line, DiagColor.Red, seed.GetEdgeA().Start, seed.GetEdgeA().End)); DiagnosticGeometry.Add(new DiagnosticGeometry(DiagGeometryType.Line, DiagColor.Red, seed.GetEdgeB().Start, seed.GetEdgeB().End)); DiagnosticGeometry.Add(new DiagnosticGeometry(DiagGeometryType.Line, DiagColor.Red, seed.GetEdgeC().Start, seed.GetEdgeC().End)); DiagnosticGeometry.Add(new DiagnosticGeometry(DiagGeometryType.Line, DiagColor.Red, min, new Point(min.X, max.Y), new Point(max.X, max.Y), new Point(max.X, max.Y), new Point(max.X, min.Y), min)); DiagnosticGeometry.Add(new DiagnosticGeometry(DiagGeometryType.Vertex, DiagColor.Red, origin)); } return(origin, seed); }