Search code examples
c#.netpolygonautocadnettopologysuite

CSharp Generate polygons from a set of intersecting lines


https://gis.stackexchange.com/questions/58245/generate-polygons-from-a-set-of-intersecting-lines

https://i.sstatic.net/UUyHF.png https://i.sstatic.net/3ClRI.png

I want to find the bounding polygon like this link.

I'm using C# nettopologysuite like the jts library shown in this link, but the polygon I want doesn't come out.

How can I extract polygons?

        Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
        Database db = doc.Database;
        Editor ed = doc.Editor;

        PromptEntityOptions pEntOpt1 = new PromptEntityOptions("Outter Boundary");
        pEntOpt1.SetRejectMessage("is Not Polyline");
        pEntOpt1.AddAllowedClass(typeof(Polyline), true);
        PromptEntityResult pEntRes1 = ed.GetEntity(pEntOpt1);

        string typeName = RXObject.GetClass(typeof(Polyline)).DxfName;
        TypedValue[] tv = new TypedValue[1] { new TypedValue((int)DxfCode.Start, typeName) };
        SelectionFilter sf = new SelectionFilter(tv);
        PromptSelectionResult pSelectRes = ed.GetSelection(sf);

        if (pSelectRes.Status != PromptStatus.OK)
            return;

        ObjectId boudaryPlineId = pEntRes1.ObjectId;
        ObjectId[] innerPlineids = pSelectRes.Value.GetObjectIds();
        ObjectIdCollection innerBoundaries = new ObjectIdCollection(innerPlineids);

        try
        {
            using (doc.LockDocument())
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    Polygonizer polygonizer = new Polygonizer();
                    GeometryFactory gf = new GeometryFactory();
                    Polyline boundaryPline = tr.GetObject(boudaryPlineId, OpenMode.ForWrite) as Polyline;
                    Coordinate[] coords = new Coordinate[boundaryPline.NumberOfVertices + 1];
                    for (int j = 0; j < boundaryPline.NumberOfVertices; j++)
                    {
                        Point3d pos = boundaryPline.GetPoint3dAt(j);
                        coords[j] = new Coordinate(pos.X, pos.Y);
                    }
                    coords[boundaryPline.NumberOfVertices] = new Coordinate(boundaryPline.StartPoint.X, boundaryPline.StartPoint.Y);
                    Polygon pg = gf.CreatePolygon(coords);
                    List<Geometry> plines = new List<Geometry>();
                    foreach (ObjectId indexid in innerBoundaries)
                    {
                        Polyline indexPline = tr.GetObject(indexid, OpenMode.ForWrite) as Polyline;
                        Coordinate[] coords2 = new Coordinate[indexPline.NumberOfVertices];
                        for (int i = 0; i < indexPline.NumberOfVertices; i++)
                        {
                            Point3d pos = indexPline.GetPoint3dAt(i);
                            coords2[i] = new Coordinate(pos.X, pos.Y);
                        }
                        LineString ls1 = new LineString(coords2);
                        polygonizer.Add(ls1);
                    }
                    ICollection<Geometry> test = polygonizer.GetPolygons();
                    foreach (Geometry polygon in test)
                    {
                        // to do 
                    }
                    tr.Commit();
                }
            }
        }
        catch
        {

        }

outter Boundary

inner Boundary

The Red Polygon I want to find

This is my second question in English, so please understand the lack of expression.

-------------- After applying the answer below --------------

        private List<NetGeometry> GetPolygons(Transaction tr, List<LineString> lineStrings)
    {
        List<NetGeometry> polygons = new List<NetGeometry>();
        Polygonizer polygonizer = new Polygonizer(false);

        GeometryFactory gf = new GeometryFactory(new PrecisionModel(10000));
        var noder = new SnapRoundingNoder(new PrecisionModel(10000)); // adjust PrecisionModel to your needs, must be fixed.
        noder.ComputeNodes(lineStrings.Select(s => (ISegmentString)new NodedSegmentString(s.Coordinates, s)).ToList());
        var noded = noder.GetNodedSubstrings();
        polygonizer.Add(noded.Select(n => (Geometry)gf.CreateLineString(n.Coordinates)).ToList());



        //for ( int i = 0; i < lineStrings.Count; i++)
        //{
        //  polygonizer.Add(lineStrings[i]);
        //}
        ICollection<NetGeometry> result = polygonizer.GetPolygons();




        foreach (NetGeometry index in result)
        {
            if ( index is Polygon pg)
            {
                polygons.Add(pg);
            }
        }
        return polygons;
    }

Results after application


Solution

  • All input geometries to Polygonizer should be LineStrings.
    The whole input set of LineStrings must be fully noded:

    var noder = new SnapRoundingNoder(new PrecisionModel(1000)); // adjust PrecisionModel to your needs, must be fixed.
    noder.ComputeNodes(lines.Select(s => (ISegmentString)new NodedSegmentString(s.Coordinates, s)).ToList());
    var noded = noder.GetNodedSubstrings();
    
    polygonizer.Add(noded.Select(n => (Geometry)gf.CreateLineString(n.Coordinates)).ToList());