protected void InvalidateNeighbors(AvlNode <MutablePoint> pointPrevious, AvlNode <MutablePoint> pointNew, AvlNode <MutablePoint> pointNext) { bool invalidPoint; if (pointPrevious != null) { AvlNode <MutablePoint> previousPrevious = pointPrevious.GetPreviousNode(); for (; ;) { if (previousPrevious == null) { break; } invalidPoint = !this.IsPointToTheRightOfOthers(previousPrevious.Item, pointNew.Item, pointPrevious.Item); if (!invalidPoint) { break; } MutablePoint pointPrevPrev = previousPrevious.Item; this.RemoveNode(pointPrevious); pointPrevious = this.GetNode(pointPrevPrev); previousPrevious = pointPrevious.GetPreviousNode(); } } // Invalidate next(s) if (pointNext != null) { AvlNode <MutablePoint> nextNext = pointNext.GetNextNode(); for (; ;) { if (nextNext == null) { break; } invalidPoint = !this.IsPointToTheRightOfOthers(pointNew.Item, nextNext.Item, pointNext.Item); if (!invalidPoint) { break; } MutablePoint pointNextNext = nextNext.Item; this.RemoveNode(pointNext); pointNext = this.GetNode(pointNextNext); nextNext = pointNext.GetNextNode(); } } }
/// <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> /// <param name="point">a point</param> //// [MethodImpl(MethodImplOptions.AggressiveInlining)] internal override void ProcessPoint(ref MutablePoint point) { this.CurrentNode = this.Root; AvlNode <MutablePoint> currentPrevious = null; AvlNode <MutablePoint> currentNext = null; while (this.CurrentNode != null) { var insertionSide = Side.Unknown; if (point.X > this.CurrentNode.Item.X) { if (this.CurrentNode.Left != null) { this.CurrentNode = this.CurrentNode.Left; continue; } currentPrevious = this.CurrentNode.GetPreviousNode(); if (CanQuickReject(ref point, ref currentPrevious.Item)) { return; } if (!this.IsPointToTheRightOfOthers(currentPrevious.Item, this.CurrentNode.Item, point)) { return; } // Ensure to have no duplicate if (this.CurrentNode.Item == point) { return; } insertionSide = Side.Left; } else if (point.X < this.CurrentNode.Item.X) { if (this.CurrentNode.Right != null) { this.CurrentNode = this.CurrentNode.Right; continue; } currentNext = this.CurrentNode.GetNextNode(); if (CanQuickReject(ref point, ref currentNext.Item)) { return; } if (!this.IsPointToTheRightOfOthers(this.CurrentNode.Item, currentNext.Item, point)) { return; } // Ensure to have no duplicate if (this.CurrentNode.Item == point) { continue; } insertionSide = Side.Right; } else { if (point.Y <= this.CurrentNode.Item.Y) { return; // invalid point } // Replace CurrentNode point with point this.CurrentNode.Item = point; this.InvalidateNeighbors(this.CurrentNode.GetPreviousNode(), this.CurrentNode, this.CurrentNode.GetNextNode()); return; } // 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 = this.CurrentNode.GetPreviousNode(); if (currentPrevious != null && !this.IsPointToTheRightOfOthers(currentPrevious.Item, point, this.CurrentNode.Item)) { this.CurrentNode.Item = point; this.InvalidateNeighbors(currentPrevious, this.CurrentNode, currentNext); return; } var nextNext = currentNext.GetNextNode(); if (nextNext != null && !this.IsPointToTheRightOfOthers(point, nextNext.Item, currentNext.Item)) { currentNext.Item = point; this.InvalidateNeighbors(null, currentNext, nextNext); return; } } else { // Left currentNext = this.CurrentNode.GetNextNode(); if (currentNext != null && !this.IsPointToTheRightOfOthers(point, currentNext.Item, this.CurrentNode.Item)) { this.CurrentNode.Item = point; this.InvalidateNeighbors(currentPrevious, this.CurrentNode, currentNext); return; } var previousPrevious = currentPrevious.GetPreviousNode(); if (previousPrevious != null && !this.IsPointToTheRightOfOthers(previousPrevious.Item, point, currentPrevious.Item)) { currentPrevious.Item = point; this.InvalidateNeighbors(previousPrevious, currentPrevious, null); return; } } // Should insert but no invalidation is required. (That's why we need to insert... can't replace an adjacent neighbor) AvlNode <MutablePoint> newNode = new AvlNode <MutablePoint>(); if (insertionSide == Side.Right) { newNode.Parent = this.CurrentNode; newNode.Item = point; this.CurrentNode.Right = newNode; this.AddBalance(newNode.Parent, -1); } else { // Left newNode.Parent = this.CurrentNode; newNode.Item = point; this.CurrentNode.Left = newNode; this.AddBalance(newNode.Parent, 1); } return; } }
/// <summary> /// Copies to an array /// </summary> /// <param name="array">The array to copy to</param> /// <param name="index">start point</param> /// <param name="count">number of items to copy</param> public void CopyTo(T[] array, int index, int count) { if (array == null) { throw new ArgumentNullException("'array' can't be null"); } if (index < 0) { throw new ArgumentException("'index' can't be null"); } if (count < 0) { throw new ArgumentOutOfRangeException("'count' should be greater or equal to 0"); } if (index > array.Length || count > array.Length - index) { throw new ArgumentException("The array size is not big enough to get all items"); } if (count == 0) { return; } int indexIter = 0; int indexArray = 0; AvlNode <T> current = this.GetFirstNode(); while (current.GetNextNode() != null) { if (indexIter >= index) { array[indexArray] = current.Item; indexArray++; count--; if (count == 0) { return; } } indexIter++; } /* * foreach (AvlNode<T> node in this.Nodes()) * { * if (indexIter >= index) * { * array[indexArray] = node.Item; * indexArray++; * count--; * if (count == 0) * { * return; * } * } * * indexIter++; * }*/ }