Как получить правильные координаты точек контура подрезки для внешней ссылки?

Автор Тема: Как получить правильные координаты точек контура подрезки для внешней ссылки?  (Прочитано 6891 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Тема содержит сообщение с Решением. Нажмите здесь чтобы посмотреть его.

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Добрый день. Получаю точки для контура подрезки внешней ссылки, все замечательно, но после перемещения ссылки или ее поворота координаты точек не меняются, только удаление контура и повторное его создание актуализирует их. Стоит заметить, что при изменении геометрии контура он отрисовывается корректно. Подскажите, как актуализировать информацию о точках или, возможно, где-то есть матрица изменения от оригинала?
Спасибо.

Пример:
Код - C# [Выбрать]
  1.         [CommandMethod("DXC", CommandFlags.Transparent | CommandFlags.Session | CommandFlags.UsePickSet)]
  2.         static public void DrawXClip()
  3.         {
  4.             Editor ed = Acad.Editor;
  5.             try
  6.             {
  7.                 if (ed.SelectImplied().Status != PromptStatus.OK) throw new System.Exception("Nothing has been pre-selected!");
  8.  
  9.                 RXClass BlockReferenceRXClass = RXClass.GetClass(typeof(BlockReference));
  10.                 using (Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument())
  11.                 using (Transaction tr = Acad.TransactionManager.StartTransaction())
  12.                 {
  13.                     foreach (ObjectId id in ed.SelectImplied().Value.GetObjectIds())
  14.                     {
  15.                         if (id.ObjectClass == BlockReferenceRXClass)
  16.                         {
  17.                             BlockReference blkRef = (BlockReference)tr.GetObject(id, OpenMode.ForRead);
  18.                             if (blkRef.ExtensionDictionary != ObjectId.Null)
  19.                             {
  20.                                 DBDictionary extdict = (DBDictionary)tr.GetObject(blkRef.ExtensionDictionary, OpenMode.ForRead);
  21.                                 if (extdict.Contains("ACAD_FILTER"))
  22.                                 {
  23.                                     DBDictionary dict = (DBDictionary)tr.GetObject(extdict.GetAt("ACAD_FILTER"), OpenMode.ForRead);
  24.                                     if (dict.Contains("SPATIAL"))
  25.                                     {
  26.                                         SpatialFilter filter = (SpatialFilter)tr.GetObject(dict.GetAt("SPATIAL"), OpenMode.ForRead);
  27.                                         DrawPolygon(blkRef.Database,
  28.                                             filter.Definition.Normal,
  29.                                             filter.ClipSpaceToWorldCoordinateSystemTransform,
  30.                                             filter.Definition.GetPoints());
  31.                                     }
  32.                                 }
  33.                             }
  34.                         }
  35.                     }
  36.  
  37.                     tr.Commit();
  38.                 }
  39.             }
  40.             catch (System.Exception ex)
  41.             {
  42.                 ed.WriteMessage(Environment.NewLine + ex.Message);
  43.             }
  44.         }
  45.  
  46.         public static ObjectId DrawPolygon(Database db, Vector3d normal, Matrix3d mat, Point2dCollection vertices)
  47.         {
  48.             ObjectId ret = ObjectId.Null;
  49.  
  50.             Transaction tr = db.TransactionManager.TopTransaction;
  51.             BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  52.             using (Polyline pl = new Polyline())
  53.             {
  54.                 pl.SetDatabaseDefaults();
  55.                 pl.ColorIndex = 3;
  56.                 pl.Closed = true;
  57.                 for (int i = 0; i < vertices.Count; i++)
  58.                 {
  59.                     pl.AddVertexAt(0, vertices[i], 0, 0, 0);
  60.                 }
  61.                 pl.TransformBy(mat);
  62.                 btr.AppendEntity(pl);
  63.                 tr.AddNewlyCreatedDBObject(pl, true);
  64.                 ret = pl.ObjectId;
  65.             }
  66.  
  67.             return ret;
  68.         }
  69.  
« Последнее редактирование: 25-12-2014, 16:51:37 от Александр Ривилис »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Clipping the boundary
« Ответ #1 : 25-12-2014, 12:03:12 »
Ничего не понял. Тебе нужно имитировать на .NET команду _XCLIP?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: Clipping the boundary
« Ответ #2 : 25-12-2014, 12:10:15 »
Ничего не понял. Тебе нужно имитировать на .NET команду _XCLIP?
Получить правильные координаты точек контура подрезки для внешней ссылки, т.к. они становятся неактуальными после перемещения или поворота ссылки.

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Clipping the boundary
« Ответ #3 : 25-12-2014, 12:12:10 »
Вот теперь понял. :)
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение T72 25-12-2014, 14:17:32

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Clipping the boundary
« Ответ #4 : 25-12-2014, 13:55:40 »
Попробуй вот такой код:
Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.DatabaseServices.Filters;
  6. using Autodesk.AutoCAD.Geometry;
  7. using Autodesk.AutoCAD.EditorInput;
  8. using AcRx = Autodesk.AutoCAD.Runtime;
  9. using AcAp = Autodesk.AutoCAD.ApplicationServices;
  10. using AcDb = Autodesk.AutoCAD.DatabaseServices;
  11. using AcGe = Autodesk.AutoCAD.Geometry;
  12. using AcEd = Autodesk.AutoCAD.EditorInput;
  13.  
  14. [assembly: CommandClass(typeof(Utils.ClipBoundary))]
  15.  
  16. namespace Utils
  17. {
  18.   public class ClipBoundary
  19.   {
  20.     [CommandMethod("GetXclipBoundary", CommandFlags.Modal)]
  21.     public void GetXclipBoundary()
  22.     {
  23.       AcAp.Document doc = AcAp.Application.DocumentManager.MdiActiveDocument;
  24.       AcDb.Database db = doc.Database;
  25.       AcEd.Editor ed = doc.Editor;
  26.       AcEd.PromptEntityOptions opt =
  27.         new AcEd.PromptEntityOptions("\nВыберите блок или внешнюю ссылку с подрезкой: ");
  28.       opt.SetRejectMessage("\nЭто не блок и не внешняя ссылка!");
  29.       opt.AddAllowedClass(typeof(AcDb.BlockReference),false);
  30.       AcEd.PromptEntityResult res = ed.GetEntity(opt);
  31.       if (res.Status != AcEd.PromptStatus.OK) return;
  32.       using (AcDb.BlockReference bref =
  33.         res.ObjectId.Open(AcDb.OpenMode.ForRead) as AcDb.BlockReference) {
  34.         AcDb.ObjectId idExt = bref.ExtensionDictionary;
  35.         if (idExt.IsNull) {
  36.           ed.WriteMessage("\nНет подрезки!");
  37.           return;
  38.         }
  39.         using (AcDb.DBDictionary extDict =
  40.           idExt.Open(AcDb.OpenMode.ForRead) as AcDb.DBDictionary) {
  41.           if (!extDict.Contains("ACAD_FILTER")) {
  42.               ed.WriteMessage("\nНет подрезки!");
  43.               return;
  44.           }
  45.           using (AcDb.DBDictionary dict =
  46.             extDict.GetAt("ACAD_FILTER").Open(AcDb.OpenMode.ForRead) as AcDb.DBDictionary) {
  47.             if (!dict.Contains("SPATIAL")) {
  48.               ed.WriteMessage("\nНет подрезки!");
  49.               return;
  50.             }
  51.             using (AcDb.Filters.SpatialFilter filter =
  52.               dict.GetAt("SPATIAL").Open(AcDb.OpenMode.ForRead) as AcDb.Filters.SpatialFilter) {
  53.               //////////////////////////////////////////////////////////////////////////
  54.               //            Получение итоговой матрицы преобразования
  55.               //////////////////////////////////////////////////////////////////////////
  56.                 AcGe.Matrix3d xformInBoundary = filter.ClipSpaceToWorldCoordinateSystemTransform;
  57.                 AcGe.Matrix3d xformRefOrig = filter.OriginalInverseBlockTransform;
  58.                 AcGe.Matrix3d refMatrix = bref.BlockTransform;
  59.                 refMatrix = refMatrix.PostMultiplyBy(xformRefOrig);
  60.                 AcGe.Matrix3d finalMatrix = refMatrix.PostMultiplyBy(xformInBoundary);
  61.               //////////////////////////////////////////////////////////////////////////
  62.                 AcDb.Filters.SpatialFilterDefinition def = filter.Definition;
  63.                 AcGe.Point2dCollection pts = def.GetPoints();
  64.                 if (pts.Count == 2) {
  65.                   // Если граница - прямоугольник
  66.                   AcGe.Point2d p1 = new AcGe.Point2d(pts[1].X, pts[0].Y);
  67.                   AcGe.Point2d p3 = new AcGe.Point2d(pts[0].X, pts[1].Y);
  68.                   pts.Insert(1, p1); pts.Add(p3);
  69.                 }
  70.                 AcGe.Point3dCollection pts3d = new AcGe.Point3dCollection();
  71.                 for (int i = 0; i < pts.Count; i++) {
  72.                   AcGe.Point3d p = new AcGe.Point3d(pts[i].X, pts[i].Y, 0);
  73.                   p = p.TransformBy(finalMatrix);
  74.                   pts3d.Add(p);
  75.                   pts[i] = new AcGe.Point2d(pts3d[i].X, pts3d[i].Y);
  76.                 }
  77.                 AcGe.Vector3d norm = def.Normal.TransformBy(finalMatrix);
  78.                 AcGe.Matrix3d plineECS = new AcGe.Matrix3d();
  79.                 using (AcDb.Polyline poly = new AcDb.Polyline()) {
  80.                   poly.Normal = norm; plineECS = poly.Ecs;
  81.                 }
  82.                 AcGe.Matrix3d plineECSInv = plineECS.Inverse();
  83.                 AcGe.Point3d ptEcs = pts3d[0];
  84.                 ptEcs.TransformBy(plineECSInv);
  85.                 double elev = ptEcs.Z;
  86.                 using (AcDb.Polyline poly = new AcDb.Polyline(pts.Count)) {
  87.                   AcDb.ObjectId ownId = bref.OwnerId;
  88.                   poly.SetPropertiesFrom(bref);
  89.                   poly.Normal = norm;
  90.                   for (int i = 0; i < pts.Count; i++) {
  91.                     poly.AddVertexAt(i, pts[i], 0, 0, 0);
  92.                   }
  93.                   poly.Elevation = elev;
  94.                   poly.ColorIndex = 1; // Установим красный цвет для границы
  95.                   poly.Closed = true;
  96.                   using (AcDb.BlockTableRecord btr =
  97.                     ownId.Open(AcDb.OpenMode.ForWrite) as AcDb.BlockTableRecord) {
  98.                     btr.AppendEntity(poly);
  99.                   }
  100.                 }
  101.             }
  102.           }
  103.         }
  104.       }
  105.     }
  106.   }
  107. }
Обрати внимание на получение итоговой матрицы преобразования.
« Последнее редактирование: 25-12-2014, 14:47:38 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: Clipping the boundary
« Ответ #5 : 25-12-2014, 14:17:12 »
Замечательно работает. Большое спасибо.

Оффлайн T72Автор темы

  • ADN Club
  • Сообщений: 23
  • Карма: 4
Re: Clipping the boundary
« Ответ #6 : 25-12-2014, 14:41:58 »
единственное исправление - дабы избежать ошибки:
Код - C# [Выбрать]
  1. if (pts.Count == 2)
  2. {
  3.     // Если граница - прямоугольник
  4.     AcGe.Point2d p1 = new AcGe.Point2d(pts[1].X, pts[0].Y);
  5.     AcGe.Point2d p3 = new AcGe.Point2d(pts[0].X, pts[1].Y);
  6.     pts.Insert(1, p1);
  7.     pts.Add(p3);
  8.     //pts.Insert(3, p3);
  9. }
  10.  

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Замечание принимается. Исправил у себя в коде.
« Последнее редактирование: 25-12-2014, 16:52:32 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение