Hey Everyone,
I'm working on a command that lets me select polylines on a specific layer, then converts them to 3d solids. I'm having a slight issue where if a polyline has the same start and end coordinates (this happens in some of our drawings), then the command stops and I get an eDegenerateGeometry error. I want to modify my command so that it detects these objects, removes them from the selection set, and then notifies the users of their prescence so they can be removed manually. The last part i think I can handle, however I'm not sure how to modify either my filter or my routine to detect and ignore these objects. I'm assuming that since i'll want to record these objects to later notify the user, that i'd probably want to modify my routine. Any pointers or examples would be greatly appreciated.
Cheers
Vince
using System; using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.DataExtraction; using Autodesk.AutoCAD.Colors; using System.Windows.Forms; namespace Convert3D { public class Convert3D { [CommandMethod("test3d")] public void test() { // Go to if layer name doesn't exist Step1: Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; string sreslayer = ""; //////////////////////////////////////////////////////////////////////////////// ////////////////////////// Get layer by selection ////////////////////////////// Transaction trans = db.TransactionManager.StartTransaction(); using (trans) { PromptSelectionOptions sopts = new PromptSelectionOptions(); sopts.MessageForAdding = "Select an object on the layer you would like to modify"; PromptSelectionResult layerres = doc.Editor.GetSelection(sopts); if (layerres.Status == PromptStatus.OK) { foreach (ObjectId id in layerres.Value.GetObjectIds()) { Entity acadent = (Entity)trans.GetObject(id, OpenMode.ForRead); sreslayer = acadent.Layer; ed.WriteMessage("The layer you have selected is " + sreslayer); } } ///////////////////////////////////////////////////////////////////////////// // This time we do check whether the layer exists LayerTable lt = (LayerTable)trans.GetObject(db.LayerTableId, OpenMode.ForRead); if (!lt.Has(sreslayer)) { ed.WriteMessage("\nLayer not found."); ed.WriteMessage("\nTry Again."); //If layername doesn't exist, re-run the command goto Step1; } } // Limits selection by layer and object type SelectionFilter filt = new SelectionFilter(new TypedValue[]{ new TypedValue(8,sreslayer), new TypedValue(0,"polyline")}); PromptSelectionResult res = ed.GetSelection(filt); if (res.Status != PromptStatus.OK) return; SelectionSet sset = res.Value; Entity ent; PromptDoubleOptions pdouble = new PromptDoubleOptions("\nEnter new diameter of pipe: "); pdouble.AllowNegative = false; pdouble.AllowZero = false; PromptDoubleResult pres = ed.GetDouble(pdouble); // radius of cylinder double rad = pres.Value; using (Transaction tr = doc.TransactionManager.StartTransaction()) { ////////////////////////////////////////////////////////////////////////// //////////////////Creates a new 3d layer for the 3d solids/////////////// LayerTable acLyrTbl1 = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable; LayerTableRecord acLyrTblRec = new LayerTableRecord(); // Check if the layer exists, if not create it, if so, continue on if (acLyrTbl1.Has(sreslayer+"-3D") == true) { goto Step2; } if (acLyrTbl1.Has(sreslayer) == true) { // Assign the layer a name acLyrTblRec.Name = sreslayer+"-3D"; acLyrTbl1.UpgradeOpen(); // Append the new layer to the Layer table and the transaction acLyrTbl1.Add(acLyrTblRec); tr.AddNewlyCreatedDBObject(acLyrTblRec, true); } /////////////////////////////////////////////////////////////////////////// Step2: BlockTableRecord btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord; foreach (SelectedObject obj in sset) { ent = tr.GetObject(obj.ObjectId, OpenMode.ForRead) as Entity; if (ent == null) return; Polyline3d poly = ent as Polyline3d; if (poly == null) return; Point3d p1 = poly.GetPointAtParameter(poly.StartParam); Point3d p2 = poly.GetPointAtParameter(poly.StartParam + 1.0); Vector3d vec = (p2 - p1).GetNormal(); double height = p1.DistanceTo(p2); Circle circ = new Circle(p1, vec, rad); circ.Normal = vec; ObjectId objId = btr.AppendEntity(circ); // Set the layer in which to create the 3d solids circ.Layer = sreslayer+"-3D"; tr.AddNewlyCreatedDBObject(circ, true); // Get the boundary curves to create a region DBObjectCollection regs = new DBObjectCollection(); regs.Add(circ); // Create a region from the circle. DBObjectCollection regions = new DBObjectCollection(); regions = Region.CreateFromCurves(regs); if (regions.Count == 0) { ed.WriteMessage("\nFailed to create region\n"); return; } Region reg = (Region)regions[0]; // Extrude the region to create a solid. Solid3d sol = new Solid3d(); sol.Layer = sreslayer + "-3D"; sol.RecordHistory = true;// optional sol.ShowHistory = false;// optional sol.ExtrudeAlongPath(reg, poly as Curve, 0.0); ObjectId solId = ObjectId.Null; solId = btr.AppendEntity(sol); tr.AddNewlyCreatedDBObject(sol, true); if (!circ.IsWriteEnabled) circ.UpgradeOpen(); circ.Erase(); } tr.Commit(); } } } }
Hi,
You can use the Editor.SelectionAdded event to filter during the selection.
[CommandMethod("Test", CommandFlags.Modal)] public void Test() { Document doc = AcAp.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; using (Transaction tr = db.TransactionManager.StartTransaction()) { TypedValue[] filter = { new TypedValue(0, "LWPOLYLINE") }; ed.SelectionAdded += ed_SelectionAdded; PromptSelectionResult psr = ed.GetSelection(new SelectionFilter(filter)); ed.SelectionAdded -= ed_SelectionAdded; if (psr.Status != PromptStatus.OK) return; ed.SetImpliedSelection(psr.Value); tr.Commit(); } } void ed_SelectionAdded(object sender, SelectionAddedEventArgs e) { ObjectId[] ids = e.AddedObjects.GetObjectIds(); for (int i = 0; i < ids.Length; i++) { using (Polyline pline = (Polyline)ids[i].Open(OpenMode.ForRead)) { if (pline.GetPoint2dAt(0).IsEqualTo(pline.GetPoint2dAt(pline.NumberOfVertices - 1))) e.Remove(i); } } }
Thanks for the example Gilles, I'll give it a shot
Is there any way that I can address this issue with an "if" statement here:
BlockTableRecord btr = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
foreach (SelectedObject obj in sset) {
Thanks Again
Vince