private static List <PolygonCrossing> GenerateRingCrossingsBruteForce(Ring2 ringA, Ring2 ringB, int ringIndexA, int ringIndexB)
        {
            Contract.Requires(ringA != null);
            Contract.Requires(ringA.Count > 0);
            Contract.Requires(ringB != null);
            Contract.Requires(ringB.Count > 0);
            Contract.Requires(ringIndexA >= 0);
            Contract.Requires(ringIndexB >= 0);
            Contract.Ensures(Contract.Result <List <PolygonCrossing> >() != null);

            var ringACount         = ringA.Count;
            var ringBCount         = ringB.Count;
            var segmentStartIndexA = ringACount - 1;
            var b         = ringA[segmentStartIndexA];
            var crossings = new List <PolygonCrossing>();

            for (int segmentEndIndexA = 0; segmentEndIndexA < ringACount; segmentStartIndexA = segmentEndIndexA++)
            {
                var a = b;
                b = ringA[segmentEndIndexA];
                var segmentDataA = new Segment2Data(
                    new Segment2(a, b),
                    segmentStartIndexA,
                    ringIndexA
                    );
                var segmentMbrA        = segmentDataA.Segment.GetMbr();
                var segmentStartIndexB = ringBCount - 1;
                var d = ringB[segmentStartIndexB];
                for (int segmentEndIndexB = 0; segmentEndIndexB < ringBCount; segmentStartIndexB = segmentEndIndexB++)
                {
                    var c = d;
                    d = ringB[segmentEndIndexB];
                    if (!segmentMbrA.Intersects(c, d))
                    {
                        continue;
                    }

                    AddPointCrossings(
                        crossings,
                        segmentDataA,
                        new Segment2Data(
                            new Segment2(c, d),
                            segmentStartIndexB,
                            ringIndexB
                            )
                        );
                }
            }
            return(crossings);
        }
        private static PolygonCrossing CreatePolygonCrossing(
            SegmentIntersectionOperation.PointResult pointResult,
            Segment2Data segmentDataA, Segment2Data segmentDataB
            )
        {
            Contract.Ensures(Contract.Result <PolygonCrossing>() != null);

            Contract.Assume(segmentDataA.RingIndex >= 0);
            Contract.Assume(segmentDataA.SegmentIndex >= 0);
            Contract.Assume(segmentDataB.RingIndex >= 0);
            Contract.Assume(segmentDataB.SegmentIndex >= 0);

            return(new PolygonCrossing(
                       pointResult.P,
                       new PolygonBoundaryLocation(segmentDataA.RingIndex, segmentDataA.SegmentIndex, pointResult.S),
                       new PolygonBoundaryLocation(segmentDataB.RingIndex, segmentDataB.SegmentIndex, pointResult.T)
                       ));
        }
        private static void AddPointCrossings(List <PolygonCrossing> results, Segment2Data segmentDataA, Segment2Data segmentDataB)
        {
            Contract.Requires(results != null);
            Contract.Ensures(results.Count >= Contract.OldValue(results).Count);

            Contract.Assume(null != segmentDataA.Segment);
            Contract.Assume(null != segmentDataB.Segment);

            var intersectionDetails = SegmentIntersectionOperation.IntersectionDetails(segmentDataA.Segment, segmentDataB.Segment);

            if (intersectionDetails is SegmentIntersectionOperation.PointResult)
            {
                var pointResult = (SegmentIntersectionOperation.PointResult)intersectionDetails;
                if (IsNotHead(pointResult))
                {
                    results.Add(CreatePolygonCrossing(pointResult, segmentDataA, segmentDataB));
                }
            }
            else if (intersectionDetails is SegmentIntersectionOperation.SegmentResult)
            {
                var segmentResult = intersectionDetails as SegmentIntersectionOperation.SegmentResult;
                var bIsNotHead    = IsNotHead(segmentResult.B);
                if (IsNotHead(segmentResult.A))
                {
                    var resultA = CreatePolygonCrossing(segmentResult.A, segmentDataA, segmentDataB);
                    if (bIsNotHead)
                    {
                        results.AddRange(new[] { resultA, CreatePolygonCrossing(segmentResult.B, segmentDataA, segmentDataB) });
                    }
                    else
                    {
                        results.Add(resultA);
                    }
                }
                else if (bIsNotHead)
                {
                    results.Add(CreatePolygonCrossing(segmentResult.B, segmentDataA, segmentDataB));
                }
            }
        }
        /// <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);
        }