Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: Gr.Om от 15-07-2026, 16:28:19

Название: Как одним кликом пользователя получить грань (face) из solid3d?
Отправлено: Gr.Om от 15-07-2026, 16:28:19
Вроде бы тривиальная задача, но убил три дня на нее и толком не решил.
Если через интерфейс легко делаем _solidedit _face, и далее можно мышкой выделять отдельные грани и делать что нужно, то почему через API это оказалось вдруг таким гемором?!
Пытался через .GetNestedEntity (в документации не уточняется, - можно ли его использовать с подобъектами из brep), в сети полно примеров с не brep-подобъектами:

Код - C# [Выбрать]
  1. PromptNestedEntityOptions pneo = new PromptNestedEntityOptions("\nSelect Face: ");
  2. pneo.AllowNone = false;
  3.  
  4. PromptNestedEntityResult pner = ed.GetNestedEntity(pneo);

Но вытащить через нее ничего получилось. Опций у него минимум (AllowNone), а на выходе только сам solid3d без каких-либо вложений. Предварительное переключение переменной SUBOBJSELECTIONMODE на 3 ничего не дает. Пришел к выводу, что метод предназначен только для примитивов, которые могут существовать в модели самостоятельно.

Через .GetEntity тоже не получается:

Код - C# [Выбрать]
  1. PromptEntityOptions opts = new PromptEntityOptions("\nВыберите грань 3D-тела: ");
  2. opts.AddAllowedClass(typeof(Solid3d), false);
  3. opts.AllowNone = false; // Обязательный выбор
  4. PromptEntityResult res = ed.GetEntity(opts);

Если указать AddAllowedClass = Solid3d, на выходе только тело полностью. При попытке подсунуть сюда типы Autodesk.AutoCAD.BoundaryRepresentation.Face или Autodesk.AutoCAD.DatabaseServices.Face и при выборе в модели грани через Ctrl дают PromptStatus.Cancel.

Дальше всего получилось продвинуться через SelectionSet в виде:
         
Код - C# [Выбрать]
  1. Application.SetSystemVariable("SUBOBJSELECTIONMODE", (short)3);
  2. // 1. Запрос выбора грани у пользователя
  3. PromptSelectionOptions pso = new PromptSelectionOptions();
  4. pso.MessageForAdding = "\nSelect Face";
  5. pso.SingleOnly = true;
  6. pso.ForceSubSelections = true;
  7. pso.SinglePickInSpace = true;
  8.  
  9. PromptSelectionResult psrFace = ed.GetSelection(pso);
  10.  
  11. SelectionSet SSet = psrFace.Value;
  12. SelectedObject mainObj = SSet[0];
  13.  
  14. SelectedSubObject[] subs = mainObj.GetSubentities();

Этим способом худо-бедно добрался до подобъекта, но во-первых не понимаю, как сделать так, чтобы команда выполнилась сразу после клика на грани. При выборе грани ничего не происходит, команда продолжается только если что-то сделать еще (зум, еще один клик, Enter). Непонятно тогда, - о чем опции .SingleOnly и .SinglePickInSpace?
И самое бредовое и непроходимое - если тело содержит историю (а запись истории включена по умолчанию), нужную грань уже не выбрать. Под курсором подхватываются солиды или грани из истории, но только не грани текущего brep :o
Чтобы повторно взять грань у предыдущего тела, после выполнения команды попробовал уже все, что можно и в разных конфигурациях (внутри и после транзакции):

Код - C# [Выбрать]
  1. solidAfter.RecordGraphicsModified(true);
  2. solidAfter.Highlight();
  3. solidAfter.Unhighlight();
  4. solidAfter.Draw();
  5. ed.UpdateScreen();
  6. ed.Regen();

Ничего не помогает! Только ручное отключение записи истории солида (с наскока даже не нашел, как это сделать через API).
Но предварительно отключать историю у всех объектов или под курсором - как-то фу! Да и должно быть какое-то штатное решение, просто не могу его найти.
На сайте примеров с ручным выделением и получением идентификатора конкретной грани не нашел.
Может кто поделится примером (достаточно только концепции - какой метод и с какими настройками), - как получить идентификатор грани одним кликом.
Название: Re: Как одним кликом пользователя получить грань (face) из solid3d?
Отправлено: avc от 15-07-2026, 16:58:21
Отключите историю солида. Это зло от которого надо сразу избавляться.
переключите SUBOBJSELECTIONMODE на Face. иначе всегда будет выбираться ребро, даже если его вообще не видно за гранью.
Далее просто:

Код - C# [Выбрать]
  1. PromptSelectionOptions pso = new()
  2.  {
  3.    SingleOnly = true,
  4.    ForceSubSelections = true,
  5.    MessageForAdding = "....",
  6.    SinglePickInSpace = true,
  7.    RejectObjectsOnLockedLayers = true
  8.  };
  9. PromptSelectionResult psr = ed.GetSelection(pso);
  10. f (psr.Status != PromptStatus.OK) return;
  11. SelectedObject so = psr.Value[0];
  12. ObjectId solidId = so.ObjectId;
  13. SelectedSubObject[] ssubs = so.GetSubentities();
  14. SubentityType subentityType = ssubs[0].FullSubentityPath.SubentId.Type;
  15. if (subentityType != SubentityType.Face) return;
  16. SubentityId id = ssubs[0].FullSubentityPath.SubentId;


Название: Re: Как одним кликом пользователя получить грань (face) из solid3d?
Отправлено: avc от 15-07-2026, 17:00:58
И кстати в AutoCAD 2025 и новее все "быстрые" визуальные стили путают направление взгляда пользователи и все команды выбора поверхности выбирают самую дальнюю невидимую поверхность на самом дальнем солиде. Надо отключать 3д-ускорение или работать в 2д-каркасе.
Название: Re: Как одним кликом пользователя получить грань (face) из solid3d?
Отправлено: Gr.Om от 15-07-2026, 18:13:58
Т.е., я уже получил максимум из возможного?))
Отключите историю солида
Тут вопрос-то не совсем в том что я могу сделать у себя. Получается, что с NET 8.0 программно можно только переключить переменную SOLIDHIST, чтобы история не писалась у НОВЫХ тел. А что делать с существующими телами, которые удаленному пользователю нужно редактировать плагином? На официальном сайте вижу свойство .RecordHistory под 2018 версией, а в 2025 автокаде его уже нет.
Я думал .NET API - это почти промышленный уровень разработки, почти как C++ и ObjectARX, думал просто многого чего не раскопал в справке:)
Когда твердо решил сменить VBA и VBE на C# и VisualStudio, была надежда на сильный LevelUp (именно в части API), что наконец можно выбросить старый потертый бубен, с которым приходилось танцевать в VBA, чтобы реализовывать нереализуемые вещи.
Теперь понемногу понимаю, что просто поменял его на целую тележку новых блестящих бубнов. ???
Название: Re: Как одним кликом пользователя получить грань (face) из solid3d?
Отправлено: avc от 15-07-2026, 18:37:45
Да, открываете солид на запись и RecordHistory = false. Вся история сбрасывается. Конечно, это свойство солида есть во всех версиях API.
Да, C# это промышленный (без почти) уровень. API полностью повторяет ObjectARX за очень малыми исключениями (динамические свойства создавать нельзя, например). Производительность ниже чем у ObjectARX. Возможность несоизмеримы с примитивным API VBA или скриптами LISP.
Да, проблем и глюков воз и маленькая тележка.
Название: Re: Как одним кликом пользователя получить грань (face) из solid3d?
Отправлено: Gr.Om от 15-07-2026, 18:55:34
Да, открываете солид на запись и RecordHistory = false. Вся история сбрасывается. Конечно, это свойство солида есть во всех версиях API.
Да, действительно. Что-то от усиленного перечитывания дерева вдоль и поперек уже начинаются глюки. Пора отдохнуть.