コード例 #1
0
        IEnumerable <Point> Calculate()
        {
            if (pivot.Y == Double.MaxValue)
            {
                return(new Point[0]);
            }
            if (hullPoints.Length == 0)
            {
                return new[] { pivot }
            }
            ;
            SortAllPointsWithoutPivot();
            Scan();
            return(EnumerateStack());
        }

        IEnumerable <Point> EnumerateStack()
        {
            HullStack stackCell = stack;

            while (stackCell != null)
            {
                yield return(stackCell.Point);

                stackCell = stackCell.Next;
            }
        }

        void Scan()
        {
            int i = 0;

            while (hullPoints[i].Deleted)
            {
                i++;
            }

            stack = new HullStack(pivot);
            Push(i++);
            if (i < hullPoints.Length)
            {
                if (!hullPoints[i].Deleted)
                {
                    Push(i++);
                }
                else
                {
                    i++;
                }
            }

            while (i < hullPoints.Length)
            {
                if (!hullPoints[i].Deleted)
                {
                    if (LeftTurn(i))
                    {
                        Push(i++);
                    }
                    else
                    {
                        Pop();
                    }
                }
                else
                {
                    i++;
                }
            }

            //cleanup the end
            while (StackHasMoreThanTwoPoints() && !LeftTurnToPivot())
            {
                Pop();
            }
        }

        bool LeftTurnToPivot()
        {
            return(Point.GetTriangleOrientation(StackSecondPoint, StackTopPoint, pivot) ==
                   TriangleOrientation.Counterclockwise);
        }

        bool StackHasMoreThanTwoPoints()
        {
            return(stack.Next != null && stack.Next.Next != null);
        }

        void Pop()
        {
            stack = stack.Next;
        }

        bool LeftTurn(int i)
        {
            if (stack.Next == null)
            {
                return(true); //there is only one point in the stack
            }
            var orientation = Point.GetTriangleOrientationWithIntersectionEpsilon(StackSecondPoint, StackTopPoint, hullPoints[i].Point);

            if (orientation == TriangleOrientation.Counterclockwise)
            {
                return(true);
            }
            if (orientation == TriangleOrientation.Clockwise)
            {
                return(false);
            }
            return(BackSwitchOverPivot(hullPoints[i].Point));
        }

        bool BackSwitchOverPivot(Point point)
        {
            //we know here that there at least two points in the stack but it has to be exaclty two
            if (stack.Next.Next != null)
            {
                return(false);
            }
            Debug.Assert(StackSecondPoint == pivot);
            return(StackTopPoint.X > pivot.X + ApproximateComparer.DistanceEpsilon &&
                   point.X < pivot.X - ApproximateComparer.DistanceEpsilon);
        }

        void Push(int p)
        {
            var t = new HullStack(hullPoints[p].Point)
            {
                Next = stack
            };

            stack = t;
        }

        void SortAllPointsWithoutPivot()
        {
            comparer = new HullPointComparer(pivot);
            Array.Sort(hullPoints, comparer);
//            if (true) {
//                var list = new List<DebugCurve>();
//                var d = 3.0;
//                list.Add(new DebugCurve(100, 0.001, "magenta", El(ref d, pivot)));
//                foreach (var hullPoint in hullPoints) {
//                    list.Add(new DebugCurve(100,0.001, hullPoint.Deleted ? "blue" : "green", El(ref d, hullPoint.Point)));
//                }
//                LayoutAlgorithmSettings.ShowDebugCurvesEnumeration(list);
//            }
        }
コード例 #2
0
        /// <summary>
        /// note that this function can change "deleted" member for collinear points
        /// </summary>
        /// <param name="i"></param>
        /// <param name="j"></param>
        /// <returns></returns>
#if SHARPKIT //http://code.google.com/p/sharpkit/issues/detail?id=203
        //SharpKit/Colin - https://code.google.com/p/sharpkit/issues/detail?id=332
        public int Compare(HullPoint i, HullPoint j)
        {
#else
        int IComparer <HullPoint> .Compare(HullPoint i, HullPoint j)
        {
#endif
            if (i == j)
            {
                return(0);
            }
            if (i == null)
            {
                return(-1);
            }
            if (j == null)
            {
                return(1);
            }

            switch (Point.GetTriangleOrientationWithIntersectionEpsilon(pivot, i.Point, j.Point))
            {
            case TriangleOrientation.Counterclockwise:
                return(-1);

            case TriangleOrientation.Clockwise:
                return(1);

            case TriangleOrientation.Collinear: {
                //because of the double point error pi and pj can be on different sizes of the pivot on the horizontal line passing through the pivot, or rather just above it
                var piDelX = i.Point.X - pivot.X;
                var pjDelX = j.Point.X - pivot.X;
                if (piDelX > ApproximateComparer.DistanceEpsilon && pjDelX < -ApproximateComparer.DistanceEpsilon)
                {
                    return(-1);
                }
                if (piDelX < -ApproximateComparer.DistanceEpsilon && pjDelX > ApproximateComparer.DistanceEpsilon)
                {
                    return(1);
                }

                //here i and j cannot be on the different sides of the pivot because of the choice of the pivot
                //delete the one that is closer to the pivot.
                var pi    = i.Point - pivot;
                var pj    = j.Point - pivot;
                var iMinJ = pi.L1 - pj.L1;
                if (iMinJ < 0)
                {
                    i.Deleted = true;
                    return(-1);
                }
                if (iMinJ > 0)
                {
                    j.Deleted = true;
                    return(1);
                }

                //points are the same, leave the one with the greatest hash code
                if (i.GetHashCode() < j.GetHashCode())
                {
                    i.Deleted = true;
                }
                else
                {
                    j.Deleted = true;
                }

                return(0);
            }
            }
            throw new InvalidOperationException();
        }