Beispiel #1
0
        internal void InvalidateNeighbors(AvlNode <Point> pointPrevious, AvlNode <Point> pointNew, AvlNode <Point> pointNext)
        {
            bool invalidPoint;

            if (pointPrevious != null)
            {
                AvlNode <Point> previousPrevious = pointPrevious.GetPreviousNode();
                for (; ;)
                {
                    if (previousPrevious == null)
                    {
                        break;
                    }

                    invalidPoint = !IsPointToTheRightOfOthers(previousPrevious.Item, pointNew.Item, pointPrevious.Item);
                    if (!invalidPoint)
                    {
                        break;
                    }
                    Point ptPrevPrev = previousPrevious.Item;

                    RemoveNode(pointPrevious);
                    pointPrevious    = this.GetNode(ptPrevPrev);
                    previousPrevious = pointPrevious.GetPreviousNode();
                }
            }

            // Invalidate next(s)
            if (pointNext != null)
            {
                AvlNode <Point> nextNext = pointNext.GetNextNode();
                for (; ;)
                {
                    if (nextNext == null)
                    {
                        break;
                    }

                    invalidPoint = !IsPointToTheRightOfOthers(pointNew.Item, nextNext.Item, pointNext.Item);
                    if (!invalidPoint)
                    {
                        break;
                    }
                    Point ptNextNext = nextNext.Item;

                    RemoveNode(pointNext);
                    pointNext = GetNode(ptNextNext);

                    nextNext = pointNext.GetNextNode();
                }
            }
        }
Beispiel #2
0
        internal override EnumConvexHullPoint ProcessPoint(ref PolygonPoint point)
        {
            CurrentNode = Root;
            AvlNode <PolygonPoint> currentPrevious = null;
            AvlNode <PolygonPoint> currentNext     = null;

            while (CurrentNode != null)
            {
                if (CanQuickReject(ref point, ref CurrentNode.Item))
                {
                    return(EnumConvexHullPoint.NotConvexHullPoint);
                }

                var insertionSide = Side.Unknown;
                if (point.Pos.X > CurrentNode.Item.Pos.X)
                {
                    if (CurrentNode.Right != null)
                    {
                        CurrentNode = CurrentNode.Right;
                        continue;
                    }

                    currentNext = CurrentNode.GetNextNode();
                    if (CanQuickReject(ref point, ref currentNext.Item))
                    {
                        return(EnumConvexHullPoint.NotConvexHullPoint);
                    }

                    if (!IsPointToTheRightOfOthers(CurrentNode.Item, currentNext.Item, point))
                    {
                        return(EnumConvexHullPoint.NotConvexHullPoint);
                    }

                    insertionSide = Side.Right;
                }
                else if (point.Pos.X < CurrentNode.Item.Pos.X)
                {
                    if (CurrentNode.Left != null)
                    {
                        CurrentNode = CurrentNode.Left;
                        continue;
                    }

                    currentPrevious = CurrentNode.GetPreviousNode();
                    if (CanQuickReject(ref point, ref currentPrevious.Item))
                    {
                        return(EnumConvexHullPoint.NotConvexHullPoint);
                    }

                    if (!IsPointToTheRightOfOthers(currentPrevious.Item, CurrentNode.Item, point))
                    {
                        return(EnumConvexHullPoint.NotConvexHullPoint);
                    }

                    insertionSide = Side.Left;
                }
                else
                {
                    if (point.Pos.Y >= CurrentNode.Item.Pos.Y)
                    {
                        if (point.Pos.Y == CurrentNode.Item.Pos.Y)
                        {
                            return(EnumConvexHullPoint.AlreadyExists);
                        }

                        return(EnumConvexHullPoint.NotConvexHullPoint);                        // invalid point
                    }

                    // Replace CurrentNode point with point
                    CurrentNode.Item = point;
                    InvalidateNeighbors(CurrentNode.GetPreviousNode(), CurrentNode, CurrentNode.GetNextNode());
                    return(EnumConvexHullPoint.ConvexHullPoint);
                }

                //We should insert the point

                // Try to optimize and verify if can replace a node instead insertion to minimize tree balancing
                if (insertionSide == Side.Right)
                {
                    currentPrevious = CurrentNode.GetPreviousNode();
                    if (currentPrevious != null && !IsPointToTheRightOfOthers(currentPrevious.Item, point, CurrentNode.Item))
                    {
                        CurrentNode.Item = point;
                        InvalidateNeighbors(currentPrevious, CurrentNode, currentNext);
                        return(EnumConvexHullPoint.ConvexHullPoint);
                    }

                    var nextNext = currentNext.GetNextNode();
                    if (nextNext != null && !IsPointToTheRightOfOthers(point, nextNext.Item, currentNext.Item))
                    {
                        currentNext.Item = point;
                        InvalidateNeighbors(null, currentNext, nextNext);
                        return(EnumConvexHullPoint.ConvexHullPoint);
                    }
                }
                else                 // Left
                {
                    currentNext = CurrentNode.GetNextNode();
                    if (currentNext != null && !IsPointToTheRightOfOthers(point, currentNext.Item, CurrentNode.Item))
                    {
                        CurrentNode.Item = point;
                        InvalidateNeighbors(currentPrevious, CurrentNode, currentNext);
                        return(EnumConvexHullPoint.ConvexHullPoint);
                    }

                    var previousPrevious = currentPrevious.GetPreviousNode();
                    if (previousPrevious != null && !IsPointToTheRightOfOthers(previousPrevious.Item, point, currentPrevious.Item))
                    {
                        currentPrevious.Item = point;
                        InvalidateNeighbors(previousPrevious, currentPrevious, null);
                        return(EnumConvexHullPoint.ConvexHullPoint);
                    }
                }

                // Should insert but no invalidation is required. (That's why we need to insert... can't replace an adjacent neightbor)
                AvlNode <PolygonPoint> newNode = new AvlNode <PolygonPoint>();
                if (insertionSide == Side.Right)
                {
                    newNode.Parent    = CurrentNode;
                    newNode.Item      = point;
                    CurrentNode.Right = newNode;
                    this.AddBalance(newNode.Parent, -1);
                }
                else                 // Left
                {
                    newNode.Parent   = CurrentNode;
                    newNode.Item     = point;
                    CurrentNode.Left = newNode;
                    this.AddBalance(newNode.Parent, 1);
                }

                return(EnumConvexHullPoint.ConvexHullPoint);
            }

            return(EnumConvexHullPoint.NotConvexHullPoint);
        }
        // ******************************************************************
        /// <summary>
        /// Iterate over each points to see if we can add it has a ConvexHull point.
        /// It is specific by Quadrant to improve efficiency.
        /// </summary>
        protected override void ProcessQuadrantSpecific()
        {
            // Main Loop to extract ConvexHullPoints
            foreach (Point point in ListOfPoint)
            {
                if (!IsGoodQuadrantForPoint(point))
                {
                    continue;
                }

                CurrentNode = Root;
                AvlNode <Point> currentPrevious = null;
                AvlNode <Point> currentNext     = null;

                // Debug.Assert(FirstPoint == GetFirstItem() && LastPoint == GetLastItem());

                while (CurrentNode != null)
                {
                    if (CanQuickReject(point, CurrentNode.Item))
                    {
                        break;
                    }

                    var insertionSide = Side.Unknown;
                    if (point.X > CurrentNode.Item.X)
                    {
                        if (CurrentNode.Right != null)
                        {
                            CurrentNode = CurrentNode.Right;
                            continue;
                        }

                        currentNext = CurrentNode.GetNextNode();
                        if (CanQuickReject(point, currentNext.Item))
                        {
                            break;
                        }

                        if (!IsPointToTheRightOfOthers(CurrentNode.Item, currentNext.Item, point))
                        {
                            break;
                        }

                        if (CurrentNode.Item == point)                         // Ensure to have no duplicate
                        {
                            continue;
                        }

                        insertionSide = Side.Right;
                    }
                    else if (point.X < CurrentNode.Item.X)
                    {
                        if (CurrentNode.Left != null)
                        {
                            CurrentNode = CurrentNode.Left;
                            continue;
                        }

                        currentPrevious = CurrentNode.GetPreviousNode();
                        if (CanQuickReject(point, currentPrevious.Item))
                        {
                            break;
                        }

                        if (!IsPointToTheRightOfOthers(currentPrevious.Item, CurrentNode.Item, point))
                        {
                            break;
                        }

                        if (CurrentNode.Item == point)                         // Ensure to have no duplicate
                        {
                            continue;
                        }

                        insertionSide = Side.Left;
                    }
                    else
                    {
                        if (point.Y >= CurrentNode.Item.Y)
                        {
                            break;                             // invalid point
                        }

                        // Replace CurrentNode point with point
                        // Debug.Assert(CurrentNode.Parent == null || !point.Equals(CurrentNode.Parent.Item));
                        CurrentNode.Item = point;
                        InvalidateNeighbors(CurrentNode.GetPreviousNode(), CurrentNode, CurrentNode.GetNextNode());
                        break;
                    }

                    //We should insert the point

                    // Try to optimize and verify if can replace a node instead insertion to minimize tree balancing
                    if (insertionSide == Side.Right)
                    {
                        currentPrevious = CurrentNode.GetPreviousNode();
                        if (currentPrevious != null && !IsPointToTheRightOfOthers(currentPrevious.Item, point, CurrentNode.Item))
                        {
                            // DebugEnsureTreeIsValid();
                            // Debug.Assert(CurrentNode.Item != FirstPoint && CurrentNode.Item != LastPoint);

                            // Debug.Assert(CurrentNode.Parent == null || !point.Equals(CurrentNode.Parent.Item));
                            CurrentNode.Item = point;
                            InvalidateNeighbors(currentPrevious, CurrentNode, currentNext);
                            // DebugEnsureTreeIsValid();
                            break;
                        }

                        var nextNext = currentNext.GetNextNode();
                        if (nextNext != null && !IsPointToTheRightOfOthers(point, nextNext.Item, currentNext.Item))
                        {
                            // DebugEnsureTreeIsValid();
                            // Debug.Assert(currentNext.Item != FirstPoint && currentNext.Item != LastPoint);

                            // Debug.Assert(CurrentNode.Parent == null || !point.Equals(CurrentNode.Parent.Item));
                            currentNext.Item = point;
                            InvalidateNeighbors(null, currentNext, nextNext);
                            // DebugEnsureTreeIsValid();
                            break;
                        }
                    }
                    else                     // Left
                    {
                        currentNext = CurrentNode.GetNextNode();
                        if (currentNext != null && !IsPointToTheRightOfOthers(point, currentNext.Item, CurrentNode.Item))
                        {
                            // DebugEnsureTreeIsValid();
                            // Debug.Assert(CurrentNode.Item != FirstPoint && CurrentNode.Item != LastPoint);

                            // Debug.Assert(CurrentNode.Parent == null || !point.Equals(CurrentNode.Parent.Item));
                            CurrentNode.Item = point;
                            InvalidateNeighbors(currentPrevious, CurrentNode, currentNext);
                            // DebugEnsureTreeIsValid();
                            break;
                        }

                        var previousPrevious = currentPrevious.GetPreviousNode();
                        if (previousPrevious != null && !IsPointToTheRightOfOthers(previousPrevious.Item, point, currentPrevious.Item))
                        {
                            // DebugEnsureTreeIsValid();
                            // Debug.Assert(currentPrevious.Item != FirstPoint && currentPrevious.Item != LastPoint);

                            // Debug.Assert(CurrentNode.Parent == null || !point.Equals(CurrentNode.Parent.Item));
                            currentPrevious.Item = point;
                            InvalidateNeighbors(previousPrevious, currentPrevious, null);
                            // DebugEnsureTreeIsValid();
                            break;
                        }
                    }

                    // Should insert but no invalidation is required. (That's why we need to insert... can't replace an adjacent neightbor)
                    AvlNode <Point> newNode = new AvlNode <Point>();
                    if (insertionSide == Side.Right)
                    {
                        newNode.Parent    = CurrentNode;
                        newNode.Item      = point;
                        CurrentNode.Right = newNode;
                        this.AddBalance(newNode.Parent, -1);
                    }
                    else                     // Left
                    {
                        newNode.Parent   = CurrentNode;
                        newNode.Item     = point;
                        CurrentNode.Left = newNode;
                        this.AddBalance(newNode.Parent, 1);
                    }

                    // DebugEnsureTreeIsValid();
                    break;
                }

                // Debug.Assert(FirstPoint == GetFirstItem() && LastPoint == GetLastItem());
            }

            // Dump2("", Name);
        }