// 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 void TestLaxPolygon(string input_str, string expected_str,
                                    EdgeType edge_type, DegenerateBoundaries degenerate_boundaries)
        {
            _logger.WriteLine(degenerate_boundaries.ToString());
            S2Builder         builder = new(new Options());
            S2LaxPolygonShape output  = new();

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

            var polygon = MakeLaxPolygonOrDie(input_str);

            builder.AddShape(polygon);

            // In order to construct polygons that are full except possibly for a
            // collection of degenerate holes, we must supply S2Builder with a predicate
            // that distinguishes empty polygons from full ones (modulo degeneracies).
            bool has_full_loop = false;

            for (int i = 0; i < polygon.NumLoops; ++i)
            {
                if (polygon.NumLoopVertices(i) == 0)
                {
                    has_full_loop = true;
                }
            }
            builder.AddIsFullPolygonPredicate(IsFullPolygon(has_full_loop));
            Assert.True(builder.Build(out _));
            string actual_str = output.ToDebugString("; ");

            Assert.Equal(expected_str, actual_str);
        }
        private void TestLaxPolygon(string input_str,
                                    string expected_str,
                                    DegenerateBoundaries degenerate_boundaries)
        {
            TestLaxPolygon(input_str, expected_str, EdgeType.DIRECTED,
                           degenerate_boundaries);
#if false
            // TODO(ericv): Implement.
            TestLaxPolygon(input_str, expected_str, EdgeType.UNDIRECTED,
                           degenerate_boundaries);
#endif
        }
 private void TestLaxPolygonUnchanged(string input_str,
                                      DegenerateBoundaries degenerate_boundaries)
 {
     TestLaxPolygon(input_str, input_str, degenerate_boundaries);
 }