ShellAsync (o3d_shellOperation): удаление граней по индексам + толщина стенки, thinType=!outward. SelectFaceByIndex в ядре, инструмент shell в FeatureTools. Валидация: thickness>0, дедупликация индексов, проверка диапазона до мутации. Integration-тест: коробка 40x30x20 → оболочка 2мм → 7152 мм³ (±5%). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.7 KiB
Дизайн: пакет B (шаг 1) — операция «Оболочка» (shell)
Дата: 2026-05-26 Статус: на ревью (автономный режим; ревьюер — Codex) Контекст: kompas3d-mcp — MCP-сервер для КОМПАС-3D через COM API (.NET 8, C#).
Цель
Добавить формообразующую операцию «Оболочка» (придать стенкам толщину, удалив выбранные
грани) — первый шаг пакета B «формообразующие». Самая востребованная операция этого пакета;
опирается на уже готовый выбор грани по индексу из list_faces, без мульти-эскизной
оркестрации (нужной для loft/sweep). Один MCP-инструмент shell.
Не входит в объём (YAGNI)
- Остальные операции пакета B (rib, draft, loft, sweep, hole) — отдельные шаги.
- Переменная толщина по граням (
ksShellDefinitionзадаёт одну общуюthickness). - Закрытая оболочка без удаляемых граней — КОМПАС требует ≥1 удаляемую грань.
Сигнатуры COM (подтверждены: рефлексия interop + SDK-база + пример Step3d1.cs)
Obj3dType.o3d_shellOperation = 43
ksShellDefinition:
double thickness // толщина стенки, мм
bool thinType // true = внутрь (габарит сохраняется), false = наружу
object FaceArray() // ksEntityCollection удаляемых (открываемых) граней; нужна >=1
Паттерн (из Samples/CSharp.zip → Step3d1.cs):
ksEntity ent = part.NewEntity(o3d_shellOperation)
ksShellDefinition def = ent.GetDefinition()
ksEntityCollection faces = def.FaceArray()
faces.Add(<грань>) // одна или несколько удаляемых граней
def.thickness = t; def.thinType = !outward
ent.Create()
Порядок: сначала заполнить FaceArray, затем thickness/thinType, затем Create().
Новый MCP-инструмент (группа Feature)
| Инструмент | Параметры | Поведение |
|---|---|---|
shell |
faceIndices: int[], thickness: double, outward: bool = false |
Превратить тело в оболочку толщиной thickness мм, удалив (открыв) грани с указанными индексами из list_faces. outward=false — толщина внутрь (габарит сохраняется), true — наружу. |
Маппинг: thinType = !outward.
Выбор граней: по стабильному индексу из list_faces (как sketch_create_on_face_index,
fillet_edge_index). Индексы валидны, пока геометрия не менялась — берутся из свежего
list_faces. Несколько граней → несколько FaceArray.Add.
Реализация
- Метод модели
ShellAsync(IReadOnlyList<int> faceIndices, double thickness, bool outward, CancellationToken)вPartModeler.Features.cs(формообразующая). Возвращает id операции (как extrude/revolve). - Helper
SelectFaceByIndex(ksPart, int)в ядреPartModeler.cs— аналог существующегоSelectEdgeByIndex(диапазон-проверка +EntityCollection(o3d_face).GetByIndex). - Инструмент
shellвFeatureTools.cs(какextrude_boss/revolve_boss). - Валидация (inline, как
ExtrudeAsync/RevolveAsync):thickness > 0;faceIndicesне null и не пуст; каждый индекс проверяется на диапазон до мутации модели (SelectFaceByIndexбросаетArgumentOutOfRangeException, какSelectEdgeByIndex); дубли индексов отбрасываются (Distinct), чтобы не добавлять грань вFaceArrayдважды;FaceArray()проверяется на null (as ksEntityCollection ?? throw). ВозвратCreate()==FALSE→InvalidOperationExceptionс пояснением вероятных причин (толщина больше локального радиуса/толщины стенки; несовместимая топология). - Известное ограничение (документируем, не обрабатываем): на телах со скруглениями/фасками и
на вогнутых/криволинейных гранях оболочка может не построиться (
Create()==FALSE) даже при формально корректных входных данных — это ограничение ядра КОМПАС, причину API не сообщает.
Тестирование
Integration (Category=Integration, KompasFixture, в SketchPrimitivesTests или новом
FeatureOpsTests): коробка 40×30×20 (AddRectangle → Extrude) → list_faces → найти
верхнюю грань (нормаль +Z или по площади) → ShellAsync([верхняя], thickness=2, outward=false)
→ объём существенно уменьшается (тело стало полым с открытым верхом) и остаётся > 0.
Точная проверка: оболочка 2 мм с открытым верхом = 24000 − 36×26×18 = 24000 − 16848 = 7152 мм³.
Утверждение: after < before и after ∈ (7152·0.95, 7152·1.05) (≈6794…7510 мм³). Если КОМПАС
считает полость иначе — скорректировать ожидание по фактическому замеру, сохранив узкий допуск.
Unit отдельный не вводим: маппинг thinType=!outward тривиален и инлайнится; валидация
параметров — в стиле существующих операций (extrude/revolve тоже покрыты интеграционно).
Влияние на документацию
После реализации (через docs-delegate): счётчик инструментов +1 (→51), тестов +1;
добавить shell в описание формообразующих в CLAUDE.md/README.md/docs/ARCHITECTURE.md/
docs/presentation.html; отметить начало пакета B.