docs: спек assembly_add_mate — сопряжения компонентов (API7), спайк зелёный

Веха СБОРКИ, инкремент 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) <noreply@anthropic.com>
This commit is contained in:
2026-05-27 13:24:58 +03:00
parent 20518efe52
commit 5e6d3ec8ae
@@ -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 с геометрической проверкой.
- Перемещение/фиксация/массив компонентов.