public PolygonCrossing[] Get(int ringIndex) { Contract.Requires(ringIndex >= 0); Contract.Ensures(Contract.Result<PolygonCrossing[]>() != null); Contract.Ensures(Contract.ForAll(Contract.Result<PolygonCrossing[]>(), x => x != null)); if (_cache.Key == ringIndex) return _cache.Value; PolygonCrossing[] crossings; if (!RingCrossings.TryGetValue(ringIndex, out crossings)) { crossings = new PolygonCrossing[0]; } _cache = new KeyValuePair<int, PolygonCrossing[]>(ringIndex, crossings); Contract.Assume(crossings != null); return crossings; }
private static Point2 FindPreviousRingPoint( 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; Contract.Assume(currentLocation.SegmentIndex < segmentCount); var previousSegmentIndex = IterationUtils.RetreatLoopingIndex(currentLocation.SegmentIndex, segmentCount); var previousCrossing = FindPreviousCrossingNotEqual(currentCrossing, crossingsOnRing, crossingComparer); if (null == previousCrossing) { return ring[ currentLocation.SegmentRatio == 0 ? previousSegmentIndex : currentLocation.SegmentIndex ]; } var previousCrossingLocation = getLocation(previousCrossing); Contract.Assume(previousCrossingLocation != null); if (currentLocation.SegmentRatio == 0) { return previousSegmentIndex == previousCrossingLocation.SegmentIndex ? previousCrossing.Point : ring[previousSegmentIndex]; } return currentLocation.SegmentIndex == previousCrossingLocation.SegmentIndex && currentLocation.SegmentRatio > previousCrossingLocation.SegmentRatio ? previousCrossing.Point : ring[currentLocation.SegmentIndex]; }
private static PolygonCrossing FindPreviousCrossingNotEqual( 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; int currentCrossingIndex = Array.BinarySearch(crossingsOnRing, currentCrossing, crossingComparer); if (currentCrossingIndex < 0) return null; int crossingsCount = crossingsOnRing.Length; // find the first crossing before this one that has a different point location for ( int i = IterationUtils.RetreatLoopingIndex(currentCrossingIndex, crossingsCount); i != currentCrossingIndex; i = IterationUtils.RetreatLoopingIndex(i, crossingsCount) ) { var crossing = crossingsOnRing[i]; if (crossing.Point != currentPoint) return crossing; } return null; }
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 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]; } }
[Pure] private static int GetRingIndexB(PolygonCrossing crossing) { Contract.Requires(crossing != null); Contract.Ensures(Contract.Result<int>() >= 0); return crossing.LocationB.RingIndex; }
private PolygonCrossing TraverseBSide( PolygonCrossing entrance, List<Point2> buildingRing ) { Contract.Requires(entrance != null); Contract.Requires(buildingRing != null); Contract.Ensures(buildingRing.Count >= Contract.OldValue(buildingRing).Count); PolygonCrossing exit; do { exit = TraverseBSideRing(buildingRing, entrance, RingCrossingsB.Get(entrance.LocationB.RingIndex)); if (exit == null) return null; } while ((entrance = TraverseBSideHops(exit)) != null); return exit; }
[Pure] private static PolygonBoundaryLocation GetLocationB(PolygonCrossing crossing) { Contract.Requires(crossing != null); Contract.Ensures(Contract.Result<PolygonBoundaryLocation>() != null); return crossing.LocationB; }
private PolygonCrossing TraverseBSideRing( List<Point2> buildingRing, PolygonCrossing fromCrossing, PolygonCrossing[] ringCrossings ) { Contract.Requires(buildingRing != null); Contract.Requires(fromCrossing != null); Contract.Requires(ringCrossings != null); Contract.Requires(Contract.ForAll(ringCrossings, x => x != null)); Contract.Ensures(buildingRing.Count >= Contract.OldValue(buildingRing).Count); var fromSegmentLocationB = fromCrossing.LocationB; if (0 == buildingRing.Count || buildingRing[buildingRing.Count - 1] != fromCrossing.Point) buildingRing.Add(fromCrossing.Point); var fromCrossingIndex = Array.BinarySearch(ringCrossings, fromCrossing, PolygonCrossing.LocationBComparer.Default); Contract.Assume(fromCrossingIndex >= 0); foreach (var crossing in TraverseCrossings(fromCrossing, ringCrossings, fromCrossingIndex)) { // hops should have already been taken care of if (crossing.Point == fromCrossing.Point && ExitHops.ContainsKey(crossing)) continue; // no, lets go somewhere useful with this var locationB = crossing.LocationB; Contract.Assume(locationB.RingIndex < B.Count); Contract.Assume(B[locationB.RingIndex] != null); AddPointsBetweenForward(buildingRing, B[locationB.RingIndex], fromSegmentLocationB, locationB); fromSegmentLocationB = locationB; // for later... if (Exits.Contains(crossing)) return crossing; // if we found it, stop if (buildingRing.Count == 0 || buildingRing[buildingRing.Count - 1] != crossing.Point) buildingRing.Add(crossing.Point); // if it is something else, lets add it } return null; }
private PolygonCrossing TraverseBSideHops(PolygonCrossing start) { Contract.Requires(start != null); PolygonCrossing current = start; PolygonCrossing result = null; PolygonCrossing next; while ( Exits.Contains(current) && ExitHops.TryGetValue(current, out next) && Entrances.Contains(next) && next.LocationB != start.LocationB ) { result = next; VisitEntrance(next); Contract.Assume(current != null); VisitExit(current); if (!EntranceHops.TryGetValue(next, out current)) break; } return result; }
private void VisitExit(PolygonCrossing exit) { Contract.Requires(exit != null); if (Exits.Remove(exit)) ApplyCrossingVisit(exit); }
private void VisitEntrance(PolygonCrossing entrance) { Contract.Requires(entrance != null); if (Entrances.Remove(entrance)) ApplyCrossingVisit(entrance); }
private void ApplyCrossingVisit(PolygonCrossing crossing) { Contract.Requires(crossing != null); VisitedCrossings.Add(crossing); VisitedCrossingsRingIndicesA.Add(crossing.LocationA.RingIndex); VisitedCrossingsRingIndicesB.Add(crossing.LocationB.RingIndex); }