private static Point2 FindNextRingPoint( PolygonCrossing currentCrossing, PolygonCrossing[] crossingsOnRing, Ring2 ring, Func <PolygonCrossing, PolygonBoundaryLocation> getLocation, IComparer <PolygonCrossing> crossingComparer ) { Contract.Requires(currentCrossing != null); Contract.Requires(crossingsOnRing != null); Contract.Requires(Contract.ForAll(crossingsOnRing, x => x != null)); Contract.Requires(ring != null); Contract.Requires(getLocation != null); Contract.Requires(crossingComparer != null); var currentLocation = getLocation(currentCrossing); var segmentCount = ring.SegmentCount; int nextSegmentIndex = IterationUtils.AdvanceLoopingIndex(currentLocation.SegmentIndex, segmentCount); var nextCrossing = FindNextCrossingNotEqual(currentCrossing, crossingsOnRing, crossingComparer); // NOTE: this method assumes a segment ratio less than 1, verify we can trust this if (null == nextCrossing) { return(ring[nextSegmentIndex]); } var nextCrossingLocation = getLocation(nextCrossing); Contract.Assume(nextCrossingLocation != null); return(currentLocation.SegmentIndex == nextCrossingLocation.SegmentIndex && currentLocation.SegmentRatio < nextCrossingLocation.SegmentRatio ? nextCrossing.Point : ring[nextSegmentIndex]); }
private static PolygonCrossing FindNextCrossingNotEqual( PolygonCrossing currentCrossing, PolygonCrossing[] crossingsOnRing, IComparer <PolygonCrossing> crossingComparer ) { Contract.Requires(currentCrossing != null); Contract.Requires(crossingsOnRing != null); Contract.Requires(Contract.ForAll(crossingsOnRing, x => x != null)); Contract.Requires(crossingComparer != null); var currentPoint = currentCrossing.Point; var currentCrossingIndex = Array.BinarySearch(crossingsOnRing, currentCrossing, crossingComparer); if (currentCrossingIndex < 0) { return(null); } var crossingsCount = crossingsOnRing.Length; // find the first crossing after this one that has a different point location for ( var i = IterationUtils.AdvanceLoopingIndex(currentCrossingIndex, crossingsCount); i != currentCrossingIndex; i = IterationUtils.AdvanceLoopingIndex(i, crossingsCount) ) { var crossing = crossingsOnRing[i]; if (crossing.Point != currentPoint) { return(crossing); } } return(null); }
private static void AddPointsBetweenForward( List <Point2> results, Ring2 ring, PolygonBoundaryLocation from, PolygonBoundaryLocation to ) { Contract.Requires(results != null); Contract.Requires(ring != null); Contract.Requires(from != null); Contract.Requires(to != null); Contract.Ensures(results.Count >= Contract.OldValue(results).Count); if (from.SegmentIndex == to.SegmentIndex && from.SegmentRatio <= to.SegmentRatio) { return; // no points will result from this } var segmentCount = ring.SegmentCount; var currentSegmentIndex = IterationUtils.AdvanceLoopingIndex(from.SegmentIndex, segmentCount); do { if (to.SegmentIndex == currentSegmentIndex) { if (to.SegmentRatio > 0) { results.Add(ring[currentSegmentIndex]); } return; } results.Add(ring[currentSegmentIndex]); currentSegmentIndex = IterationUtils.AdvanceLoopingIndex(currentSegmentIndex, segmentCount); } while (true); }
private static IEnumerable <PolygonCrossing> TraverseCrossings( PolygonCrossing fromCrossing, PolygonCrossing[] ringCrossings, int fromCrossingIndex ) { Contract.Requires(fromCrossing != null); Contract.Requires(ringCrossings != null); //Contract.Requires(crossingComparer != null); Contract.Requires(fromCrossingIndex >= 0); Contract.Ensures(Contract.Result <IEnumerable <PolygonCrossing> >() != null); //var fromCrossingIndex = ringCrossings.BinarySearch(fromCrossing, crossingComparer); var ringCrossingsCount = ringCrossings.Length; Stack <PolygonCrossing> priorResults = null; var backTrackIndex = fromCrossingIndex; do { var priorIndex = IterationUtils.RetreatLoopingIndex(backTrackIndex, ringCrossingsCount); var priorCrossing = ringCrossings[priorIndex]; if (priorCrossing.Point != fromCrossing.Point) { break; } backTrackIndex = priorIndex; (priorResults ?? (priorResults = new Stack <PolygonCrossing>())) .Push(priorCrossing); } while (backTrackIndex != fromCrossingIndex); if (null != priorResults) { while (priorResults.Count > 0) { yield return(priorResults.Pop()); } } for ( int i = IterationUtils.AdvanceLoopingIndex(fromCrossingIndex, ringCrossingsCount); i != fromCrossingIndex; i = IterationUtils.AdvanceLoopingIndex(i, ringCrossingsCount) ) { yield return(ringCrossings[i]); } }
private static int Compare(int indexAStart, int indexBStart, Ring2 ring) { Contract.Requires(ring != null); Contract.Requires(indexAStart >= 0); Contract.Requires(indexAStart < ring.Count); Contract.Requires(indexBStart >= 0); Contract.Requires(indexBStart < ring.Count); var ax = ring[indexAStart].X; var bx = ring[IterationUtils.AdvanceLoopingIndex(indexAStart, ring.Count)].X; var cx = ring[indexBStart].X; var dx = ring[IterationUtils.AdvanceLoopingIndex(indexBStart, ring.Count)].X; int compareResult; if (dx < cx) { compareResult = Math.Min(ax, bx).CompareTo(dx); return(compareResult != 0 ? compareResult : Math.Max(ax, bx).CompareTo(cx)); } compareResult = Math.Min(ax, bx).CompareTo(cx); return(compareResult != 0 ? compareResult : Math.Max(ax, bx).CompareTo(dx)); }
/// <summary> /// Determines the points that would need to be inserted into the resulting /// intersection geometry between the two given rings, at the location where /// their boundaries cross. /// </summary> /// <param name="ringA">The first ring to test.</param> /// <param name="ringB">The second ring to test.</param> /// <param name="ringIndexA">The ring index on polygon a.</param> /// <param name="ringIndexB">The ring index on polygon b.</param> private List <PolygonCrossing> GenerateRingCrossingsSorted(Ring2 ringA, Ring2 ringB, int ringIndexA, int ringIndexB) { Contract.Requires(ringA != null); Contract.Requires(ringA.Count > 0); Contract.Requires(ringIndexA >= 0); Contract.Requires(ringIndexA < ringA.Count); Contract.Requires(ringB != null); Contract.Requires(ringB.Count > 0); Contract.Requires(ringIndexB >= 0); Contract.Requires(ringIndexB < ringB.Count); Contract.Ensures(Contract.Result <List <PolygonCrossing> >() != null); int minSegmentSearchIndicesB = 0; var segmentSearchIndicesA = GetSortedRingSegmentIndices(ringA); var segmentSearchIndicesB = GetSortedRingSegmentIndices(ringB); var countA = ringA.Count; var countB = ringB.Count; var crossings = new List <PolygonCrossing>(); for (var segmentSearchIndexA = 0; segmentSearchIndexA < segmentSearchIndicesA.Length; segmentSearchIndexA++) { double temp; var segmentStartIndexA = segmentSearchIndicesA[segmentSearchIndexA]; Contract.Assume(segmentStartIndexA >= 0); Contract.Assume(segmentStartIndexA < ringA.Count); var a = ringA[segmentStartIndexA]; var smallestXValueOnA = a.X; var b = ringA[IterationUtils.AdvanceLoopingIndex(segmentStartIndexA, countA)]; var largestXValueOnA = b.X; if (largestXValueOnA < smallestXValueOnA) { temp = largestXValueOnA; largestXValueOnA = smallestXValueOnA; smallestXValueOnA = temp; } var segmentDataA = new Segment2Data( new Segment2(a, b), segmentStartIndexA, ringIndexA ); var segmentAMbr = segmentDataA.Segment.GetMbr(); for (int segmentSearchIndexB = minSegmentSearchIndicesB; segmentSearchIndexB < segmentSearchIndicesB.Length; segmentSearchIndexB++) { int segmentStartIndexB = segmentSearchIndicesB[segmentSearchIndexB]; Contract.Assume(segmentStartIndexB >= 0); Contract.Assume(segmentStartIndexB < ringB.Count); var c = ringB[segmentStartIndexB]; var smallestXValueOnC = c.X; var d = ringB[IterationUtils.AdvanceLoopingIndex(segmentStartIndexB, countB)]; var largestXValueOnD = d.X; if (largestXValueOnD < smallestXValueOnC) { temp = largestXValueOnD; largestXValueOnD = smallestXValueOnC; smallestXValueOnC = temp; } //if (largestXValueOnD < smallestXValueOnA) { // minSegmentSearchIndicesB = segmentSearchIndexB + 1; // continue; //} if (smallestXValueOnC > largestXValueOnA) { break; } if (!segmentAMbr.Intersects(c, d)) { continue; } AddPointCrossings( crossings, segmentDataA, new Segment2Data( new Segment2(c, d), segmentStartIndexB, ringIndexB ) ); } if (minSegmentSearchIndicesB >= segmentSearchIndicesB.Length) { break; // wont do anything else } } return(crossings); }