There is recently a question asked in AutoCAD Map discussion forum on how to do this with MPolygon. There are very few discussions/code samples on MPolygon that one can find online. So, I post the code out of my study here.
Here are things related to solving this issue:
1. An MPolygon has, just like a Hatch, one or more loops (class of MPolygonLoop);
2. MPolygonLoop can be accessed by MPolygon.GetMPolygonLoopAt(int) method;
3. An MPolygonLoop is a collection of BulgeVertex object (class of BulgeVertexCollection);
4. With BulgeVertex object, one can calculate whether 2 BulgeVertex is duplicated (too closed);
5. If duplicate is found, one of the BulgeVertex can be removed from the MPolygonLoop;
6. HOWEVER, simply remove a BulgeVertex from an MPolygonLoop of an MPolygon DOES NOT change the MPolygon, because MPolygon's loop is somehow "immutable". One need to remove the loop from the MPolygon, change the loop (adding/removing/changing one or more BulgeVertices as needed), then append the loop back to the MPolygon.
Here is the code of cleaning duplicate vertices in MPolygon, which is an extension class:
using Autodesk.AutoCAD.DatabaseServices; namespace MPolyUtil { public static class MPolygonExtension { public static int RemoveDuplicateVertices( this MPolygon mpoly, double tolerance=1.0) { if (!mpoly.IsWriteEnabled) mpoly.UpgradeOpen(); var count = 0; var hasDup = true; while(hasDup) { hasDup = PurgeDuplicatedVertex(mpoly, tolerance); if (hasDup) count++; } return count; } public static int GetVertexCount(this MPolygon mpoly) { var count = 0; for (int i=0; i<mpoly.NumMPolygonLoops; i++) { var loop = mpoly.GetMPolygonLoopAt(i); count += loop.Count; } return count; } private static bool PurgeDuplicatedVertex( MPolygon mpoly, double tolerance) { var purged = false; for (int i = 0; i < mpoly.NumMPolygonLoops; i++) { var loop = mpoly.GetMPolygonLoopAt(i); if (LoopChanged(loop, tolerance)) { mpoly.RemoveMPolygonLoopAt(i); mpoly.AppendMPolygonLoop(loop, true, 0.0); purged = true; break; } } return purged; } private static bool LoopChanged( MPolygonLoop loop, double tolerance) { var changed = false; for (int i = 0; i < loop.Count - 1; i++) { var vertex1 = loop[i]; var vertex2 = loop[i + 1]; var dist = vertex1.Vertex.GetDistanceTo(vertex2.Vertex); if (dist < tolerance) { loop.Remove(vertex2); changed = true; } } return changed; } } }
Here is the CommandClass that put above code into work:
using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Runtime; using CadApp = Autodesk.AutoCAD.ApplicationServices.Application; [assembly: CommandClass(typeof(MPolyUtil.MyCommands))] namespace MPolyUtil { public class MyCommands { [CommandMethod("CleanMPoly")] public static void RunMyCommand() { var dwg = CadApp.DocumentManager.MdiActiveDocument; var ed = dwg.Editor; try { var mpolyId = SelectMPolygon(ed); if (!mpolyId.IsNull) { var removedCount = 0; using (var tran = dwg.TransactionManager.StartTransaction()) { var mpoly = (MPolygon)tran.GetObject( mpolyId, OpenMode.ForWrite); removedCount = mpoly.RemoveDuplicateVertices(10.0); tran.Commit(); } ed.WriteMessage( $"\nDuplicate vertices found and removed: {removedCount}"); } } catch (System.Exception ex) { ed.WriteMessage($"\nInitializing error:\n{ex.Message}\n"); } } private static ObjectId SelectMPolygon(Editor ed) { var opt = new PromptEntityOptions( "\nSelect an MPolygon:"); opt.SetRejectMessage("\nInvalid: not an MPolygon!"); opt.AddAllowedClass(typeof(MPolygon), true); var res = ed.GetEntity(opt); if (res.Status == PromptStatus.OK) return res.ObjectId; else return ObjectId.Null; } } }
The video clip below shows the effect of running the code:
No comments:
Post a Comment