예제 #1
0
 public static double dotProduct(this double[] b, PointLight a)
 {
     return(a.X * b[0] + a.Y * b[1]);
 }
예제 #2
0
파일: Silhouette.cs 프로젝트: PeterZs/TVGL
        private static List <List <PointLight> > EliminateOverhangPolygons(List <List <PointLight> > nonSelfIntersectingPaths,
                                                                           Dictionary <int, List <PointLight> > projectedFacePolygons)
        {
            var correctedSurfacePath = new List <List <PointLight> >();
            var negativePaths        = new List <List <PointLight> >();

            foreach (var path in nonSelfIntersectingPaths)
            {
                if (path.Count < 3)
                {
                    continue;                 //Don't include lines. It must be a valid polygon.
                }
                //If the area is negative, we need to check if it is a hole or an overhang
                //If it is an overhang, we ignore it. An overhang exists if any the points
                //in the path are inside any of the positive faces touching the path
                var area2D = MiscFunctions.AreaOfPolygon(path);
                if (Math.Sign(area2D) > 0)
                {
                    correctedSurfacePath.Add(path);
                }
                else
                {
                    negativePaths.Add(path);
                }
            }

            foreach (var path in negativePaths)
            {
                var isHoleCounter1     = 0;
                var isOverhangCounter1 = 0;
                //Get all the adjacent faces on this surface
                //We need to check the face centers with the surface path.
                //If any adjacent face centers are inside the surface path, then it is an overhang
                //Note: regardless of whether the face is further than the loop in question or
                //before, being inside the loop is enough to say that it is not a hole.
                if (path.Count > 3)
                {
                    //Presenter.ShowAndHang(path);
                    //Presenter.ShowVertexPathsWithSolid(new List<List<List<Vertex>>> { loops },
                    //    new List<TessellatedSolid> { originalSolid });
                }

                var polygons = new HashSet <List <PointLight> >(projectedFacePolygons.Values);

                //Get a few points that are inside the polygon (It is non-self intersecting,
                //but taking the center may not work.)
                var pathCenterX        = path.Average(v => v.X);
                var pathCenterY        = path.Average(v => v.Y);
                var centerPoint        = new PointLight(pathCenterX, pathCenterY);
                var centerPointIsValid = false;
                if (MiscFunctions.IsPointInsidePolygon(path, centerPoint, false))
                {
                    //A negative polygon may be inside of a positive polygon without issue, however,
                    //If there is a negative polygon inside a negative polygon an issue may arise.
                    //So we need to check to make sure this point is not inside any of the other negative polgyons.
                    if (negativePaths.Count == 1)
                    {
                        centerPointIsValid = true;
                    }
                    else
                    {
                        centerPointIsValid = negativePaths.Where(otherPath => otherPath != path).Any(otherPath =>
                                                                                                     MiscFunctions.IsPointInsidePolygon(path, centerPoint, true));
                    }
                }

                if (centerPointIsValid)
                {
                    //Great! We have an easy point that is inside. Check if it is inside any surface polygon
                }
                else
                {
                    //Get a point that is inside the polygon. We could set up a sweep line to do this,
                    //but for now I'm taking an easier approach (take average of three random points)
                    //Use the overload of the Random constructor which accepts a seed value, so that this is repeatable
                    var rnd   = new Random(0);
                    var count = 0;
                    while (!centerPointIsValid && count < 1000)
                    {
                        var r1 = rnd.Next(path.Count);
                        var r2 = rnd.Next(path.Count);
                        var r3 = rnd.Next(path.Count);
                        while (r1 == r2)
                        {
                            //Get a new r2
                            r2 = rnd.Next(path.Count);
                        }
                        while (r3 == r2 || r3 == r1)
                        {
                            //Get a new r3
                            r3 = rnd.Next(path.Count);
                        }
                        var p1        = path[r1];
                        var p2        = path[r2];
                        var p3        = path[r3];
                        var centerX   = (p1.X + p2.X + p3.X) / 3;
                        var centerY   = (p1.Y + p2.Y + p3.Y) / 3;
                        var newCenter = new PointLight(centerX, centerY);
                        if (MiscFunctions.IsPointInsidePolygon(path, newCenter, false))
                        {
                            centerPoint = newCenter;

                            //A negative polygon may be inside of a positive polygon without issue, however,
                            //If there is a negative polygon inside a negative polygon an issue may arise.
                            //So we need to check to make sure this point is not inside any of the other negative polgyons.
                            if (negativePaths.Count == 1)
                            {
                                centerPointIsValid = true;
                            }
                            else
                            {
                                centerPointIsValid = negativePaths.Where(otherPath => otherPath != path).Any(otherPath =>
                                                                                                             MiscFunctions.IsPointInsidePolygon(path, newCenter, true));
                            }
                        }
                        count++;
                    }
                    if (count == 1000)
                    {
                        //Presenter.ShowAndHang(negativePaths);
                        throw new Exception("Not able to find a point inside polygon");
                    }
                }

                if (polygons.Any(p => MiscFunctions.IsPointInsidePolygon(p, centerPoint, true)))
                {
                    //This is an overhang
                    //path.Reverse();
                    //correctedSurfacePath.Add(path);
                }
                else
                {
                    //This is a hole
                    correctedSurfacePath.Add(path);
                }
            }
            return(correctedSurfacePath);
        }
예제 #3
0
 /// <inheritdoc />
 /// <summary>
 ///     Initializes a new instance of the <see cref="T:TVGL.Point" /> class.
 /// </summary>
 public Point(PointLight p)
     : this(null, p.X, p.Y, 0.0)
 {
 }
        private void ExpandHorizontally(PointLight lastPoint, PointLight fromPoint, PointLight toPoint, double[,] grid, int iMin, int iMax, int jMin, int jMax)
        {
            var segment = toPoint - fromPoint;

            if (segment[1].IsNegligible(1e-9))
            {
                return;
            }
            var segmentHalfWidth    = 0.5 * segment[0];
            var magnitude           = Math.Sqrt(segment[0] * segment[0] + segment[1] * segment[1]);
            var lastSegment         = fromPoint - lastPoint;
            var convexSign          = Math.Sign(StarMath.crossProduct2(lastSegment, segment));
            var xStart              = fromPoint.X + segmentHalfWidth;
            var iStart              = (int)((xStart - _xMin) * coordToGridFactor);
            var numStepsInHalfWidth = (int)(segmentHalfWidth * coordToGridFactor) + 1;
            var d      = new[] { segment[1] / magnitude, -segment[0] / magnitude }; //unit vector along the band
            var yDelta = (toPoint.Y > fromPoint.Y) ? -1 : +1;

            for (int xDelta = -1; xDelta <= 1; xDelta += 2)
            { //first backward, then forward
                var i = iStart;
                if (xDelta > 0)
                {
                    i++;
                }
                var  numSteps = 0;
                bool atLeastOneSuccessfulChange;
                do
                {  // outer x loop
                    atLeastOneSuccessfulChange = false;
                    numSteps++;
                    if (i < iMin || i >= iMax)
                    {
                        break;
                    }
                    var x = i * gridToCoordinateFactor + _xMin;
                    var y = toPoint.Y + d[1] * (x - toPoint.X) / d[0];
                    var j = (int)((y - _yMin) * coordToGridFactor);
                    while (true)
                    { //inner y loop
                        if ((yDelta > 0 && j >= jMax) || (yDelta < 0 && j < jMin))
                        {
                            break;
                        }
                        if ((yDelta <= 0 || j >= jMin) && (yDelta >= 0 || j < jMax))
                        {
                            var p     = new PointLight(x, j * gridToCoordinateFactor + _yMin);
                            var vFrom = p - fromPoint;
                            var t     = d.dotProduct(vFrom, 2);
                            if (segment.dotProduct(vFrom, 2) >= 0) //then in the band of the extruded edge
                            {
                                if (Math.Sign(t) * t < Math.Sign(t) * grid[i, j])
                                {
                                    grid[i, j] = t;
                                    atLeastOneSuccessfulChange = true;
                                }
                            }
                            else if (lastSegment.dotProduct(vFrom, 2) >= 0)
                            {
                                var distance = Math.Sqrt(vFrom[0] * vFrom[0] + vFrom[1] * vFrom[1]);
                                if (distance < convexSign * grid[i, j])
                                {
                                    grid[i, j] = convexSign * distance;
                                    atLeastOneSuccessfulChange = true;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                        j += yDelta;
                    }
                    i += xDelta;
                } while (atLeastOneSuccessfulChange || numSteps <= numStepsInHalfWidth);
            }
            if (lastSegment[1] * segment[1] < 0) // then it is possible there are additional points around the corner that need
                                                 //to be evaluated
            {
                if (Math.Abs(lastSegment[0]) < Math.Abs(lastSegment[1]))
                {
                    ExpandLastCornerHorizontally(fromPoint, lastSegment, grid, iMin, iMax, jMin, jMax, convexSign);
                }
                else
                {
                    ExpandLastCornerVertically(fromPoint, lastSegment, grid, iMin, iMax, jMin, jMax, convexSign);
                }
            }
        }
        private void ExpandVertically(PointLight lastPoint, PointLight fromPoint, PointLight toPoint, double[,] grid, int iMin, int iMax, int jMin, int jMax)
        {
            var segment = toPoint - fromPoint;

            if (segment[0].IsNegligible(1e-9))
            {
                return;
            }
            var segmentHalfHeight    = 0.5 * segment[1];
            var magnitude            = Math.Sqrt(segment[0] * segment[0] + segment[1] * segment[1]);
            var lastSegment          = fromPoint - lastPoint;
            var convexSign           = Math.Sign(StarMath.crossProduct2(lastSegment, segment));
            var yStart               = fromPoint.Y + segmentHalfHeight;
            var jStart               = (int)((yStart - _yMin) * coordToGridFactor);
            var numStepsInHalfHeight = (int)(segmentHalfHeight * coordToGridFactor) + 1;
            var d      = new[] { segment[1] / magnitude, -segment[0] / magnitude }; //unit vector along the band
            var xDelta = (toPoint.X > fromPoint.X) ? -1 : +1;

            for (int yDelta = -1; yDelta <= 1; yDelta += 2)
            { //first backward, then forward
                var j = jStart;
                if (yDelta > 0)
                {
                    j++;
                }
                var  numSteps = 0;
                bool atLeastOneSuccessfulChange;
                do
                {  // outer x loop
                    atLeastOneSuccessfulChange = false;
                    numSteps++;
                    if (j < jMin || j >= jMax)
                    {
                        break;
                    }
                    var y = j * gridToCoordinateFactor + _yMin;
                    var x = toPoint.X + d[0] * (y - toPoint.Y) / d[1];
                    var i = (int)((x - _xMin) * coordToGridFactor);
                    while (true)
                    { //inner y loop
                        if ((xDelta > 0 && i >= iMax) || (xDelta < 0 && i < iMin))
                        {
                            break;
                        }
                        if ((xDelta <= 0 || i >= iMin) && (xDelta >= 0 || i < iMax))
                        {
                            var p     = new PointLight(i * gridToCoordinateFactor + _xMin, y);
                            var vFrom = p - fromPoint;
                            var t     = d.dotProduct(vFrom, 2);
                            if (segment.dotProduct(vFrom, 2) >= 0) //then in the band of the extruded edge
                            {
                                if (Math.Sign(t) * t < Math.Sign(t) * grid[i, j])
                                {
                                    grid[i, j] = t;
                                    atLeastOneSuccessfulChange = true;
                                }
                            }
                            else if (lastSegment.dotProduct(vFrom, 2) >= 0)
                            {
                                var distance = Math.Sqrt(vFrom[0] * vFrom[0] + vFrom[1] * vFrom[1]);
                                if (distance < convexSign * grid[i, j])
                                {
                                    grid[i, j] = convexSign * distance;
                                    atLeastOneSuccessfulChange = true;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                        i += xDelta;
                    }
                    j += yDelta;
                } while (atLeastOneSuccessfulChange || numSteps <= numStepsInHalfHeight);
            }
        }
예제 #6
0
            /// <summary>
            ///     Create a new circle from 3 points
            /// </summary>
            /// <param name="p0"></param>
            /// <param name="p1"></param>
            /// <param name="p2"></param>
            internal InternalCircle(PointLight p0, PointLight p1, PointLight p2)
            {
                NumPointsDefiningCircle = 3;
                Point0 = p0;
                Point1 = p1;
                Point2 = p2;
                var point0X = Point0.X;
                var point0Y = Point0.Y;
                var point1X = Point1.X;
                var point1Y = Point1.Y;
                var point2X = Point2.X;
                var point2Y = Point2.Y;

                //Find Circle center and radius
                //Assume NO two points are exactly the same
                var    rise1 = point1Y - point0Y;
                var    run1  = point1X - point0X;
                var    rise2 = point2Y - point1Y;
                var    run2  = point2X - point1X;
                double x;
                double y;

                //Check for special cases of vertical or horizontal lines
                if (rise1.IsNegligible(Constants.BaseTolerance)) //If rise is zero, x can be found directly
                {
                    x = (point0X + point1X) / 2;
                    //If run of other line is approximately zero as well, y can be found directly
                    if (run2.IsNegligible(Constants.BaseTolerance))
                    //If run is approximately zero, y can be found directly
                    {
                        y = (point1Y + point2Y) / 2;
                    }
                    else
                    {
                        //Find perpendicular slope, and midpoint of line 2.
                        //Then use the midpoint to find "b" and solve y = mx+b
                        //This is condensed into a single line because VS rounds the numbers
                        //during division.
                        y = (point1Y + point2Y) / 2 + -run2 / rise2 * (x - (point1X + point2X) / 2);
                    }
                }
                else if (rise2.IsNegligible(Constants.BaseTolerance))
                //If rise is approximately zero, x can be found directly
                {
                    x = (point1X + point2X) / 2;
                    //If run of other line is approximately zero as well, y can be found directly
                    if (run1.IsNegligible(Constants.BaseTolerance))
                    //If run is approximately zero, y can be found directly
                    {
                        y = (point0Y + point1Y) / 2;
                    }
                    else
                    {
                        //Find perpendicular slope, and midpoint of line 2.
                        //Then use the midpoint to find "b" and solve y = mx+b
                        //This is condensed into a single line because VS rounds the numbers
                        //during division.
                        y = (point0Y + point1Y) / 2 + -run1 / rise1 * (x - (point0X + point1X) / 2);
                    }
                }
                else if (run1.IsNegligible(Constants.BaseTolerance))
                //If run is approximately zero, y can be found directly
                {
                    y = (point0Y + point1Y) / 2;
                    //Find perpendicular slope, and midpoint of line 2.
                    //Then use the midpoint to find "b" and solve y = mx+b
                    //This is condensed into a single line because VS rounds the numbers
                    //during division.
                    x = (y - ((point1Y + point2Y) / 2 - -run2 / rise2 *
                              (point1X + point2X) / 2)) / (-run2 / rise2);
                }
                else if (run2.IsNegligible(Constants.BaseTolerance))
                //If run is approximately zero, y can be found directly
                {
                    y = (point1Y + point2Y) / 2;
                    //Find perpendicular slope, and midpoint of line 2.
                    //Then use the midpoint to find "b" and solve y = mx+b
                    //This is condensed into a single line because VS rounds the numbers
                    //during division.
                    x = (y - ((point1Y + point0Y) / 2 - -run1 / rise1 *
                              (point1X + point0X) / 2)) / (-run1 / rise1);
                }
                else
                {
                    //Didn't solve for slopes first because of rounding error in division
                    //ToDo: This does not always find a good center. Figure out why.
                    x = (rise1 / run1 * (rise2 / run2) * (point2Y - point0Y) +
                         rise1 / run1 * (point1X + point2X) -
                         rise2 / run2 * (point0X + point1X)) / (2 * (rise1 / run1 - rise2 / run2));
                    y = -(1 / (rise1 / run1)) * (x - (point0X + point1X) / 2) +
                        (point0Y + point1Y) / 2;
                }

                var dx = x - point0X;
                var dy = y - point0Y;

                CenterX  = x;
                CenterY  = y;
                SqRadius = dx * dx + dy * dy;
            }
예제 #7
0
            /// <summary>
            ///     Finds the furthest the specified point.
            /// </summary>
            /// <param name="point">The point.</param>
            /// <param name="furthestPoint">The furthest point.</param>
            /// <param name="previousPoint1"></param>
            /// <param name="previousPoint2"></param>
            /// <exception cref="ArgumentNullException">previousPoints cannot be null</exception>
            internal void Furthest(PointLight point, out PointLight furthestPoint, out PointLight previousPoint1, out PointLight previousPoint2, out int numPreviousPoints)
            {
                //Distance between point and center is greater than radius, it is outside the circle
                //DO P0, then P1, then P2
                numPreviousPoints = (NumPointsDefiningCircle == 3) ? 2 : 1;
                previousPoint2    = _dummyPoint;
                var p0SquareDistance = Math.Pow(Point0.X - point.X, 2) + Math.Pow(Point0.Y - point.Y, 2);
                var p1SquareDistance = Math.Pow(Point1.X - point.X, 2) + Math.Pow(Point1.Y - point.Y, 2);

                if (p0SquareDistance > p1SquareDistance)
                {
                    previousPoint1 = Point1;
                    if (NumPointsDefiningCircle == 3)
                    {
                        var p2SquareDistance = Math.Pow(Point2.X - point.X, 2) + Math.Pow(Point2.Y - point.Y, 2);
                        if (p0SquareDistance > p2SquareDistance)
                        {
                            furthestPoint  = Point0;
                            previousPoint2 = Point2;
                        }
                        else
                        {
                            //If P2 > P0 and P0 > P1, P2 must also be greater than P1.
                            furthestPoint  = Point2;
                            previousPoint2 = Point0;
                        }
                    }
                    else
                    {
                        furthestPoint = Point0;
                    }
                }
                else
                {
                    previousPoint1 = Point0;
                    if (NumPointsDefiningCircle == 3)
                    {
                        var p2SquareDistance = Math.Pow(Point2.X - point.X, 2) + Math.Pow(Point2.Y - point.Y, 2);
                        if (p1SquareDistance > p2SquareDistance)
                        {
                            furthestPoint  = Point1;
                            previousPoint2 = Point2;
                        }
                        else
                        {
                            furthestPoint  = Point2;
                            previousPoint2 = Point1;
                        }
                    }
                    else
                    {
                        furthestPoint = Point1;
                    }
                }
            }
예제 #8
0
        /// <summary>
        ///     Finds the minimum bounding circle
        /// </summary>
        /// <param name="points">The points.</param>
        /// <returns>System.Double.</returns>
        /// <exception cref="Exception">Bounding circle failed to converge</exception>
        /// <references>
        ///     Based on Emo Welzl's "move-to-front heuristic" and this paper (algorithm 1).
        ///     http://www.inf.ethz.ch/personal/gaertner/texts/own_work/esa99_final.pdf
        ///     This algorithm runs in near linear time. Visiting most points just a few times.
        ///     Though a linear algorithm was found by Meggi do, this algorithm is more robust
        ///     (doesn't care about multiple points on a line and fewer rounding functions)
        ///     and directly applicable to multiple dimensions (in our case, just 2 and 3 D).
        /// </references>
        public static BoundingCircle MinimumCircle(IList <PointLight> points)
        {
            #region Algorithm 1

            ////Randomize the list of points
            //var r = new Random();
            //var randomPoints = new List<PointLight>(points.OrderBy(p => r.Next()));

            //if (randomPoints.Count < 2) return new BoundingCircle(0.0, points[0]);
            ////Get any two points in the list points.
            //var point1 = randomPoints[0];
            //var point2 = randomPoints[1];
            //var previousPoints = new HashSet<PointLight>();
            //var circle = new InternalCircle(point1, point2);
            //var stallCounter = 0;
            //var i = 0;

            //while (i < randomPoints.Count && stallCounter < points.Count * 2)
            //{
            //    var currentPoint = randomPoints[i];
            //    //If the current point is part of the circle or inside the circle, go to the next iteration
            //    if (circle.Point0.Equals(currentPoint) ||
            //        circle.Point1.Equals(currentPoint) ||
            //        circle.Point2.Equals(currentPoint) ||
            //        circle.IsPointInsideCircle(currentPoint))
            //    {
            //        i++;
            //        continue;
            //    }

            //    //Else if the currentPoint is a previousPoint, increase dimension
            //    if (previousPoints.Contains(currentPoint))
            //    {
            //        //Make a new circle from the current two-point circle and the current point
            //        circle = new InternalCircle(circle.Point0, circle.Point1, currentPoint);
            //        previousPoints.Remove(currentPoint);
            //        i++;
            //    }
            //    else
            //    {
            //        //Find the point in the circle furthest from new point.
            //        circle.Furthest(currentPoint, out var furthestPoint, ref previousPoints);
            //        //Make a new circle from the furthest point and current point
            //        circle = new InternalCircle(currentPoint, furthestPoint);
            //        //Add previousPoints to the front of the list
            //        foreach (var previousPoint in previousPoints)
            //        {
            //            randomPoints.Remove(previousPoint);
            //            randomPoints.Insert(0, previousPoint);
            //        }
            //        //Restart the search
            //        stallCounter++;
            //        i = 0;
            //    }
            //}

            #endregion

            #region Algorithm 2: Furthest Point
            //var r = new Random();
            //var randomPoints = new List<PointLight>(points.OrderBy(p => r.Next()));

            //Algorithm 2
            //I tried using the extremes (X, Y, and also tried Sum, Diff) to do a first pass at the circle
            //or to define the starting circle for max dX or dY, but all of these were slower do to the extra
            //for loop at the onset. The current approach is faster and simpler; just start with some arbitrary points.
            var circle       = new InternalCircle(points[0], points[points.Count / 2]);
            var dummyPoint   = new PointLight(double.NaN, double.NaN);
            var stallCounter = 0;
            var successful   = false;
            var stallLimit   = points.Count * 1.5;
            if (stallLimit < 100)
            {
                stallLimit = 100;
            }
            var centerX               = circle.CenterX;
            var centerY               = circle.CenterY;
            var sqTolerance           = Math.Sqrt(Constants.BaseTolerance);
            var sqRadiusPlusTolerance = circle.SqRadius + sqTolerance;
            var nextPoint             = dummyPoint;
            var priorRadius           = circle.SqRadius;
            while (!successful && stallCounter < stallLimit)
            {
                //If stallCounter is getting big, add a bit extra to the circle radius to ensure convergence
                if (stallCounter > stallLimit / 2)
                {
                    sqRadiusPlusTolerance = sqRadiusPlusTolerance + Constants.BaseTolerance * sqRadiusPlusTolerance;
                }
                //Add it a second time if stallCounter is even bigger
                if (stallCounter > stallLimit * 2 / 3)
                {
                    sqRadiusPlusTolerance = sqRadiusPlusTolerance + Constants.BaseTolerance * sqRadiusPlusTolerance;
                }

                //Find the furthest point from the center point
                var maxDistancePlusTolerance = sqRadiusPlusTolerance;
                var nextPointIsSet           = false;
                foreach (var point in points)
                {
                    var dx = centerX - point.X;
                    var dy = centerY - point.Y;
                    var squareDistanceToPoint = dx * dx + dy * dy;
                    //If the square distance is less than or equal to the max square distance, continue.
                    if (squareDistanceToPoint < maxDistancePlusTolerance)
                    {
                        continue;
                    }
                    //Otherwise, set this as the next point to go to.
                    maxDistancePlusTolerance = squareDistanceToPoint + sqTolerance;
                    nextPoint      = point;
                    nextPointIsSet = true;
                }
                if (!nextPointIsSet)
                {
                    successful = true;
                    continue;
                }

                //Create a new circle with 2 points
                //Find the point in the circle furthest from new point.
                circle.Furthest(nextPoint, out var furthestPoint, out var previousPoint1,
                                out var previousPoint2, out var numPreviousPoints);
                //Make a new circle from the furthest point and current point
                circle  = new InternalCircle(nextPoint, furthestPoint);
                centerX = circle.CenterX;
                centerY = circle.CenterY;
                sqRadiusPlusTolerance = circle.SqRadius + sqTolerance;

                //Now check if the previous points are outside this circle.
                //To be outside the circle, it must be further out than the specified tolerance.
                //Otherwise, the loop can get caught in a loop due to rounding error
                //If you wanted to use a tighter tolerance, you would need to take the square roots to get the radius.
                //If they are, increase the dimension and use three points in a circle
                var dxP1             = centerX - previousPoint1.X;
                var dyP1             = centerY - previousPoint1.Y;
                var squareDistanceP1 = dxP1 * dxP1 + dyP1 * dyP1;
                if (squareDistanceP1 > sqRadiusPlusTolerance)
                {
                    //Make a new circle from the current two-point circle and the current point
                    circle  = new InternalCircle(circle.Point0, circle.Point1, previousPoint1);
                    centerX = circle.CenterX;
                    centerY = circle.CenterY;
                    sqRadiusPlusTolerance = circle.SqRadius + sqTolerance;
                }
                else if (numPreviousPoints == 2)
                {
                    var dxP2             = centerX - previousPoint2.X;
                    var dyP2             = centerY - previousPoint2.Y;
                    var squareDistanceP2 = dxP2 * dxP2 + dyP2 * dyP2;
                    if (squareDistanceP2 > sqRadiusPlusTolerance)
                    {
                        //Make a new circle from the current two-point circle and the current point
                        circle  = new InternalCircle(circle.Point0, circle.Point1, previousPoint2);
                        centerX = circle.CenterX;
                        centerY = circle.CenterY;
                        sqRadiusPlusTolerance = circle.SqRadius + sqTolerance;
                    }
                }

                if (circle.SqRadius < priorRadius)
                {
                    Debug.WriteLine("Bounding circle got smaller during this iteration");
                }
                priorRadius = circle.SqRadius;
                stallCounter++;
            }
            if (stallCounter >= stallLimit)
            {
                Debug.WriteLine("Bounding circle failed to converge to within " + (Constants.BaseTolerance * circle.SqRadius * 2));
            }

            #endregion

            #region Algorithm 3: Meggiddo's Linear-Time Algorithm

            //Pair up points into n/2 pairs.
            //If an odd number of points.....

            //Construct a bisecting line for each pair of points. This sets their slope.

            //Order the slopes.
            //Find the median (halfway in the set) slope of the bisector lines


            //Test

            #endregion

            var radius = circle.SqRadius.IsNegligible() ? 0 : Math.Sqrt(circle.SqRadius);
            return(new BoundingCircle(radius, new PointLight(centerX, centerY)));
        }
예제 #9
0
        /// <summary>
        ///     Gets the maximum inner circle given a group of polygons and a center point.
        ///     If there are no negative polygons, the function will return a negligible Bounding Circle
        /// </summary>
        /// <returns>BoundingBox.</returns>
        public static BoundingCircle MaximumInnerCircle(IList <PolygonLight> paths, PointLight centerPoint)
        {
            var polygons = paths.Select(path => new Polygon(path)).ToList();

            return(MaximumInnerCircle(polygons, new Point(centerPoint)));
        }
예제 #10
0
 public double[] Subtract(PointLight b)
 {
     return(new[] { X - b.X, Y - b.Y });
 }
예제 #11
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="Point" /> class.
 /// </summary>
 /// <param name="x">The x.</param>
 /// <param name="y">The y.</param>
 /// <param name="point"></param>
 public Point(Point point)
 {
     Light      = new PointLight(point.X, point.Y);
     Lines      = new List <Line>(point.Lines);
     References = new List <Vertex>(point.References);
 }
예제 #12
0
 public double[] Add(PointLight b)
 {
     return(new[] { X + b.X, Y + b.Y });
 }