public void AddEdges(S2Cap index_cap, int num_edges, MutableS2ShapeIndex index)
    {
        var fractal = new S2Testing.Fractal();

        fractal.SetLevelForApproxMaxEdges(num_edges);
        index.Add(new S2Loop.Shape(
                      fractal.MakeLoop(S2Testing.GetRandomFrameAt(index_cap.Center),
                                       index_cap.RadiusAngle())));
    }
    public void AddEdges(S2Cap index_cap, int num_edges, MutableS2ShapeIndex index)
    {
        var points = new List <S2Point>();

        for (int i = 0; i < num_edges; ++i)
        {
            points.Add(S2Testing.SamplePoint(index_cap));
        }
        index.Add(new S2PointVectorShape(points.ToArray()));
    }
    public void Test_S2ShapeIndexBufferedRegion_EmptyIndex()
    {
        // Test buffering an empty S2ShapeIndex.
        var         index    = new MutableS2ShapeIndex();
        var         radius   = new S1ChordAngle(S1Angle.FromDegrees(2));
        var         region   = new S2ShapeIndexBufferedRegion(index, radius);
        var         coverer  = new S2RegionCoverer();
        S2CellUnion covering = coverer.GetCovering(region);

        Assert.True(covering.IsEmpty());
    }
Beispiel #4
0
 public VisitIntersectingShapesTest(S2ShapeIndex index)
 {
     index_  = index;
     iter_   = new(index);
     region_ = new(index);
     // Create an S2ShapeIndex for each shape in the original index, so that we
     // can use MayIntersect() and Contains() to determine the status of
     // individual shapes.
     for (int s = 0; s < index_.NumShapeIds(); ++s)
     {
         var shape_index = new MutableS2ShapeIndex();
         shape_index.Add(new S2WrappedShape(index_.Shape(s)));
         shape_indexes_.Add(shape_index);
     }
 }
Beispiel #5
0
    // As above, but does not Debug.Assert-fail on invalid input. Returns true if
    // conversion is successful.
    public static bool MakeIndex(string str, out MutableS2ShapeIndex index)
    {
        index = null;
        var result = new MutableS2ShapeIndex();
        var strs   = str.Split('#');

        System.Diagnostics.Debug.Assert(3 == strs.Length);

        var points = new List <S2Point>();

        foreach (var point_str in SplitString(strs[0], '|'))
        {
            if (!MakePoint(point_str, out var point))
            {
                return(false);
            }
            points.Add(point);
        }
        if (points.Any())
        {
            result.Add(new S2PointVectorShape(points.ToArray()));
        }
        foreach (var line_str in SplitString(strs[1], '|'))
        {
            if (!MakeLaxPolyline(line_str, out var lax_polyline))
            {
                return(false);
            }
            result.Add(lax_polyline);
        }
        foreach (var polygon_str in SplitString(strs[2], '|'))
        {
            if (!MakeLaxPolygon(polygon_str, out var lax_polygon))
            {
                return(false);
            }
            result.Add(lax_polygon);
        }
        index = result;
        return(true);
    }
Beispiel #6
0
    // The purpose of this function is to construct polygons consisting of
    // multiple loops.  It takes as input a collection of loops whose boundaries
    // do not cross, and groups them into polygons whose interiors do not
    // intersect (where the boundary of each polygon may consist of multiple
    // loops).
    //
    // some of those islands have lakes, then the input to this function would
    // islands, and their lakes.  Each loop would actually be present twice, once
    // in each direction (see below).  The output would consist of one polygon
    // representing each lake, one polygon representing each island not including
    // islands or their lakes, and one polygon representing the rest of the world
    //
    // This method is intended for internal use; external clients should use
    // S2Builder, which has more convenient interface.
    //
    // The input consists of a set of connected components, where each component
    // consists of one or more loops.  The components must satisfy the following
    // properties:
    //
    //  - The loops in each component must form a subdivision of the sphere (i.e.,
    //    they must cover the entire sphere without overlap), except that a
    //    component may consist of a single loop if and only if that loop is
    //    degenerate (i.e., its interior is empty).
    //
    //  - The boundaries of different components must be disjoint (i.e. no
    //    crossing edges or shared vertices).
    //
    //  - No component should be empty, and no loop should have zero edges.
    //
    // The output consists of a set of polygons, where each polygon is defined by
    // the collection of loops that form its boundary.  This function does not
    // actually construct any S2Shapes; it simply identifies the loops that belong
    // to each polygon.
    public static void BuildPolygonBoundaries(List <List <S2Shape> > components, List <List <S2Shape> > polygons)
    {
        polygons.Clear();
        if (!components.Any())
        {
            return;
        }

        // Since the loop boundaries do not cross, a loop nesting hierarchy can be
        // defined by choosing any point on the sphere as the "point at infinity".
        // Loop A then contains loop B if (1) A contains the boundary of B and (2)
        // loop A does not contain the point at infinity.
        //
        // We choose S2.Origin for this purpose.  The loop nesting hierarchy then
        // determines the face structure.  Here are the details:
        //
        // 1. Build an S2ShapeIndex of all loops that do not contain S2.Origin.
        //    This leaves at most one unindexed loop per connected component
        //    (the "outer loop").
        //
        // 2. For each component, choose a representative vertex and determine
        //    which indexed loops contain it.  The "depth" of this component is
        //    defined as the number of such loops.
        //
        // 3. Assign the outer loop of each component to the containing loop whose
        //    depth is one less.  This generates a set of multi-loop polygons.
        //
        // 4. The outer loops of all components at depth 0 become a single face.

        var index = new MutableS2ShapeIndex();
        // A map from shape.id() to the corresponding component number.
        var component_ids = new List <int>();
        var outer_loops   = new List <S2Shape>();

        for (int i = 0; i < components.Count; ++i)
        {
            var component = components[i];
            foreach (var loop in component)
            {
                if (component.Count > 1 &&
                    !loop.ContainsBruteForce(S2.Origin))
                {
                    // Ownership is transferred back at the end of this function.
                    index.Add(loop);
                    component_ids.Add(i);
                }
                else
                {
                    outer_loops.Add(loop);
                }
            }
            // Check that there is exactly one outer loop in each component.
            System.Diagnostics.Debug.Assert(i + 1 == outer_loops.Count); // Component is not a subdivision
        }
        // Find the loops containing each component.
        var ancestors      = new List <List <S2Shape> >(components.Count);
        var contains_query = index.MakeS2ContainsPointQuery();

        for (int i = 0; i < outer_loops.Count; ++i)
        {
            var loop = outer_loops[i];
            System.Diagnostics.Debug.Assert(loop.NumEdges() > 0);
            ancestors[i] = contains_query.GetContainingShapes(loop.GetEdge(0).V0);
        }
        // Assign each outer loop to the component whose depth is one less.
        // Components at depth 0 become a single face.
        Dictionary <S2Shape, List <S2Shape> > children = new(); // btree_map

        for (int i = 0; i < outer_loops.Count; ++i)
        {
            S2Shape?ancestor = null;
            int     depth    = ancestors[i].Count;
            if (depth > 0)
            {
                foreach (var candidate in ancestors[i])
                {
                    if (ancestors[component_ids[candidate.Id]].Count == depth - 1)
                    {
                        System.Diagnostics.Debug.Assert(ancestor is null);
                        ancestor = candidate;
                    }
                }
                System.Diagnostics.Debug.Assert(ancestor is not null);
            }
            S2Shape notNullAncestor = ancestor !;
            if (!children.ContainsKey(notNullAncestor))
            {
                children.Add(notNullAncestor, new List <S2Shape>());
            }
            children[notNullAncestor].Add(outer_loops[i]);
        }
        // There is one face per loop that is not an outer loop, plus one for the
        // outer loops of components at depth 0.
        polygons.Resize(index.NumShapeIds() + 1, () => new List <S2Shape>());
        for (int i = 0; i < index.NumShapeIds(); ++i)
        {
            var polygon = polygons[i];
            var loop    = index.Shape(i);
            var itr     = children.ContainsKey(loop) ? children[loop] : null;
            if (itr != null)
            {
                polygon = itr;
            }
            polygon.Add(loop);
        }
        polygons[^ 1] = children[null];
 public void AddEdges(S2Cap index_cap, int num_edges, MutableS2ShapeIndex index)
 {
     index.Add(new S2Loop.Shape(S2Loop.MakeRegularLoop(
                                    index_cap.Center, index_cap.RadiusAngle(), num_edges)));
 }