From ca3d91ae68bd6b0d87d38f593df193124f24e718 Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 17:49:18 +0300 Subject: [PATCH] =?UTF-8?q?docs:=20=D1=81=D0=BF=D0=B5=D0=BA=20drawing=5Fad?= =?UTF-8?q?d=5Flinear=5Fdimension=20=E2=80=94=20=D0=BB=D0=B8=D0=BD=D0=B5?= =?UTF-8?q?=D0=B9=D0=BD=D1=8B=D0=B9=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D0=B2=D0=B8=D0=B4=D0=B5=20(API7)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Веха 2D-ЧЕРТЁЖ, инкремент 3. Спайк подтвердил: (ISymbols2DContainer)view QI → LineDimensions.Add → X1..Y3 (локальная СК вида) + Orientation + Update; авто-значение ((IDimensionText)dim).NominalValue == расстояние (проверено 40). Плюс: DrawingViewsResult += ViewNumbers (адресация видов, закрывает замечание Codex из ревью видов). Co-Authored-By: Claude Opus 4.7 (1M context) --- ...6-05-27-drawing-linear-dimension-design.md | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-27-drawing-linear-dimension-design.md diff --git a/docs/superpowers/specs/2026-05-27-drawing-linear-dimension-design.md b/docs/superpowers/specs/2026-05-27-drawing-linear-dimension-design.md new file mode 100644 index 0000000..984462d --- /dev/null +++ b/docs/superpowers/specs/2026-05-27-drawing-linear-dimension-design.md @@ -0,0 +1,104 @@ +# Дизайн: линейный размер на виде чертежа (drawing_add_linear_dimension) через API7 + +**Дата:** 2026-05-27 +**Статус:** спайк зелёный (механизм + авто-значение подтверждены); спроектировано; на ревью (Codex) + +## Цель + +Веха 2D-ЧЕРТЁЖ, инкремент 3 (размеры). После видов и основной надписи — **линейный размер** на +ассоциативном виде: между двумя точками (в локальной СК вида) с авто-измерением длины. Размеры — +самый ценный элемент оформления (несут размерную информацию). Начинаем с линейного +(горизонтальный/вертикальный/параллельный); диаметральные/радиальные/угловые — далее. + +## Спайк: механизм подтверждён вживую (НЕ разучивать) + +Спайк (`DrawingDimensionSpikeTests`, зелёный) подтвердил путь API7: + +``` +IView view = первый вид с Number != 0; // системный вид — #0, пропускаем +ISymbols2DContainer symbols = (ISymbols2DContainer)view; // COM-QI ОТ ВИДА (не от документа!) +ILineDimension dim = symbols.LineDimensions.Add(); +dim.X1=x1; dim.Y1=y1; dim.X2=x2; dim.Y2=y2; // выносные точки (ЛОКАЛЬНАЯ СК вида, мм) +dim.X3=x3; dim.Y3=y3; // положение размерной линии +dim.Orientation = ksLinDHorizontal; // 0=Parallel / 1=Horizontal / 2=Vertical +bool ok = dim.Update(); +double value = ((IDimensionText)dim).NominalValue; // авто-измеренное значение (мм) +``` + +**Проверено (вид спереди коробки 40×30×20):** размер (0,0)-(40,0) горизонтальный → +`Update()=True`, `Valid=True`, `NominalValue == 40` (авто `|X2-X1|`), `view.ObjectCount` вырос. + +**Подтверждённые факты:** +- **`ISymbols2DContainer` берётся COM-QI ОТ КОНКРЕТНОГО `IView`** — размер попадает именно в этот + вид (не нужен `Current=true`). (Аналогично 3D: `part`→`IModelContainer`.) +- **Координаты X1..Y3 — ЛОКАЛЬНАЯ СК вида** (= координаты модели на плоскости вида, при масштабе + 1:1 совпадают с мм модели). НЕ координаты листа. +- **`AutoNominalValue=true` по умолчанию** → `NominalValue` = расстояние между точками + (горизонтальный: `|X2-X1|`, вертикальный: `|Y2-Y1|`, параллельный: реальная длина). Значение + читается `((IDimensionText)dim).NominalValue` (QI). +- `Orientation` (`ksLineDimensionOrientationEnum`): `ksLinDParallel=0`, `ksLinDHorizontal=1`, + `ksLinDVertical=2` (в `Kompas6Constants`). +- `Update()` обязателен; перестроение документа не нужно. + +## Адресация вида (часть инкремента) + +Чтобы указать, НА КАКОМ виде ставить размер, нужен его `Number`. Сейчас +`drawing_create_standard_views` возвращает только `{Created, Total}`. **Расширяем `DrawingViewsResult` +полем `ViewNumbers` (номера созданных видов)** — уже собираются как `newViews` в +`CreateStandardViewsCore` (тривиально: `newViews.Select(v => v.Number)`). Это закрывает замечание +Codex из ревью видов (#10: «нет ссылок на созданные виды») и делает размеры адресуемыми. + +## MCP-инструмент + +| Инструмент | Параметры | Поведение | +|---|---|---| +| `drawing_add_linear_dimension` | `x1,y1,x2,y2` (выносные точки), `x3,y3` (положение размерной линии), `orientation="horizontal"`, `viewNumber=0` | Поставить линейный размер на виде активного чертежа между точками (x1,y1)-(x2,y2) в ЛОКАЛЬНОЙ СК вида (мм). `orientation`: horizontal/vertical/parallel. `viewNumber`: номер вида (0 = первый ассоциативный/главный). Значение измеряется автоматически. Возвращает измеренное значение и номер вида. | + +Контракт: активный документ — чертёж; на чертеже есть хотя бы один ассоциативный вид. Координаты — +локальные вида (см. выше). `drawing_create_standard_views` возвращает `ViewNumbers` для адресации. + +## Архитектура + +В существующем `DrawingService`. Свой enum `DimensionOrientation` (паттерн `MateType`/`StampField`). + +- `src/Kompas.Mcp.Core/Drawings/DimensionOrientation.cs` — enum + static `DimensionOrientations` + (`Parse(string)`, `ToKompas` → `ksLineDimensionOrientationEnum`). +- `DrawingService.AddLinearDimensionAsync(viewNumber, x1,y1,x2,y2,x3,y3, DimensionOrientation, ct)`. +- `DrawingViewsResult` += `IReadOnlyList ViewNumbers`. +- Инструмент `drawing_add_linear_dimension` в `DrawingTools` (orientation строкой → Parse). + +## Валидация (чистые static, unit-тест) + +- `DimensionOrientations.Parse` — horizontal/vertical/parallel (+рус.) → enum; иначе `ArgumentException`. +- `DimensionOrientations.ToKompas` — enum → `ksLineDimensionOrientationEnum` (0/1/2). +- `DrawingValidation.RequireFiniteCoords(params)` — координаты конечны (NaN/Infinity → ошибка). + +## Реализация + +`AddLinearDimensionCore`: валидация координат + orientation → `RequireActiveDrawing` → найти вид +(`viewNumber<=0` → первый с `Number!=0`; иначе по `Number`, ошибка если нет) → `(ISymbols2DContainer)view` +→ `LineDimensions.Add()` → задать X1..Y3 + Orientation → `Update()` (FALSE → откат `dim.Delete()` + +ошибка) → проверить `dim.Valid` (false → откат + ошибка) → вернуть `AddedDimension { Value = +((IDimensionText)dim).NominalValue, ViewNumber = view.Number }`. RCW точечно не освобождаем (v2-2). + +## Тестирование + +### Unit (`DimensionOrientationsTests`) +- `Parse` — horizontal/vertical/parallel и рус.-синонимы → enum; бросает на мусоре. +- `ToKompas` — каждый → 1/2/0. +- `RequireFiniteCoords` — бросает на NaN/Infinity; пропускает конечные. + +### Integration (`DrawingDimensionTests`) +Паттерн: построить деталь → сохранить → создать чертёж → стандартные виды → размер → проверить → +`finally CloseAsync` (база `IntegrationTestBase`). +1. **Горизонтальный** (0,0)-(40,0) → `Value ≈ 40`; `view.ObjectCount` вырос. +2. **Вертикальный** (0,0)-(0,20) → `Value ≈ 20`. +3. **Адресация вида**: `CreateStandardViewsAsync` вернул `ViewNumbers` (3 шт); размер с конкретным + `viewNumber` ставится в этот вид. +4. **Нет видов**: чертёж без видов → понятная ошибка. + +(Сценарий 1 = промотированный спайк; спайк-файл удаляется.) + +## Дальнейшее (вне спека) +- Диаметральные/радиальные/угловые размеры; привязка к геометрии вида (ассоциативно, `BaseObject`); + допуски/обозначения; рамка/формат листа.