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)
                       ));
        }
示例#2
0
        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);
        }