Тема: Выделение и подсветка примитивов в AutoCAD средствами .NET/COM
Пример для обсуждения:
////////////////////////////////////////////////////////////////////////// // Выделение и подсветка различными методами примитивов // в AutoCAD средствами .NET/COM ////////////////////////////////////////////////////////////////////////// using System ; using System.Collections ; using System.Threading; using Autodesk.AutoCAD.Runtime ; using Autodesk.AutoCAD.Geometry ; using Autodesk.AutoCAD.ApplicationServices ; using Autodesk.AutoCAD.EditorInput ; using Autodesk.AutoCAD.DatabaseServices ; using Autodesk.AutoCAD.Interop ; using Autodesk.AutoCAD.Interop.Common; [assembly: CommandClass(typeof(ZoomLibrary.Zoom))] namespace ZoomLibrary { public class Zoom { /// <summary> /// Функция для зумирования примитива на экране AutoCAD /// id - ObjectId для примитива /// zoomFactor - процент высоты/ширины экранной области, /// которую будет занимать примитив после зумирования (от 0 до 100) /// </summary> static public void ZoomObject(ObjectId id, double zoomFactor) { Database db = HostApplicationServices.WorkingDatabase; AcadApplication app = (AcadApplication) Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication; Point3d center; double zoomHeight = 0.0; using (Transaction tr = db.TransactionManager.StartTransaction()) { object oMinpt = new object(), oMaxpt = new object(); double [] dMinpt = new double[3], dMaxpt = new double[3]; Entity en = (Entity) tr.GetObject(id,OpenMode.ForRead); AcadEntity en_com = en.AcadObject as AcadEntity; object minPt = new object(), maxPt = new object(); en_com.GetBoundingBox(out oMinpt, out oMaxpt); dMinpt = (double []) oMinpt; dMaxpt = (double []) oMaxpt; double heightEnt = dMaxpt[1] - dMinpt[1]; double widthEnt = dMaxpt[0] - dMinpt[0]; object objRes = app.ActiveDocument.GetVariable("SCREENSIZE"); Point2d screenRes = new Point2d((double []) objRes); double aspectScreen = screenRes.Y / screenRes.X; if (widthEnt*aspectScreen > heightEnt) { zoomHeight = widthEnt*aspectScreen*100/Math.Max(zoomFactor,1e-6); } else { zoomHeight = heightEnt*100/Math.Max(zoomFactor,1e-6); } center = new Point3d( (dMinpt[0]+dMaxpt[0]) * 0.5, (dMinpt[1]+dMaxpt[1]) * 0.5, (dMinpt[2]+dMaxpt[2]) * 0.5 ); } app.ZoomCenter(center.ToArray(),zoomHeight); } /// <summary> /// Функция для получения коллекции примитивов - клонов переданного /// примитива. Если примитив не блок - в коллекции только один примитив, /// если блок, то идет рекурсивное расчленение и в коллекции все примитивы /// входящие в блок и во все вложенные. Для атрибутов производится отдельная /// обработка. /// </summary> static public DBObjectCollection DeepCloneExplode(Entity en) { DBObjectCollection fullCol = new DBObjectCollection(); BlockReference blkRef = en as BlockReference; if (blkRef != null) { DBObjectCollection partCol = new DBObjectCollection(); AttributeCollection attCol = blkRef.AttributeCollection; Document doc = Application.DocumentManager.MdiActiveDocument; using (DocumentLock doclock = doc.LockDocument()) { using (Transaction tr = doc.TransactionManager.StartTransaction()) { foreach (ObjectId id in (IEnumerable) attCol) { AttributeReference attRef = (AttributeReference) tr.GetObject(id,OpenMode.ForRead); if (!attRef.Invisible) { DBText txt = new DBText(); try { txt.SetDatabaseDefaults(doc.Database); txt.AdjustAlignment(doc.Database); txt.VerticalMode = attRef.VerticalMode; txt.HorizontalMode = attRef.HorizontalMode; txt.Position = attRef.Position; txt.Normal = attRef.Normal; txt.Rotation = attRef.Rotation; txt.Height = attRef.Height; txt.WidthFactor = attRef.WidthFactor; txt.Thickness = attRef.Thickness; txt.TextStyle = attRef.TextStyle; txt.TextString = attRef.TextString; txt.Oblique = attRef.Oblique; txt.Color = attRef.Color; txt.LayerId = attRef.LayerId; txt.AlignmentPoint = attRef.AlignmentPoint; } catch { } fullCol.Add(txt); } } } } en.Explode(partCol); foreach (DBObject en_col in partCol) { AttributeDefinition attdef = en_col as AttributeDefinition; if (attdef == null) { using (DBObjectCollection locCol = DeepCloneExplode((Entity) en_col)) { foreach (DBObject en_col1 in locCol) fullCol.Add(en_col1); } } } partCol.Dispose(); } else { fullCol.Add((en.ObjectId != ObjectId.Null)?(DBObject)en.Clone():(DBObject)en); } return fullCol; } /// <summary> /// Функция производит "мигание" объектом при помощи изменения веса линии (LineWeight) /// Есть ряд исключений, когда это не работает. Например, для текста на основе TrueType /// шрифта (во всяком случае в AutoCAD 2006 SP1). /// </summary> /// <param name="id">ObjectId для примитива</param> /// <param name="num">Количество "миганий"</param> /// <param name="delay1">Длительность "подсвеченного" состояния</param> /// <param name="delay2">Длительность "неподсвеченного" состояния</param> static public void FlickObjectLineWeight(ObjectId id, int num, int delay1, int delay2) { Document doc = Application.DocumentManager.MdiActiveDocument; object lwdisplay = Application.GetSystemVariable("LWDISPLAY"); if ((short)lwdisplay == 0) Application.SetSystemVariable("LWDISPLAY",(short)1); LineWeight prevLineWeight = LineWeight.ByLineWeightDefault; DBObjectCollection expEnts = null; ArrayList ids = new ArrayList(); // Cloneing entities for highlighting using (DocumentLock doclock = doc.LockDocument()) { using (Transaction tr = doc.TransactionManager.StartTransaction()) { Entity en = (Entity) tr.GetObject(id,OpenMode.ForRead); expEnts = DeepCloneExplode(en); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(en.OwnerId, OpenMode.ForWrite); foreach (Entity ent in expEnts) { ObjectId expid = btr.AppendEntity(ent); ids.Add(expid); tr.AddNewlyCreatedDBObject(ent,true); } expEnts.Dispose(); tr.Commit(); } } for (int i = 0; i < num; i++) { // Highlight entity using (DocumentLock doclock = doc.LockDocument()) { using (Transaction tr = doc.TransactionManager.StartTransaction()) { foreach (ObjectId eId in ids) { Entity en = (Entity) tr.GetObject(eId,OpenMode.ForWrite); en.LineWeight = LineWeight.LineWeight211; // Maximum lineweight } tr.Commit(); } } doc.Editor.UpdateScreen(); // Wait for delay1 msecs Thread.Sleep(delay1); // Unhighlight entity using (DocumentLock doclock = doc.LockDocument()) { using (Transaction tr = doc.TransactionManager.StartTransaction()) { foreach (ObjectId eId in ids) { Entity en = (Entity) tr.GetObject(eId,OpenMode.ForWrite); en.LineWeight = prevLineWeight; } tr.Commit(); } } doc.Editor.UpdateScreen(); // Wait for delay2 msecs Thread.Sleep(delay2); } // Erase cloned entities using (DocumentLock doclock = doc.LockDocument()) { using (Transaction tr = doc.TransactionManager.StartTransaction()) { foreach (ObjectId eId in ids) { Entity en = (Entity) tr.GetObject(eId,OpenMode.ForWrite); en.Erase(); } tr.Commit(); } } Application.SetSystemVariable("LWDISPLAY",lwdisplay); } /// <summary> /// Функция производит "мигание" объектом при помощи Highlight/Unhighlight /// </summary> /// <param name="id">ObjectId для примитива</param> /// <param name="num">Количество "миганий"</param> /// <param name="delay1">Длительность "подсвеченного" состояния</param> /// <param name="delay2">Длительность "неподсвеченного" состояния</param> static public void FlickObjectHighlight(ObjectId id, int num, int delay1, int delay2) { Document doc = Application.DocumentManager.MdiActiveDocument; for (int i = 0; i < num; i++) { // Highlight entity using (DocumentLock doclock = doc.LockDocument()) { using (Transaction tr = doc.TransactionManager.StartTransaction()) { Entity en = (Entity) tr.GetObject(id,OpenMode.ForWrite); ObjectId[] ids = new ObjectId[1] ; ids[0] = id; SubentityId index = new SubentityId(SubentityType.Null, 0); FullSubentityPath path = new FullSubentityPath(ids, index); en.Highlight(path,true); tr.Commit(); } } doc.Editor.UpdateScreen(); // Wait for delay1 msecs Thread.Sleep(delay1); // Unhighlight entity using (DocumentLock doclock = doc.LockDocument()) { using (Transaction tr = doc.TransactionManager.StartTransaction()) { Entity en = (Entity) tr.GetObject(id,OpenMode.ForWrite); ObjectId[] ids = new ObjectId[1] ; ids[0] = id; SubentityId index = new SubentityId(SubentityType.Null, 0); FullSubentityPath path = new FullSubentityPath(ids, index); en.Unhighlight(path,true); tr.Commit(); } } doc.Editor.UpdateScreen(); // Wait for delay2 msecs Thread.Sleep(delay2); } } /// <summary> /// Функция производит "мигание" объектом при помощи включения/выключения видимости /// выбранного примитива /// </summary> /// <param name="id">ObjectId для примитива</param> /// <param name="num">Количество "миганий"</param> /// <param name="delay1">Длительность "подсвеченного" состояния</param> /// <param name="delay2">Длительность "неподсвеченного" состояния</param> static public void FlickObjectVisible(ObjectId id, int num, int delay1, int delay2) { Document doc = Application.DocumentManager.MdiActiveDocument; bool prevVisibility = true; for (int i = 0; i < num; i++) { // Highlight entity using (DocumentLock doclock = doc.LockDocument()) { using (Transaction tr = doc.TransactionManager.StartTransaction()) { Entity en = (Entity) tr.GetObject(id,OpenMode.ForWrite); prevVisibility = en.Visible; en.Visible = !en.Visible; tr.Commit(); } } doc.Editor.UpdateScreen(); // Wait for delay1 msecs Thread.Sleep(delay1); // Unhighlight entity using (DocumentLock doclock = doc.LockDocument()) { using (Transaction tr = doc.TransactionManager.StartTransaction()) { Entity en = (Entity) tr.GetObject(id,OpenMode.ForWrite); en.Visible = prevVisibility; tr.Commit(); } } doc.Editor.UpdateScreen(); // Wait for delay2 msecs Thread.Sleep(delay2); } } /// <summary> /// Только для проверки /// </summary> // Define Command "TestZoom" [CommandMethod("TestZoom")] static public void TestZoom() { Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; PromptEntityResult rse = ed.GetEntity("\nSelect Entity: "); if (rse.Status == PromptStatus.OK) { double zoomFactor = 100.0; PromptDoubleOptions pdo = new PromptDoubleOptions("\nEnter zoom factor in percent (0...100) <100>: "); pdo.UseDefaultValue = true; pdo.DefaultValue = zoomFactor; pdo.AllowNegative = false; pdo.AllowZero = false; pdo.AllowNone = false; PromptDoubleResult rsd = ed.GetDouble(pdo); switch (rsd.Status) { case PromptStatus.Cancel: case PromptStatus.Error: return; case PromptStatus.OK: zoomFactor = rsd.Value; break; default: break; } ZoomObject(rse.ObjectId,zoomFactor); FlickObjectLineWeight(rse.ObjectId,3,350,200); FlickObjectHighlight(rse.ObjectId,3,350,200); FlickObjectVisible(rse.ObjectId,3,350,200); } } } }