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(); } } }
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); }