Cflux
Cflux

Reputation: 1532

C# - Autocad api - Operation is not valid due to the current state of the object

I'm trying to manipulate some lines that I've drawn using the Autocad-API with c#. I usually work with Revit, but now I'm exploring AutoCAD's API.

Long story short, I have some polyline rectangles I've split up, converted to Line2D and now I'm trying to add them to another list however their information is not coming with them. The new list shows they are there but they have no startpoints or endpoints and this error occurs:

Exception thrown: 'System.InvalidOperationException' in AcdbMgd.dll
An exception of type 'System.InvalidOperationException' occurred in AcdbMgd.dll but was not handled in user code
Additional information: Operation is not valid due to the current state of the object.

I think it might have something to do with the block table record or perhaps having objects open for read? I am not sure. I've looked around for a bit but haven't found anyinformation on it. Also information on the BlockTableRecord seems to be....sparse in terms of how its used. I've only found this link which did a moderate job at explaining it with usage examples

Any and all help is appreciated.

Here is a shot of my 3dLineList: enter image description here

Here is a shot of my new 2dLinelist: enter image description here

here is my code:


// Get the current document and database, and start a transaction
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database acCurDb = doc.Database;

using (Transaction tr = acCurDb.TransactionManager.StartTransaction())
                {

                    // Open the Block table record for read
                    BlockTable acBlkTbl;
                    acBlkTbl = tr.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;
                    // Open the Block table record Model space for read
                    BlockTableRecord acBlkTblRec;
                    acBlkTblRec = tr.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;

                    List<Line> lineList3d = new List<Line>();

                    doc.Editor.WriteMessage("\nModel space objects: ");
                    // Step through each object in Model space and
                    // display the type of object found
                    foreach (ObjectId objId in acBlkTblRec)
                    {
                        doc.Editor.WriteMessage("\n" + objId.ObjectClass.DxfName);
                        if (objId.ObjectClass.DxfName == "LWPOLYLINE")
                        {

                            Polyline polyline = (Polyline)tr.GetObject(objId, OpenMode.ForRead);

                            for (int i = 0; i < polyline.NumberOfVertices; i++)
                            {
                                if (i != polyline.NumberOfVertices - 1)
                                {
                                    Point3d pt1 = polyline.GetPoint3dAt(i);
                                    Point3d pt2 = polyline.GetPoint3dAt(i + 1); // TODO: getting index out of range here. fix it. 
                                    UnitsConverter.GetConversionFactor(UnitsValue.Inches, UnitsValue.Feet);

                                    var lineSegment = new Line(pt1, pt2);

                                    lineList3d.Add(lineSegment);
                                }
                                else if (i == polyline.NumberOfVertices - 1)
                                {
                                    Point3d pt1 = polyline.GetPoint3dAt(i);
                                    Point3d pt2 = polyline.GetPoint3dAt(0);
                                    UnitsConverter.GetConversionFactor(UnitsValue.Inches, UnitsValue.Feet);

                                    var lineSegment = new Line(pt1, pt2);

                                    lineList3d.Add(lineSegment);
                                }
                            }
                        }
                        else if (objId.ObjectClass.DxfName == "LINE")
                        {
                            Line line = (Line)tr.GetObject(objId, OpenMode.ForRead);
                            lineList3d.Add(line);
                        }
                    }


                    // find the other side of the wall
                    List<Line2d> lineList2d = new List<Line2d>();
                    foreach (Line xLine3d in lineList3d)
                    {
                        
                        // convert 3dline to line2d
                        Plane linePlane = xLine3d.GetPlane();
                        Point2d line1pt1 = xLine3d.StartPoint.Convert2d(linePlane);
                        Point2d line1pt2 = xLine3d.EndPoint.Convert2d(linePlane);
                        Line2d line2d = new Line2d(line1pt1, line1pt2);
                        lineList2d.Add(line2d);

                        Debug.WriteLine("line2d: " + line2d.StartPoint); // <-- Crash occurs here


                    }
                }

Upvotes: 1

Views: 1618

Answers (2)

gileCAD
gileCAD

Reputation: 2493

Autodesk.AutoCAD.Geometry.Line2d represents an unbounded line (without start and end points). If you need a list of 2d linear segments (LineSegement2d), you can get them directly by using the Polyline.GetLineSegment2dAt() method.

        // Get the current document and database, and start a transaction
        var doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
        var ed = doc.Editor;
        var db = doc.Database;

        using (var tr = db.TransactionManager.StartTransaction())
        {

            // Open the Block table record for read
            var bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
            // Open the Block table record Model space for read
            var btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;

            var segments = new List<LineSegment2d>();

            doc.Editor.WriteMessage("\nModel space objects: ");
            // Step through each object in Model space and
            // display the type of object found
            foreach (ObjectId id in btr)
            {
                ed.WriteMessage("\n" + id.ObjectClass.DxfName);
                if (id.ObjectClass.DxfName == "LWPOLYLINE")
                {

                    var polyline = (Polyline)tr.GetObject(id, OpenMode.ForRead);

                    for (int i = 0; i < polyline.NumberOfVertices; i++)
                    {
                        if (i != polyline.NumberOfVertices - 1)
                        {
                            if (polyline.GetSegmentType(i) == SegmentType.Line)
                                segments.Add(polyline.GetLineSegment2dAt(i));
                        }
                    }
                }
                else if (id.ObjectClass.DxfName == "LINE")
                {
                    var line = (Line)tr.GetObject(id, OpenMode.ForRead);
                    var linePlane = line.GetPlane();
                    segments.Add(new LineSegment2d(line.StartPoint.Convert2d(linePlane), line.EndPoint.Convert2d(linePlane)));
                }
            }


            // find the other side of the wall
            foreach (var segment in segments)
            {
                Debug.WriteLine("line2d: " + segment.StartPoint); // <-- Crash occurs here
            }

Upvotes: 2

Cflux
Cflux

Reputation: 1532

Turns out I should have been using LineSegment2d instead of Line2d

¯_(ツ)_/¯

Upvotes: 1

Related Questions