Beispiel #1
0
        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);
        }
Beispiel #2
0
            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);
            }
Beispiel #3
0
        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]);
        }
Beispiel #4
0
 private void ApplyCrossingVisit(PolygonCrossing crossing)
 {
     Contract.Requires(crossing != null);
     VisitedCrossings.Add(crossing);
     VisitedCrossingsRingIndicesA.Add(crossing.LocationA.RingIndex);
     VisitedCrossingsRingIndicesB.Add(crossing.LocationB.RingIndex);
 }
Beispiel #5
0
 private void VisitExit(PolygonCrossing exit)
 {
     Contract.Requires(exit != null);
     if (Exits.Remove(exit))
     {
         ApplyCrossingVisit(exit);
     }
 }
Beispiel #6
0
 private void VisitEntrance(PolygonCrossing entrance)
 {
     Contract.Requires(entrance != null);
     if (Entrances.Remove(entrance))
     {
         ApplyCrossingVisit(entrance);
     }
 }
Beispiel #7
0
        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]);
            }
        }
Beispiel #8
0
            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);
            }
Beispiel #9
0
        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]);
        }
Beispiel #10
0
            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);
            }
Beispiel #11
0
            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);
            }
Beispiel #12
0
        /// <summary>
        /// Builds required crossing data.
        /// </summary>
        /// <param name="crossings">The crossings to calculate. (Note: collection is modified)</param>
        /// <param name="a">The left hand polygon.</param>
        /// <param name="b">The right hand polygon.</param>
        private PolygonCrossingsAlgorithmKernel CreateIntersectionKernelFromCrossings(List <PolygonCrossing> crossings, Polygon2 a, Polygon2 b)
        {
            Contract.Requires(crossings != null);
            Contract.Requires(a != null);
            Contract.Requires(b != null);
            Contract.Ensures(Contract.Result <PolygonCrossingsAlgorithmKernel>() != null);

            var kernel = new PolygonCrossingsAlgorithmKernel(a, b, crossings);

            if (crossings.Count == 0)
            {
                return(kernel);
            }

            foreach (var currentCrossing in crossings)
            {
                var ringIndexA = currentCrossing.LocationA.RingIndex;
                Contract.Assume(ringIndexA < a.Count);
                var ringA = a[ringIndexA];
                Contract.Assume(ringA != null);
                var crossingsOnRingA = kernel.RingCrossingsA.Get(ringIndexA);

                var priorPointA = FindPreviousRingPoint(currentCrossing, crossingsOnRingA, ringA, GetLocationA, PolygonCrossing.LocationAComparer.Default);
                var nextPointA  = FindNextRingPoint(currentCrossing, crossingsOnRingA, ringA, GetLocationA, PolygonCrossing.LocationAComparer.Default);

                var ringIndexB = currentCrossing.LocationB.RingIndex;
                Contract.Assume(ringIndexB < b.Count);
                var ringB = b[ringIndexB];
                Contract.Assume(ringB != null);
                var crossingsOnRingB = kernel.RingCrossingsB.Get(ringIndexB);

                var priorPointB = FindPreviousRingPoint(currentCrossing, crossingsOnRingB, ringB, GetLocationB, PolygonCrossing.LocationBComparer.Default);
                var nextPointB  = FindNextRingPoint(currentCrossing, crossingsOnRingB, ringB, GetLocationB, PolygonCrossing.LocationBComparer.Default);

                // based on the vectors, need to classify the crossing type
                currentCrossing.CrossType = PolygonCrossing.DetermineCrossingType(
                    (nextPointA - currentCrossing.Point).GetNormalized(),
                    (priorPointA - currentCrossing.Point).GetNormalized(),
                    (nextPointB - currentCrossing.Point).GetNormalized(),
                    (priorPointB - currentCrossing.Point).GetNormalized()
                    );
            }

            foreach (var ringCrossings in kernel.RingCrossingsA.RingCrossings)
            {
                Contract.Assume(ringCrossings.Key >= 0 && ringCrossings.Key < a.Count);
                if (a[ringCrossings.Key].FillSide == RelativeDirectionType.Right)
                {
                    foreach (var crossing in ringCrossings.Value)
                    {
                        Contract.Assume(crossing != null);
                        var crossLegType = crossing.CrossType & CrossingType.Parallel;
                        if (crossLegType == CrossingType.CrossToRight || crossLegType == CrossingType.DivergeRight)
                        {
                            kernel.Entrances.Add(crossing);
                        }
                        else if (crossLegType == CrossingType.CrossToLeft || crossLegType == CrossingType.ConvergeRight)
                        {
                            kernel.Exits.Add(crossing);
                        }
                    }
                }
                else
                {
                    foreach (var crossing in ringCrossings.Value)
                    {
                        Contract.Assume(crossing != null);
                        var crossLegType = crossing.CrossType & CrossingType.Parallel;
                        if (crossLegType == CrossingType.CrossToLeft || crossLegType == CrossingType.DivergeLeft)
                        {
                            kernel.Entrances.Add(crossing);
                        }
                        else if (crossLegType == CrossingType.CrossToRight || crossLegType == CrossingType.ConvergeLeft)
                        {
                            kernel.Exits.Add(crossing);
                        }
                    }
                }
            }

            var sortedEntrances = kernel.Entrances.ToArray();

            Array.Sort(sortedEntrances, PolygonCrossing.LocationAComparer.CompareNonNull);
            Contract.Assume(kernel.Exits != null);
            var sortedExits = kernel.Exits.ToArray();

            Array.Sort(sortedExits, PolygonCrossing.LocationBComparer.CompareNonNull);

            for (int i = 0; i < sortedExits.Length; i++)
            {
                var exit          = sortedExits[i];
                var locationIndex = Array.BinarySearch(sortedEntrances, exit, PolygonCrossing.LocationAComparer.Default);
                if (locationIndex >= 0)
                {
                    kernel.ExitHops.Add(exit, sortedEntrances[locationIndex]);
                }
            }
            for (int i = 0; i < sortedEntrances.Length; i++)
            {
                var entrance      = sortedEntrances[i];
                var locationIndex = Array.BinarySearch(sortedExits, entrance, PolygonCrossing.LocationBComparer.Default);
                if (locationIndex >= 0)
                {
                    kernel.EntranceHops.Add(entrance, sortedExits[locationIndex]);
                }
            }

            return(kernel);
        }
Beispiel #13
0
 [Pure] private static int GetRingIndexB(PolygonCrossing crossing)
 {
     Contract.Requires(crossing != null);
     Contract.Ensures(Contract.Result <int>() >= 0);
     return(crossing.LocationB.RingIndex);
 }
Beispiel #14
0
 [Pure] private static PolygonBoundaryLocation GetLocationB(PolygonCrossing crossing)
 {
     Contract.Requires(crossing != null);
     Contract.Ensures(Contract.Result <PolygonBoundaryLocation>() != null);
     return(crossing.LocationB);
 }