Search code examples
c#autocad

Adding Multiple Table Records via an Iteration


I am trying to write a routine that converts a collection of points into circles. I am able to select the points and add them to a list; however, when iterating through the list I do not know how to correctly add multiple newly created circles. I tried using the AppendEntity command but it throws an eAlreadyInDb exception after the first circle. That makes sense if each object requires its own table record, but what’s the best way to add multiple records via the iteration?

Also, I am using two transactions: one to read the points and add them to the list; and another transaction to create the circles. Is that the most efficient solution?

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;

[CommandMethod("PointsToCircles")]
        public void PointsToCircles()
        {
            Document adoc = Application.DocumentManager.MdiActiveDocument;
            Database adb = adoc.Database;
            Editor acDocEd = Application.DocumentManager.MdiActiveDocument.Editor;
            List<Point3d> vlist = new List<Point3d>();
            Point3d vpoint;

            // Start a transaction
            Transaction trans = adb.TransactionManager.StartTransaction();
            {
                // Open the Block table for read
                BlockTable acBlkTbl;
                acBlkTbl = trans.GetObject(adb.BlockTableId, OpenMode.ForRead) as BlockTable;

                // Filter criteria
                TypedValue[] acTypValAr = new TypedValue[1];
                acTypValAr.SetValue(new TypedValue((int)DxfCode.Start, "POINT"), 0);
                SelectionFilter acSelFtr = new SelectionFilter(acTypValAr);
                // Select objects in the drawing area
                PromptSelectionResult acSSPrompt;
                acSSPrompt = acDocEd.GetSelection(acSelFtr);

                if (acSSPrompt.Status == PromptStatus.OK)
                {
                    SelectionSet acSSet = acSSPrompt.Value;
                    Application.ShowAlertDialog("Number of POINTS selected: " + acSSet.Count.ToString());
                    foreach (SelectedObject acSSObj in acSSet)
                    {
                        if (acSSObj != null)
                        {
                            DBPoint acDBP = trans.GetObject(acSSObj.ObjectId, OpenMode.ForRead) as DBPoint;
                            vpoint = acDBP.Position;
                            vlist.Add(vpoint);
                        }
                    }
                }
                else
                {
                    Application.ShowAlertDialog("Number of POINTS selected: 0");
                }
                trans.Commit();
            }
            

            // Start another transaction
            Transaction trans2 = adb.TransactionManager.StartTransaction();
            {
                BlockTable acBlkTbl2;
                acBlkTbl2 = trans2.GetObject(adb.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord acBlkTblRec;
                acBlkTblRec = trans2.GetObject(acBlkTbl2[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                Circle acCirc = new Circle();
                for (var i = 0; i < vlist.Count; i++)
                {
                    acCirc.Center = vlist[i];
                    acCirc.Radius = 12.00;
                    acBlkTblRec.AppendEntity(acCirc);     //Crashes here with "eAlreadyInDb" exception
                    trans2.AddNewlyCreatedDBObject(acCirc, true);
                }
                trans2.Commit();
            }
          }

Solution

  • In this way, You create one circle and add it multiple times to the same block. Once the circle is appended to the block what do You want to get when next append the same circle to the same block for the next time? Do I understand correctly You want to draw the circle for each point? In that case, You should create a new circle for each point so try this:

    for (var i = 0; i < vlist.Count; i++)
    {
        Circle acCirc = new Circle();
        acCirc.Center = vlist[i];
        acCirc.Radius = 12.00;
        acBlkTblRec.AppendEntity(acCirc);
        trans2.AddNewlyCreatedDBObject(acCirc, true);
    }