ADN Club > AutoCAD .NET API

Как одним кликом пользователя получить грань (face) из solid3d?

(1/3) > >>

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


--- Код - C# [Выбрать] ---PromptNestedEntityOptions pneo = new PromptNestedEntityOptions("\nSelect Face: ");pneo.AllowNone = false; PromptNestedEntityResult pner = ed.GetNestedEntity(pneo);
Но вытащить через нее ничего получилось. Опций у него минимум (AllowNone), а на выходе только сам solid3d без каких-либо вложений. Предварительное переключение переменной SUBOBJSELECTIONMODE на 3 ничего не дает. Пришел к выводу, что метод предназначен только для примитивов, которые могут существовать в модели самостоятельно.

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


--- Код - C# [Выбрать] ---PromptEntityOptions opts = new PromptEntityOptions("\nВыберите грань 3D-тела: ");opts.AddAllowedClass(typeof(Solid3d), false);opts.AllowNone = false; // Обязательный выборPromptEntityResult res = ed.GetEntity(opts);
Если указать AddAllowedClass = Solid3d, на выходе только тело полностью. При попытке подсунуть сюда типы Autodesk.AutoCAD.BoundaryRepresentation.Face или Autodesk.AutoCAD.DatabaseServices.Face и при выборе в модели грани через Ctrl дают PromptStatus.Cancel.

Дальше всего получилось продвинуться через SelectionSet в виде:
         

--- Код - C# [Выбрать] ---Application.SetSystemVariable("SUBOBJSELECTIONMODE", (short)3);// 1. Запрос выбора грани у пользователяPromptSelectionOptions pso = new PromptSelectionOptions();pso.MessageForAdding = "\nSelect Face";pso.SingleOnly = true;pso.ForceSubSelections = true;pso.SinglePickInSpace = true; PromptSelectionResult psrFace = ed.GetSelection(pso); SelectionSet SSet = psrFace.Value;SelectedObject mainObj = SSet[0]; SelectedSubObject[] subs = mainObj.GetSubentities();
Этим способом худо-бедно добрался до подобъекта, но во-первых не понимаю, как сделать так, чтобы команда выполнилась сразу после клика на грани. При выборе грани ничего не происходит, команда продолжается только если что-то сделать еще (зум, еще один клик, Enter). Непонятно тогда, - о чем опции .SingleOnly и .SinglePickInSpace?
И самое бредовое и непроходимое - если тело содержит историю (а запись истории включена по умолчанию), нужную грань уже не выбрать. Под курсором подхватываются солиды или грани из истории, но только не грани текущего brep :o
Чтобы повторно взять грань у предыдущего тела, после выполнения команды попробовал уже все, что можно и в разных конфигурациях (внутри и после транзакции):


--- Код - C# [Выбрать] ---solidAfter.RecordGraphicsModified(true);solidAfter.Highlight();solidAfter.Unhighlight();solidAfter.Draw();ed.UpdateScreen();ed.Regen();
Ничего не помогает! Только ручное отключение записи истории солида (с наскока даже не нашел, как это сделать через API).
Но предварительно отключать историю у всех объектов или под курсором - как-то фу! Да и должно быть какое-то штатное решение, просто не могу его найти.
На сайте примеров с ручным выделением и получением идентификатора конкретной грани не нашел.
Может кто поделится примером (достаточно только концепции - какой метод и с какими настройками), - как получить идентификатор грани одним кликом.

avc:
Отключите историю солида. Это зло от которого надо сразу избавляться.
переключите SUBOBJSELECTIONMODE на Face. иначе всегда будет выбираться ребро, даже если его вообще не видно за гранью.
Далее просто:


--- Код - C# [Выбрать] ---PromptSelectionOptions pso = new() {   SingleOnly = true,   ForceSubSelections = true,   MessageForAdding = "....",   SinglePickInSpace = true,   RejectObjectsOnLockedLayers = true };PromptSelectionResult psr = ed.GetSelection(pso);f (psr.Status != PromptStatus.OK) return;SelectedObject so = psr.Value[0];ObjectId solidId = so.ObjectId;SelectedSubObject[] ssubs = so.GetSubentities();SubentityType subentityType = ssubs[0].FullSubentityPath.SubentId.Type;if (subentityType != SubentityType.Face) return;SubentityId id = ssubs[0].FullSubentityPath.SubentId;

avc:
И кстати в AutoCAD 2025 и новее все "быстрые" визуальные стили путают направление взгляда пользователи и все команды выбора поверхности выбирают самую дальнюю невидимую поверхность на самом дальнем солиде. Надо отключать 3д-ускорение или работать в 2д-каркасе.

Gr.Om:
Т.е., я уже получил максимум из возможного?))

--- Цитата: avc от 15-07-2026, 16:58:21 ---Отключите историю солида
--- Конец цитаты ---
Тут вопрос-то не совсем в том что я могу сделать у себя. Получается, что с NET 8.0 программно можно только переключить переменную SOLIDHIST, чтобы история не писалась у НОВЫХ тел. А что делать с существующими телами, которые удаленному пользователю нужно редактировать плагином? На официальном сайте вижу свойство .RecordHistory под 2018 версией, а в 2025 автокаде его уже нет.
Я думал .NET API - это почти промышленный уровень разработки, почти как C++ и ObjectARX, думал просто многого чего не раскопал в справке:)
Когда твердо решил сменить VBA и VBE на C# и VisualStudio, была надежда на сильный LevelUp (именно в части API), что наконец можно выбросить старый потертый бубен, с которым приходилось танцевать в VBA, чтобы реализовывать нереализуемые вещи.
Теперь понемногу понимаю, что просто поменял его на целую тележку новых блестящих бубнов. ???

avc:
Да, открываете солид на запись и RecordHistory = false. Вся история сбрасывается. Конечно, это свойство солида есть во всех версиях API.
Да, C# это промышленный (без почти) уровень. API полностью повторяет ObjectARX за очень малыми исключениями (динамические свойства создавать нельзя, например). Производительность ниже чем у ObjectARX. Возможность несоизмеримы с примитивным API VBA или скриптами LISP.
Да, проблем и глюков воз и маленькая тележка.

Навигация

[0] Главная страница сообщений

[#] Следующая страница

Перейти к полной версии