Как получить SubentityId всех поверхностей солида

Автор Тема: Как получить SubentityId всех поверхностей солида  (Прочитано 2500 раз)

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

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

  • ADN Club
  • ****
  • Сообщений: 478
  • Карма: 88
    • Мои плагины к Автокаду
Пытаюсь сделать смещение всех граней солида, но для OffsetFaces нужен список SubentityId. А где его взять? Вот такой код не работает:
Код - C# [Выбрать]
  1.       List<SubentityId> lst = new List<SubentityId>();
  2.       using (Brep br = new Brep(solid))
  3.         foreach (Face face in br.Faces)
  4.           lst.Add(face.SubentityPath.SubentId);
  5.       solid.OffsetFaces(lst.ToArray(), offset);
т.к. обращение к SubentityPath выталкивает BoundaryRepresentation.Exception :(
Сам solid - временный клон. Я попытался сохранять его в базе чертежа, чтоб у него ObjectId появился - это не помогло.

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

  • Administrator
  • *****
  • Сообщений: 9696
  • Карма: 1241
  • Рыцарь ObjectARX
  • Skype: rivilis
Попробуй такой трюк:
Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using Autodesk.AutoCAD.Runtime;
  4. using Autodesk.AutoCAD.ApplicationServices;
  5. using Autodesk.AutoCAD.DatabaseServices;
  6. using Autodesk.AutoCAD.Geometry;
  7. using Autodesk.AutoCAD.EditorInput;
  8. using AcBr = Autodesk.AutoCAD.BoundaryRepresentation;
  9.  
  10. [assembly: CommandClass(typeof(Rivilis.SolidOffset))]
  11.  
  12. namespace Rivilis
  13. {
  14.   public class SolidOffset
  15.   {
  16.     [CommandMethod("Sol3dOffset")]
  17.     public void MyCommand()
  18.     {
  19.       Document doc = Application.DocumentManager.MdiActiveDocument;
  20.       if (doc == null) return;
  21.      
  22.       Editor ed = doc.Editor;
  23.      
  24.       PromptEntityOptions prEnOpt =
  25.         new PromptEntityOptions("\nВыберите 3DSOLID: ");
  26.       prEnOpt.SetRejectMessage("Это не 3DSOLID!");
  27.       prEnOpt.AddAllowedClass(typeof(Solid3d), true);
  28.       PromptEntityResult rsEn = ed.GetEntity(prEnOpt);
  29.      
  30.       if (rsEn.Status != PromptStatus.OK) return;
  31.  
  32.       PromptDistanceOptions prDistOpt =
  33.         new PromptDistanceOptions("\nУкажите величину смещения: ");
  34.       prDistOpt.DefaultValue = 0;
  35.       prDistOpt.UseDefaultValue = true;
  36.       PromptDoubleResult rsOff = ed.GetDistance(prDistOpt);
  37.       if (rsEn.Status != PromptStatus.OK && rsEn.Status != PromptStatus.None) return;
  38.      
  39.       double offset = rsOff.Value;
  40.       ObjectId idSol3d = rsEn.ObjectId;
  41.  
  42.       using (Solid3d sol3d = idSol3d.Open(OpenMode.ForWrite) as Solid3d)
  43.       {
  44.         ObjectId[] ids = new ObjectId[] { sol3d.ObjectId };
  45.         SubentityId subentId = new SubentityId(SubentityType.Null, IntPtr.Zero);
  46.         FullSubentityPath path = new FullSubentityPath(ids, subentId);
  47.         List<SubentityId> subids = new List<SubentityId>();
  48.         // Brep создаём не из Entity, а из FullSubentityPath
  49.         using (AcBr.Brep brep = new AcBr.Brep(path)) {
  50.           foreach (AcBr.Face face in brep.Faces)  {
  51.             subids.Add(face.SubentityPath.SubentId);
  52.           }
  53.         }
  54.         sol3d.OffsetFaces(subids.ToArray(), offset);
  55.       }
  56.     }
  57.   }
  58. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение avc 23-06-2016, 11:52:35

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

  • Administrator
  • *****
  • Сообщений: 9696
  • Карма: 1241
  • Рыцарь ObjectARX
  • Skype: rivilis
Пытаюсь сделать смещение всех граней солида, но для OffsetFaces нужен список SubentityId.
Если всех граней, то почему не воспользоваться Solid3d.OffsetBody?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 478
  • Карма: 88
    • Мои плагины к Автокаду
Хотел сразу написать, что уже пытался создавать bRep по path. Там та же самая ошибка. А вот OffsetBody - это интересно, буду посмотреть.
P.S. А как это вы так лихо без блокировки документа и без транзакции редактируете объект? Это кошерно? Даже не вышебет Автокад фаталом?! Чудесааа... Я, темный человек, даже не подозревал, что у ObjectId есть вообще метод Open... 

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

  • Administrator
  • *****
  • Сообщений: 9696
  • Карма: 1241
  • Рыцарь ObjectARX
  • Skype: rivilis
Хотел сразу написать, что уже пытался создавать bRep по path. Там та же самая ошибка.
Наверное потому, что работал с клоном. Тут требуется объект в базе.
Я, темный человек, даже не подозревал, что у ObjectId есть вообще метод Open... 
А я об этом методе знал еще задолго до работы с транзакциями. В ObjectARX транзакциями пользуются только при массовых изменениях. Чаще же Open/Close. Вот еще пример использования: http://adn-cis.org/sozdanie-polyline3d-bez-ispolzovaniya-tranzakczii.html
Это кошерно? Даже не вышебет Автокад фаталом?!
Код проверил перед тем как публиковать в AutoCAD 2016 x64.

Код - C# [Выбрать]
  1. using System;
  2. using System.Collections.Generic;
  3. using Autodesk.AutoCAD.Runtime;
  4. using Autodesk.AutoCAD.ApplicationServices;
  5. using Autodesk.AutoCAD.DatabaseServices;
  6. using Autodesk.AutoCAD.Geometry;
  7. using Autodesk.AutoCAD.EditorInput;
  8. using AcBr = Autodesk.AutoCAD.BoundaryRepresentation;
  9.  
  10. [assembly: CommandClass(typeof(Rivilis.SolidOffset))]
  11.  
  12. namespace Rivilis
  13. {
  14.   public class SolidOffset
  15.   {
  16.     [CommandMethod("Sol3dOffset")]
  17.     public void MyCommand()
  18.     {
  19.       Document doc = Application.DocumentManager.MdiActiveDocument;
  20.       if (doc == null) return;
  21.      
  22.       Editor ed = doc.Editor;
  23.      
  24.       PromptEntityOptions prEnOpt =
  25.         new PromptEntityOptions("\nВыберите 3DSOLID: ");
  26.       prEnOpt.SetRejectMessage("Это не 3DSOLID!");
  27.       prEnOpt.AddAllowedClass(typeof(Solid3d), true);
  28.       PromptEntityResult rsEn = ed.GetEntity(prEnOpt);
  29.      
  30.       if (rsEn.Status != PromptStatus.OK) return;
  31.  
  32.       PromptDistanceOptions prDistOpt =
  33.         new PromptDistanceOptions("\nУкажите величину смещения: ");
  34.       prDistOpt.DefaultValue = 0;
  35.       prDistOpt.UseDefaultValue = true;
  36.       PromptDoubleResult rsOff = ed.GetDistance(prDistOpt);
  37.       if (rsEn.Status != PromptStatus.OK && rsEn.Status != PromptStatus.None) return;
  38.      
  39.       double offset = rsOff.Value;
  40.       ObjectId idSol3d = rsEn.ObjectId;
  41.  
  42.       using (Solid3d sol3d = idSol3d.Open(OpenMode.ForWrite) as Solid3d)
  43.       {
  44.         ObjectId[] ids = new ObjectId[] { sol3d.ObjectId };
  45.         SubentityId subentId = new SubentityId(SubentityType.Null, IntPtr.Zero);
  46.         FullSubentityPath path = new FullSubentityPath(ids, subentId);
  47.         List<SubentityId> subids = new List<SubentityId>();
  48.         using (AcBr.Brep brep = new AcBr.Brep(path)) {
  49.           foreach (AcBr.Face face in brep.Faces)  {
  50.             subids.Add(face.SubentityPath.SubentId);
  51.           }
  52.         }
  53.         sol3d.OffsetFaces(subids.ToArray(), offset);
  54.       }
  55.     }
  56.     [CommandMethod("Sol3dOffset1")]
  57.     public void MyCommand1()
  58.     {
  59.       Document doc = Application.DocumentManager.MdiActiveDocument;
  60.       if (doc == null) return;
  61.  
  62.       Editor ed = doc.Editor;
  63.  
  64.       PromptEntityOptions prEnOpt =
  65.         new PromptEntityOptions("\nВыберите 3DSOLID: ");
  66.       prEnOpt.SetRejectMessage("Это не 3DSOLID!");
  67.       prEnOpt.AddAllowedClass(typeof(Solid3d), true);
  68.       PromptEntityResult rsEn = ed.GetEntity(prEnOpt);
  69.  
  70.       if (rsEn.Status != PromptStatus.OK) return;
  71.  
  72.       PromptDistanceOptions prDistOpt =
  73.         new PromptDistanceOptions("\nУкажите величину смещения: ");
  74.       prDistOpt.DefaultValue = 0;
  75.       prDistOpt.UseDefaultValue = true;
  76.       PromptDoubleResult rsOff = ed.GetDistance(prDistOpt);
  77.       if (rsEn.Status != PromptStatus.OK && rsEn.Status != PromptStatus.None) return;
  78.  
  79.       double offset = rsOff.Value;
  80.       ObjectId idSol3d = rsEn.ObjectId;
  81.  
  82.       using (Solid3d sol3d = idSol3d.Open(OpenMode.ForWrite) as Solid3d)
  83.       {
  84.         sol3d.OffsetBody(offset);
  85.       }
  86.     }
  87.   }
  88. }

Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 478
  • Карма: 88
    • Мои плагины к Автокаду
Да, OffsetBody - это именно то что нужно! Спасибо. Странно, что у пользователя в интерфейсе нет аналогичной команды. Или я ее не нашел за 20 лет работы... Очень полезная фича. Надо срочно публиковать новый плагин :)

Код проверил перед тем как публиковать
Ни в коем случае не сомневаюсь в качестве вашего кода! Я собственно о другом. Глядя на такой упрощенный доступ в базу документа возникает куча вопросов и опасений. По вашей ссылке написано про производительность, но ничего про безопасность. Извиняюсь за офтопик, уж больно любопытно стало:
1. Метод Open не только сам транзакцию открывает, но и сам документ блокирует? Или в данном случае не будет сбоев из-за отсутствия блокировки? Много я по этим граблям походил - вот и сомнения...
2. А когда изменения попадают в базу данных документа? На диспозе объекта в конце блока using?
3. В каких случаях нужен метод Close ?
4. Студия ругается на Open, говорит - устаревший метод. Заменяю на новый GetObject. Получаю банан: System.NullReferenceException: Object reference not set to an instance of an object.

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

  • Administrator
  • *****
  • Сообщений: 9696
  • Карма: 1241
  • Рыцарь ObjectARX
  • Skype: rivilis
1. Метод Open не только сам транзакцию открывает, но и сам документ блокирует? Или в данном случае не будет сбоев из-за отсутствия блокировки? Много я по этим граблям походил - вот и сомнения...
Метод Open не открывает никакой транзакции - он работает вне транзакции. Блокировку я не делал, так как использовал команду, которая работает в контексте документа. AutoCAD сам при запуске такой команды выполняет блокировку документа, а после её завершения разблокирует документ. Так что в данном случае блокировка в моём коде не нужна. Если бы этот код (не команда) выполнялся из контекста приложения (немодальное окно, палитра и т.д.), то нужно было бы блокировать документ.
2. А когда изменения попадают в базу данных документа? На диспозе объекта в конце блока using?
Да. Для открытого при помощи Open объекта Dispose() эквивалентен Close().

3. В каких случаях нужен метод Close ?
Если открыт объект из базы при помощи Open, то Close нужен обязательно (using тоже подходит).

4. Студия ругается на Open, говорит - устаревший метод. Заменяю на новый GetObject. Получаю банан: System.NullReferenceException: Object reference not set to an instance of an object.
Не устаревший, а "For advanced use only". А это совершенно разные вещи...
И вообще воспользуйся поиском - на этом форуме неоднократно этот момент обсуждался.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN Club
  • ****
  • Сообщений: 478
  • Карма: 88
    • Мои плагины к Автокаду
Спасибо!