From 5e6d3ec8ae0ef80c0929b8e5a4d644016751953d Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 13:24:58 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20=D1=81=D0=BF=D0=B5=D0=BA=20assembly=5Fa?= =?UTF-8?q?dd=5Fmate=20=E2=80=94=20=D1=81=D0=BE=D0=BF=D1=80=D1=8F=D0=B6?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=BE=D0=B2=20(API7),=20=D1=81=D0=BF=D0=B0?= =?UTF-8?q?=D0=B9=D0=BA=20=D0=B7=D0=B5=D0=BB=D1=91=D0=BD=D1=8B=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Веха СБОРКИ, инкремент 2. Механизм подтверждён спайком: mates.Add(type) + BaseObject1/2 (грани через FindObjectsByPoint FirstLevel=false) + Update + RebuildModel. Coincidence (ширина 120→40), Distance(30) (→70). Свой enum MateType. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-05-27-assembly-add-mate-design.md | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-27-assembly-add-mate-design.md diff --git a/docs/superpowers/specs/2026-05-27-assembly-add-mate-design.md b/docs/superpowers/specs/2026-05-27-assembly-add-mate-design.md new file mode 100644 index 0000000..b6f4a70 --- /dev/null +++ b/docs/superpowers/specs/2026-05-27-assembly-add-mate-design.md @@ -0,0 +1,105 @@ +# Дизайн: сопряжение компонентов сборки (assembly_add_mate) через API7 + +**Дата:** 2026-05-27 +**Статус:** спайк зелёный (механизм подтверждён вживую); спроектировано; на ревью (Codex) + +## Цель + +Веха СБОРКИ, инкремент 2. После вставки компонентов (`assembly_add_component`, инкремент 1) — +**сопряжения**: наложить связь между гранями двух компонентов (совпадение / на расстоянии), +чтобы решатель сборки спозиционировал компоненты относительно друг друга. Это вторая +половина минимально полезного цикла сборки (вставить → связать). + +## Спайк: механизм подтверждён вживую (НЕ разучивать) + +Спайк (`AssemblyMateSpikeTests`, оба теста зелёные) подтвердил полный путь API7: + +``` +IPart7 top = (IPart7)doc3d.TopPart; // активная сборка +IMateConstraints3D mates = top.MateConstraints; // COM-свойство (не QI) +IMateConstraint3D mate = mates.Add(MateConstraintType); // напр. mc_Coincidence=0 / mc_Distance=5 +mate.BaseObject1 = (IModelObject)face1; // грань компонента 1 +mate.BaseObject2 = (IModelObject)face2; // грань компонента 2 +if (distance|angle) mate.ParamValue = value; // зазор (мм) / угол (°) +bool ok = mate.Update(); // наложить сопряжение +top.RebuildModel(true); // применить к геометрии +``` + +**Выбор граней компонентов:** `top.FindObjectsByPoint(x, y, z, FirstLevel=false)` — `FirstLevel=false` +заставляет спуститься В компоненты и вернуть их грань в **контексте сборки** (мировые координаты с +учётом placement компонента). Это именно тот `IModelObject`, который нужен решателю сопряжений. + +**Проверенные результаты (2 куба 20³, A в нуле x[0,20], B со сдвигом +100 x[100,120]):** +- **Совпадение** (`mc_Coincidence`) +X грани A (20,10,10) с −X гранью B (100,10,10): `Update=True`, + `Valid=True`, `Alignment=ksMCAlignmentClosest` (дефолт). Грани сошлись заподлицо → ширина сборки + по X **120 → 40** (кубы соприкасаются). Решатель подвинул A (к B), не B. +- **Расстояние** (`mc_Distance`, `ParamValue=30`) тех же граней: `Update=True`, `Valid=True`. Грани + встали в 30 мм → ширина сборки по X **120 → 70** (20+30+20). + +**Тонкости (эмпирика):** +- `Alignment` НЕ выставляем — дефолт работает (`ksMCAlignmentClosest` для совпадения, + `ksMCAlignmentUnknown` для расстояния). Параметр выравнивания — расширение позже (YAGNI). +- Решатель может двигать **любой** компонент (в т.ч. первый, «зафиксированный»). Поэтому результат + проверяем по **ширине габарита** (грани сблизились), а не по тому, какой компонент сдвинулся. +- `mates.Add` возвращает `IMateConstraint3D`; результат `Update()` проверяем (FALSE = не наложилось). + После — `RebuildModel(true)` (результат проверяем, как в инкременте 1). + +## Архитектура + +Метод в существующем `AssemblyService` (он уже про сборки). Свой enum `MateType` (паттерн +`BasePlane`/`CoordinateAxis`) маппится на КОМПАС `MateConstraintType` — COM-константы не текут в +Host/тесты. + +- `src/Kompas.Mcp.Core/Assemblies/MateType.cs` — enum `MateType` + static `Mates` + (`ToConstraintType`, `Parse(string)` англ./рус., `RequiresValue`). +- `AssemblyService.AddMateAsync(MateType, x1,y1,z1, x2,y2,z2, value, ct)` — реализация. +- Инструмент `assembly_add_mate` в `AssemblyTools` (тип сопряжения строкой → `Mates.Parse`). + +## MCP-инструмент + +| Инструмент | Параметры | Поведение | +|---|---|---| +| `assembly_add_mate` | `mateType: string`, `x1,y1,z1`, `x2,y2,z2`, `value=0` | Наложить сопряжение между гранями двух компонентов активной сборки, выбранными по мировым точкам (x1..z1) и (x2..z2). `mateType`: coincidence / distance / parallel / perpendicular / concentric / angle / tangency. Для distance — `value` зазор (мм), для angle — `value` угол (°). | + +Контракт: активный документ — сборка (`RequireActiveAssembly`, уже есть); обе точки должны попасть +на грани компонентов. **Гарантированно валидированы геометрией: coincidence, distance.** Остальные +типы маппятся и вызываемы через тот же путь Add+BaseObject+Update, но не покрыты регрессионным +тестом по габариту (требуют иной геометрии/проверки) — помечены в описании инструмента. + +## Валидация (чистые static, unit-тест) + +`Mates`: +- `Parse(string)` — англ./рус. → `MateType`; иначе `ArgumentException` со списком допустимых. +- `ToConstraintType(MateType)` — → `MateConstraintType`. +- `RequiresValue(MateType)` — true для Distance/Angle. + +В сервисе: `RequireFinitePosition` для обеих точек (уже есть в `AssemblyValidation`); если +`RequiresValue` — проверить `double.IsFinite(value)` (новый чистый валидатор +`AssemblyValidation.RequireFiniteValue`). + +## Реализация + +`AddMateCore`: валидация точек (и value, если нужен) → `RequireActiveAssembly` → +`FindFaceInAssembly` (FirstLevel=false) для обеих точек (понятная ошибка, если грань не найдена) → +`mates.Add(Mates.ToConstraintType(type))` → `BaseObject1/2` → `ParamValue` (если нужен) → +`Update()` (FALSE → откат сопряжения через `IFeature7.Delete` + ошибка) → `RebuildModel(true)` +(FALSE → ошибка). Транзитные RCW не освобождаем точечно (долг v2-2, как везде). + +## Тестирование + +### Unit (`MateTests` или в `AssemblyValidationTests`) +- `Mates.Parse` — англ. и рус. синонимы → верный `MateType`; бросает на мусоре. +- `Mates.ToConstraintType` — каждый `MateType` → ожидаемый `MateConstraintType`. +- `Mates.RequiresValue` — true для Distance/Angle, false для прочих. +- `AssemblyValidation.RequireFiniteValue` — бросает на NaN/Infinity. + +### Integration (`AssemblyMateTests`) +Паттерн: построить куб 20³ → сохранить → создать сборку → вставить 2 компонента (A в нуле, B +100) +→ сопряжение → проверить ширину габарита → `finally CloseAsync`. +1. **Совпадение** граней A(+X)/B(−X): ширина по X **120 → ~40** (соприкосновение). +2. **Расстояние 30**: ширина по X **120 → ~70** (зазор 30). +(Эти два сценария = промотированный спайк; спайк-файл удаляется.) + +## Дальнейшее (вне спека) +- Выравнивание (`Alignment`), типы concentric/angle/parallel с геометрической проверкой. +- Перемещение/фиксация/массив компонентов.