/// <summary>
            /// Visits all crossings of the current edge with all edges of the given index
            /// cell of B.  Terminates early and returns false if visitor_ returns false.
            /// </summary>
            private bool VisitEdgeCellCrossings(ShapeEdge a, S2ShapeIndexCell b_cell)
            {
                // Test the current edge of A against all edges of "b_cell".

                // Note that we need to use a new S2EdgeCrosser (or call Init) whenever we
                // replace the contents of b_shape_edges_, since S2EdgeCrosser requires that
                // its S2Point arguments point to values that persist between Init() calls.
                GetShapeEdges(b_index_, b_cell, b_shape_edges_);
                var crosser = new S2EdgeCrosser(a.V0, a.V1);

                foreach (var b in b_shape_edges_)
                {
                    if (crosser.C == S2Point.Empty || crosser.C != b.V0)
                    {
                        crosser.RestartAt(b.V0);
                    }
                    int sign = crosser.CrossingSign(b.V1);
                    if (sign >= min_crossing_sign_)
                    {
                        if (!VisitEdgePair(a, b, sign == 1))
                        {
                            return(false);
                        }
                    }
                }
                return(true);
            }
        /// <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);
        }
 // Visits all crossings of any edge in "a_edges" with any edge in "b_edges".
 private bool VisitEdgesEdgesCrossings(ShapeEdgeVector a_edges, ShapeEdgeVector b_edges)
 {
     // Test all edges of "a_edges" against all edges of "b_edges".
     foreach (var a in a_edges)
     {
         var crosser = new S2EdgeCrosser(a.V0, a.V1);
         foreach (var b in b_edges)
         {
             if (crosser.C == S2Point.Empty || crosser.C != b.V0)
             {
                 crosser.RestartAt(b.V0);
             }
             int sign = crosser.CrossingSign(b.V1);
             if (sign >= min_crossing_sign_)
             {
                 if (!VisitEdgePair(a, b, sign == 1))
                 {
                     return(false);
                 }
             }
         }
     }
     return(true);
 }