/// <summary>
 /// If "swapped" is true, the loops A and B have been swapped.  This affects
 /// how arguments are passed to the given loop relation, since for example
 /// A.Contains(B) is not the same as B.Contains(A).
 /// </summary>
 public IndexCrosser(S2ShapeIndex a_index, S2ShapeIndex b_index, CrossingType type, EdgePairVisitor visitor, bool swapped)
 {
     a_index_           = a_index;
     b_index_           = b_index;
     visitor_           = visitor;
     min_crossing_sign_ = type == CrossingType.INTERIOR ? 1 : 0;
     swapped_           = swapped;
     b_query_           = new S2CrossingEdgeQuery(b_index_);
 }
        /// <summary>
        /// Given a vector of edges within an S2ShapeIndexCell, visit all pairs of
        /// crossing edges (of the given CrossingType).
        /// </summary>
        private static bool VisitCrossings(ShapeEdgeVector shape_edges, CrossingType type, bool need_adjacent, EdgePairVisitor visitor)
        {
            var min_crossing_sign = type == CrossingType.INTERIOR ? 1 : 0;
            var num_edges         = shape_edges.Count;

            for (int i = 0; i + 1 < num_edges; i++)
            {
                var a = shape_edges[i];
                var j = i + 1;

                // A common situation is that an edge AB is followed by an edge BC.  We
                // only need to visit such crossings if "need_adjacent" is true (even if
                // AB and BC belong to different edge chains).
                if (!need_adjacent && a.V1 == shape_edges[j].V0)
                {
                    j++;
                    if (j >= num_edges)
                    {
                        break;
                    }
                }

                var crosser = new S2EdgeCrosser(a.V0, a.V1);
                for (; j < num_edges; j++)
                {
                    var b = shape_edges[j];
                    if (crosser.C == S2Point.Empty || crosser.C != b.V0)
                    {
                        crosser.RestartAt(b.V0);
                    }
                    var sign = crosser.CrossingSign(b.V1);
                    if (sign >= min_crossing_sign)
                    {
                        if (!visitor(a, b, sign == 1))
                        {
                            return(false);
                        }
                    }
                }
            }
            return(true);
        }
        /// <summary>
        /// Visits all pairs of crossing edges in the given S2ShapeIndex, terminating
        /// early if the given EdgePairVisitor function returns false (in which case
        /// VisitCrossings returns false as well).  "type" indicates whether all
        /// crossings should be visited, or only interior crossings.
        ///
        /// CAVEAT: Crossings may be visited more than once.
        /// </summary>
        public static bool VisitCrossingEdgePairs(S2ShapeIndex index, CrossingType type, EdgePairVisitor visitor)
        {
            var needAdjacent = type == CrossingType.ALL;

            return(VisitCrossings(index, type, needAdjacent, visitor));
        }
        /// <summary>
        /// Like the above, but visits all pairs of crossing edges where one edge comes
        /// from each S2ShapeIndex.
        ///
        /// CAVEAT: Crossings may be visited more than once.
        /// </summary>
        public static bool VisitCrossingEdgePairs(S2ShapeIndex a_index, S2ShapeIndex b_index, CrossingType type, EdgePairVisitor visitor)
        {
            // We look for S2CellId ranges where the indexes of A and B overlap, and
            // then test those edges for crossings.

            // TODO(ericv): Use brute force if the total number of edges is small enough
            // (using a larger threshold if the S2ShapeIndex is not constructed yet).
            var ai = new RangeEnumerator(a_index);
            var bi = new RangeEnumerator(b_index);
            var ab = new IndexCrosser(a_index, b_index, type, visitor, false);  // Tests A against B
            var ba = new IndexCrosser(b_index, a_index, type, visitor, true);   // Tests B against A

            while (!ai.Done() || !bi.Done())
            {
                if (ai.RangeMax < bi.RangeMin)
                {
                    // The A and B cells don't overlap, and A precedes B.
                    ai.SeekTo(bi);
                }
                else if (bi.RangeMax < ai.RangeMin)
                {
                    // The A and B cells don't overlap, and B precedes A.
                    bi.SeekTo(ai);
                }
                else
                {
                    // One cell contains the other.  Determine which cell is larger.
                    var ab_relation = ai.Id.LowestOnBit() - bi.Id.LowestOnBit();
                    if (ab_relation > 0)
                    {
                        // A's index cell is larger.
                        if (!ab.VisitCrossings(ai, bi))
                        {
                            return(false);
                        }
                    }
                    else if (ab_relation < 0)
                    {
                        // B's index cell is larger.
                        if (!ba.VisitCrossings(bi, ai))
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        // The A and B cells are the same.
                        if (ai.Cell.NumEdges() > 0 && bi.Cell.NumEdges() > 0)
                        {
                            if (!ab.VisitCellCellCrossings(ai.Cell, bi.Cell))
                            {
                                return(false);
                            }
                        }
                        ai.MoveNext();
                        bi.MoveNext();
                    }
                }
            }
            return(true);
        }
        /// <summary>
        /// Visits all pairs of crossing edges in the given S2ShapeIndex, terminating
        /// early if the given EdgePairVisitor function returns false (in which case
        /// VisitCrossings returns false as well).  "type" indicates whether all
        /// crossings should be visited, or only interior crossings.
        ///
        /// If "need_adjacent" is false, then edge pairs of the form (AB, BC) may
        /// optionally be ignored (even if the two edges belong to different edge
        /// chains).  This option exists for the benefit of FindSelfIntersection(),
        /// which does not need such edge pairs (see below).
        /// </summary>
        private static bool VisitCrossings(S2ShapeIndex index, CrossingType type, bool need_adjacent, EdgePairVisitor visitor)
        {
            // TODO(ericv): Use brute force if the total number of edges is small enough
            // (using a larger threshold if the S2ShapeIndex is not constructed yet).
            var count = index.GetEnumerableCount();

            for (var pos = 0; pos < count; pos++)
            {
                var shape_edges = new ShapeEdgeVector();
                var icell       = index.GetIndexCell(pos);
                var indexCell   = icell.Value.Item2;
                GetShapeEdges(index, indexCell, shape_edges);
                if (!VisitCrossings(shape_edges, type, need_adjacent, visitor))
                {
                    return(false);
                }
            }
            return(true);
        }