// Converts "input_str" to an S2LaxPolygonShape, assigns labels to its edges,
        // then uses LaxPolygonLayer with the given arguments to build a new
        // S2LaxPolygonShape and verifies that all edges have the expected labels.
        // (This function does not test whether the output edges are correct.)
        private static void TestEdgeLabels(string input_str, EdgeType edge_type,
                                           DegenerateBoundaries degenerate_boundaries)
        {
            S2Builder         builder           = new(new Options());
            S2LaxPolygonShape output            = new();
            LabelSetIds       label_set_ids     = new();
            IdSetLexicon      label_set_lexicon = new();

            LaxPolygonLayer.Options options = new();
            options.EdgeType = (edge_type);
            options.DegenerateBoundaries_ = (degenerate_boundaries);
            builder.StartLayer(new LaxPolygonLayer(
                                   output, label_set_ids, label_set_lexicon, options));

            EdgeLabelMap edge_label_map = new();

            AddShapeWithLabels(MakeLaxPolygonOrDie(input_str), edge_type,
                               builder, edge_label_map);
            Assert.True(builder.Build(out _));
            for (int i = 0; i < output.NumChains(); ++i)
            {
                for (int j = 0; j < output.GetChain(i).Length; ++j)
                {
                    S2Shape.Edge edge            = output.ChainEdge(i, j);
                    var          expected_labels = edge_label_map[GetKey(edge, edge_type)];
                    Assert.Equal(expected_labels.Count,
                                 label_set_lexicon.IdSet_(label_set_ids[i][j]).Count);
                    Assert.True(expected_labels.SequenceEqual(label_set_lexicon.IdSet_(label_set_ids[i][j])));
                }
            }
        }
 private static S2Shape.Edge GetKey(S2Shape.Edge edge, EdgeType edge_type)
 {
     // For undirected edges, sort the vertices in lexicographic order.
     if (edge_type == EdgeType.UNDIRECTED && edge.V0 > edge.V1)
     {
         edge = new S2Shape.Edge(edge.V1, edge.V0);
     }
     return(edge);
 }
        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);
            }
        }
Ejemplo n.º 4
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));
    }
Ejemplo n.º 5
0
 public ShapeEdge(Int32 shape_id, Int32 edge_id, S2Shape.Edge edge)
     : this(new(shape_id, edge_id), edge.V0, edge.V1)