Пример #1
0
 // Converts a 0-dimensional S2Shape into a list of S2Points.
 // This method does allow an empty shape (i.e. a shape with no vertices).
 public static List<S2Point> ShapeToS2Points(S2Shape multipoint)
 {
     System.Diagnostics.Debug.Assert(multipoint.Dimension() == 0);
     List<S2Point> points = new();
     points.Capacity = multipoint.NumEdges();
     for (int i = 0; i < multipoint.NumEdges(); ++i)
     {
         points.Add(multipoint.GetEdge(i).V0);
     }
     return points;
 }
Пример #2
0
    // This is a helper function for GetReferencePoint() below.
    //
    // If the given vertex "vtest" is unbalanced (see definition below), sets
    // "result" to a ReferencePoint indicating whther "vtest" is contained and
    // returns true.  Otherwise returns false.
    private static bool GetReferencePointAtVertex(S2Shape shape, S2Point vtest, out S2Shape.ReferencePoint result)
    {
        // Let P be an unbalanced vertex.  Vertex P is defined to be inside the
        // region if the region contains a particular direction vector starting from
        // P, namely the direction S2::RefDir(P).  This can be calculated using
        // S2ContainsVertexQuery.
        var contains_query = new S2ContainsVertexQuery(vtest);
        int n = shape.NumEdges();

        for (int e = 0; e < n; ++e)
        {
            var edge = shape.GetEdge(e);
            if (edge.V0 == vtest)
            {
                contains_query.AddEdge(edge.V1, 1);
            }
            if (edge.V1 == vtest)
            {
                contains_query.AddEdge(edge.V0, -1);
            }
        }
        int contains_sign = contains_query.ContainsSign();

        if (contains_sign == 0)
        {
            result = new S2Shape.ReferencePoint(S2Point.Empty, false);
            return(false);  // There are no unmatched edges incident to this vertex.
        }
        result = new S2Shape.ReferencePoint(vtest, contains_sign > 0);
        return(true);
    }
Пример #3
0
 /// <summary>
 /// Verifies that all methods of the two S2Shapes return identical results,
 /// except for id() and type_tag().
 /// </summary>
 public static void ExpectEqual(S2Shape a, S2Shape b)
 {
     Assert.True(a.NumEdges() == b.NumEdges());
     for (int i = 0; i < a.NumEdges(); ++i)
     {
         Assert.Equal(a.GetEdge(i), b.GetEdge(i));
         Assert.True(a.GetChainPosition(i) == b.GetChainPosition(i));
     }
     Assert.True(a.Dimension() == b.Dimension());
     Assert.True(a.GetReferencePoint() == b.GetReferencePoint());
     Assert.True(a.NumChains() == b.NumChains());
     for (int i = 0; i < a.NumChains(); ++i)
     {
         Assert.True(a.GetChain(i) == b.GetChain(i));
         int chain_length = a.GetChain(i).Length;
         for (int j = 0; j < chain_length; ++j)
         {
             Assert.True(a.ChainEdge(i, j) == b.ChainEdge(i, j));
         }
     }
 }
        private static void AddShapeWithLabels(S2Shape shape, EdgeType edge_type,
                                               S2Builder builder, EdgeLabelMap edge_label_map)
        {
            const int kLabelBegin = 1234;  // Arbitrary.

            for (int e = 0; e < shape.NumEdges(); ++e)
            {
                Int32 label = kLabelBegin + e;
                builder.SetLabel(label);
                // For undirected edges, reverse the direction of every other input edge.
                S2Shape.Edge edge = shape.GetEdge(e);
                if (edge_type == EdgeType.UNDIRECTED && ((e & 1) != 0))
                {
                    edge = new S2Shape.Edge(edge.V1, edge.V0);
                }
                builder.AddEdge(edge.V0, edge.V1);
                edge_label_map[GetKey(edge, edge_type)].Add(label);
            }
        }
Пример #5
0
    // Returns true if the given shape contains the given point.  Most clients
    // should not use this method, since its running time is linear in the number
    // of shape edges.  Instead clients should create an S2ShapeIndex and use
    // S2ContainsPointQuery, since this strategy is much more efficient when many
    // points need to be tested.
    //
    // Polygon boundaries are treated as being semi-open (see S2ContainsPointQuery
    // and S2VertexModel for other options).
    //
    // CAVEAT: Typically this method is only used internally.  Its running time is
    //         linear in the number of shape edges.
    public static bool ContainsBruteForce(this S2Shape shape, S2Point point)
    {
        if (shape.Dimension() < 2)
        {
            return(false);
        }

        var ref_point = shape.GetReferencePoint();

        if (ref_point.Point == point)
        {
            return(ref_point.Contained);
        }

        S2CopyingEdgeCrosser crosser = new(ref_point.Point, point);
        bool inside = ref_point.Contained;

        for (int e = 0; e < shape.NumEdges(); ++e)
        {
            var edge = shape.GetEdge(e);
            inside ^= crosser.EdgeOrVertexCrossing(edge.V0, edge.V1);
        }
        return(inside);
    }
Пример #6
0
    // This is a helper function for implementing S2Shape.GetReferencePoint().
    //
    // Given a shape consisting of closed polygonal loops, the interior of the
    // shape is defined as the region to the left of all edges (which must be
    // oriented consistently).  This function then chooses an arbitrary point and
    // returns true if that point is contained by the shape.
    //
    // Unlike S2Loop and S2Polygon, this method allows duplicate vertices and
    // edges, which requires some extra care with definitions.  The rule that we
    // apply is that an edge and its reverse edge "cancel" each other: the result
    // is the same as if that edge pair were not present.  Therefore shapes that
    // consist only of degenerate loop(s) are either empty or full; by convention,
    // the shape is considered full if and only if it contains an empty loop (see
    // S2LaxPolygonShape for details).
    //
    // Determining whether a loop on the sphere contains a point is harder than
    // the corresponding problem in 2D plane geometry.  It cannot be implemented
    // just by counting edge crossings because there is no such thing as a "point
    // at infinity" that is guaranteed to be outside the loop.
    public static S2Shape.ReferencePoint GetReferencePoint(this S2Shape shape)
    {
        System.Diagnostics.Debug.Assert(shape.Dimension() == 2);
        if (shape.NumEdges() == 0)
        {
            // A shape with no edges is defined to be full if and only if it
            // contains at least one chain.
            return(S2Shape.ReferencePoint.FromContained(shape.NumChains() > 0));
        }
        // Define a "matched" edge as one that can be paired with a corresponding
        // reversed edge.  Define a vertex as "balanced" if all of its edges are
        // matched. In order to determine containment, we must find an unbalanced
        // vertex.  Often every vertex is unbalanced, so we start by trying an
        // arbitrary vertex.
        var edge = shape.GetEdge(0);

        if (GetReferencePointAtVertex(shape, edge.V0, out var result))
        {
            return(result);
        }
        // That didn't work, so now we do some extra work to find an unbalanced
        // vertex (if any).  Essentially we gather a list of edges and a list of
        // reversed edges, and then sort them.  The first edge that appears in one
        // list but not the other is guaranteed to be unmatched.
        int n         = shape.NumEdges();
        var edges     = new S2Shape.Edge[n];
        var rev_edges = new S2Shape.Edge[n];

        for (int i = 0; i < n; ++i)
        {
            var edge2 = shape.GetEdge(i);
            edges[i]     = edge2;
            rev_edges[i] = new S2Shape.Edge(edge2.V1, edge2.V0);
        }
        Array.Sort(edges);
        Array.Sort(rev_edges);
        for (int i = 0; i < n; ++i)
        {
            if (edges[i] < rev_edges[i])
            {  // edges[i] is unmatched
                System.Diagnostics.Debug.Assert(GetReferencePointAtVertex(shape, edges[i].V0, out result));
                return(result);
            }
            if (rev_edges[i] < edges[i])
            {  // rev_edges[i] is unmatched
                System.Diagnostics.Debug.Assert(GetReferencePointAtVertex(shape, rev_edges[i].V0, out result));
                return(result);
            }
        }
        // All vertices are balanced, so this polygon is either empty or full except
        // for degeneracies.  By convention it is defined to be full if it contains
        // any chain with no edges.
        for (int i = 0; i < shape.NumChains(); ++i)
        {
            if (shape.GetChain(i).Length == 0)
            {
                return(S2Shape.ReferencePoint.FromContained(true));
            }
        }
        return(S2Shape.ReferencePoint.FromContained(false));
    }