From 5272066bef24b92b3ed98f5a30f5f3df5bc3c964 Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 21:13:11 +0300 Subject: [PATCH 1/2] =?UTF-8?q?feat(drawing):=20=D1=82=D0=B5=D0=BA=D1=81?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=BE=D0=B1=D0=BE=D0=B7=D0=BD?= =?UTF-8?q?=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=E2=80=94=20=D1=88=D0=B5?= =?UTF-8?q?=D1=80=D0=BE=D1=85=D0=BE=D0=B2=D0=B0=D1=82=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C,=20=D1=82=D0=B5=D0=BA=D1=81=D1=82,=20=D1=82=D0=B5=D1=85.?= =?UTF-8?q?=20=D1=82=D1=80=D0=B5=D0=B1=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drawing_add_rough (знак шероховатости: ISymbols2DContainer.Roughs + IRoughParams, SignType ksRoughSignEnum, значение Ra/Rz через RoughParamText.Str), drawing_add_text (свободная надпись: IDrawingContainer.DrawingTexts + IText.Str), drawing_set_technical_requirements (блок тех. требований уровня документа: IDrawingDocument.TechnicalDemand.Text). - DrawingService: AddRoughAsync/AddTextAsync/SetTechnicalRequirementsAsync + ReadTechnicalRequirementsAsync + счётчики; RequireDrawingContainer/RequireTechnicalDemand - RoughSignType (enum + Parse/ToKompas), DrawingAnnotationResult (Value read-back из COM) - RequireNonEmptyText в DrawingValidation - 13 unit + 13 интеграционных тестов (всего 267 зелёных), сборка Release чистая Спайк подтвердил: значение шероховатости через IRoughParams.RoughParamText.Str (round-trip); текст НЕ в IView.ObjectCount (счёт по DrawingTexts.Count); тех. требования IsCreated False→True при первом Text.Str+Update, многострочно через \n. Ревью Codex спека учтено (height убран — это высота блока, не шрифт; guards; read-back возврат). Спек — docs/superpowers/specs/. Co-Authored-By: Claude Opus 4.7 (1M context) --- ...6-05-27-drawing-text-annotations-design.md | 167 ++++++++++++++++++ .../Drawings/DrawingAnnotationResult.cs | 11 ++ .../Drawings/DrawingService.cs | 142 +++++++++++++++ .../Drawings/DrawingValidation.cs | 7 + src/Kompas.Mcp.Core/Drawings/RoughSignType.cs | 41 +++++ src/Kompas.Mcp.Host/Tools/DrawingTools.cs | 50 ++++++ .../DrawingValidationTests.cs | 11 ++ .../Integration/DrawingRoughTests.cs | 107 +++++++++++ .../Integration/DrawingTechReqTests.cs | 76 ++++++++ .../Integration/DrawingTextTests.cs | 115 ++++++++++++ tests/Kompas.Mcp.Tests/RoughSignTypesTests.cs | 29 +++ 11 files changed, 756 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-27-drawing-text-annotations-design.md create mode 100644 src/Kompas.Mcp.Core/Drawings/DrawingAnnotationResult.cs create mode 100644 src/Kompas.Mcp.Core/Drawings/RoughSignType.cs create mode 100644 tests/Kompas.Mcp.Tests/Integration/DrawingRoughTests.cs create mode 100644 tests/Kompas.Mcp.Tests/Integration/DrawingTechReqTests.cs create mode 100644 tests/Kompas.Mcp.Tests/Integration/DrawingTextTests.cs create mode 100644 tests/Kompas.Mcp.Tests/RoughSignTypesTests.cs diff --git a/docs/superpowers/specs/2026-05-27-drawing-text-annotations-design.md b/docs/superpowers/specs/2026-05-27-drawing-text-annotations-design.md new file mode 100644 index 0000000..e9c7ca8 --- /dev/null +++ b/docs/superpowers/specs/2026-05-27-drawing-text-annotations-design.md @@ -0,0 +1,167 @@ +# Дизайн: текстовые обозначения чертежа — шероховатость, текст, тех. требования (API7) + +**Дата:** 2026-05-27 +**Статус:** дизайн согласован (все три в одном инкременте), спайк проведён, ревью Codex спека учтено — к реализации + +## Правки по ревью Codex (спек) + +- **#4** параметр `height` у `drawing_add_text` **убран:** `IDrawingText.Height` — высота блока + форматирования, НЕ размер шрифта (шрифт задаётся на уровне `ITextItem`, вне объёма). Текст ставится + стилем по умолчанию. (Снимает и #10 — валидация height не нужна.) +- **#3/#11** сервис возвращает значение, **прочитанное обратно из COM** после `Update` (rough — + `RoughParamText.Str`; text — `((IText)dt).Str`) — как `NominalValue` у размеров. Тест `Value==вход` + доказывает round-trip. Пост-Add откат `Delete` есть в коде; не форсируется тестом (для валидных + параметров COM всегда `Valid` — как решено у диаметрального; путь идентичен протестированному угловому). +- **#1** `value` шероховатости нормализуется (`null`/whitespace → `""`); возвращается нормализованное + (read-back), контракт `Value` непустой не нарушается. +- **#2/#5/#7** добавлены null/QI-guards: `Roughs`/`(IRoughParams)`/`RoughParamText`; + `(IDrawingContainer)`/`DrawingTexts`/`(IText)`; `(IDrawingDocument)`/`TechnicalDemand`/`Text` — + каждый с раздельной диагностикой (как `RequireStampCell`/`RequireSymbols2DContainer`). +- **#6** тесты текста дополнены: многострочный round-trip (`\n`), несуществующий `viewNumber>0`. +- **#8** добавлен helper `ReadTechnicalRequirementsAsync` — тест читает `td.Text.Str` и проверяет + перезапись (как `DrawingStampTests` перечитывают графы). +- **#9** подсчёт строк тех. требований нормализован: `text.Replace("\r\n","\n")`, хвостовые пустые + строки отбрасываются (`"a\n"` → 1 строка). + +## Цель + +Веха 2D-ЧЕРТЁЖ, инкремент 6. После завершения базового семейства размеров — **текстовые обозначения**: +знак шероховатости, свободная текстовая надпись, технические требования. Три инструмента покрывают +самые частые «не-размерные» элементы конструкторского чертежа. + +## Спайк: все три механизма подтверждены вживую (НЕ разучивать) + +Спайк (`_SpikeAnnotations`, прогнан на реальном КОМПАС v24, затем удалён) на коробке 40×30×20 с +тремя стандартными видами. + +### Шероховатость — на виде (`ISymbols2DContainer.Roughs`) + +``` +IRough rough = symbols.Roughs.Add(); // без параметров +rough.BranchX0 = 20; rough.BranchY0 = 25; // положение знака (ЛОКАЛЬНАЯ СК вида, мм) +rough.Angle = 0; // угол наклона оси знака (градусы) +IRoughParams rp = (IRoughParams)rough; // QI (как IDimensionText у размеров) +rp.SignType = ksRoughSignEnum.ksDeleteMaterial; // тип знака +rp.RoughParamText.Str = "Ra 1.6"; // значение (Ra/Rz) — текст +rough.Update(); // True, rough.Valid == True +``` + +**Проверено:** `Update=True`, `Valid=True`, `RoughParamText.Str` round-trip = `"Ra 1.6"`, `Roughs.Count` +→ 1. `ksRoughSignEnum`: `ksNoProcessingType=0` (без указания обработки), `ksDeleteMaterial=1` (с +удалением слоя материала), `ksWithoutDeleteMaterial=2` (без удаления). Положение — свободные координаты +(`BranchX0/Y0`); `BaseObject` (привязка к контуру) не задаём — будущее. + +### Свободный текст — на виде (`IDrawingContainer.DrawingTexts`, НЕ Symbols!) + +``` +IDrawingContainer dc = (IDrawingContainer)view; // ВНИМАНИЕ: текст в контейнере геометрии, +IDrawingText dt = dc.DrawingTexts.Add(); // а НЕ в ISymbols2DContainer +dt.X = 30; dt.Y = 45; dt.Angle = 0; // точка привязки (ЛОКАЛЬНАЯ СК вида, мм) +((IText)dt).Str = "Образец надписи"; // содержимое (QI к IText), \n — многострочно +dt.Update(); // True, dt.Valid == True +``` + +**Проверено:** `Update=True`, `Valid=True`, `Str` round-trip, `DrawingTexts.Count` → **2** (вид уже +содержал 1 текст — авто-подпись вида; проверять по ДЕЛЬТЕ before+1, не по абсолюту). `ObjectCount` +4→4 — текст **НЕ** входит в `IView.ObjectCount` (как и размеры) → проверять `DrawingTexts.Count`. + +### Технические требования — на уровне ДОКУМЕНТА (`IDrawingDocument.TechnicalDemand`) + +``` +IDrawingDocument dd = (IDrawingDocument)doc; // QI от активного IKompasDocument2D +ITechnicalDemand td = dd.TechnicalDemand; // единый блок на документ +td.Text.Str = "1. Общие допуски по ГОСТ 30893.1.\n2. Острые кромки притупить."; // \n — строки +td.Update(); // True +``` + +**Проверено:** `IsCreated` False→True (первый `Text.Str`+`Update()` создаёт блок), `Update=True`, текст +с `\n` сохранён построчно. Объект уровня документа (не вида), единственный, над основной надписью. +`Str` замещает содержимое (как у штампа) → инструмент `set` (перезапись). + +## MCP-инструменты + +| Инструмент | Параметры | Поведение | +|---|---|---| +| `drawing_add_rough` | `x,y` (положение знака), `value=""` (Ra/Rz, напр. "Ra 1.6"), `signType="delete"` (delete\|without\|none), `angle=0` (°), `viewNumber=0` | Поставить знак шероховатости на виде. Положение `x,y` в ЛСК вида (мм). `value` — текст параметра (пусто = знак без значения). Возвращает значение и номер вида. | +| `drawing_add_text` | `x,y` (точка привязки), `text`, `angle=0` (°), `viewNumber=0` | Поставить свободную текстовую надпись на виде стилем по умолчанию. `text` — содержимое (`\n` — многострочно). Возвращает текст (read-back) и номер вида. | +| `drawing_set_technical_requirements` | `text` | Задать технические требования активного чертежа (единый блок над штампом; перезаписывает прежние). `text` — строки через `\n`. Возвращает число строк. | + +## Архитектура + +В существующем `DrawingService` (namespace `Kompas.Mcp.Core.Drawings`). Шероховатость/текст — +per-view; тех. требования — per-document. + +- `AddRoughAsync(viewNumber, x, y, value, signType, angleDeg, ct)` → `DrawingAnnotationResult`. + Введём `record DrawingAnnotationResult { string Value; int ViewNumber }` (универсальный для rough/text — + `Value`=строка, прочитанная обратно из COM; `ViewNumber`). Тех. требования возвращают число строк (int). +- `AddTextAsync(viewNumber, x, y, text, angleDeg, ct)` → `DrawingAnnotationResult`. +- `SetTechnicalRequirementsAsync(text, ct)` → `int` (число строк). +- `ReadTechnicalRequirementsAsync(ct)` → `string` (для теста — `td.Text.Str`). +- Helpers: `RequireSymbols2DContainer` (есть, для rough), новый `RequireDrawingContainer(viewNumber)` + = guarded `(IDrawingContainer)FindView(...)` (для text), новый `RequireDrawingDocument()` = + guarded `(IDrawingDocument)RequireActiveDrawing()` (для тех. требований). Все QI с раздельной диагностикой. +- Счётчики для тестов: `GetViewRoughCountAsync`, `GetViewTextCountAsync`. +- Новый enum-файл `RoughSignType.cs`: `enum RoughSignType {NoProcessing, DeleteMaterial, WithoutDeleteMaterial}` + + `RoughSignTypes.Parse(string)`/`ToKompas(...)` (→ `ksRoughSignEnum`), по образцу `AngleDimensionTypes`. +- Новый файл `DrawingAnnotationResult.cs`. +- Инструменты в `DrawingTools.cs`. + +## Валидация (чистые static, unit-тест) + +- `RequireFiniteCoords` (есть) — координаты rough/text. +- Новый `RequireNonEmptyText(string, paramName)` — для `text` (drawing_add_text, тех. требования). + `value` шероховатости НЕ обязателен (знак без значения допустим; `null`/whitespace → `""`). +- `RoughSignTypes.Parse` — разбор строки (unit-тест; `ToKompas` → `ksRoughSignEnum` НЕ покрываем unit — + граница проекта, как у `AngleDimensionTypes`/`DimensionOrientations`). + +## Реализация + +**`AddRoughCore`**: нормализация `value` (`null`/whitespace → `""`) → `RequireFiniteCoords(x,y,angleDeg)` +→ `RequireSymbols2DContainer` → `symbols.Roughs` (null-check) → `.Add()` (null-check) → `BranchX0/Y0/Angle` +→ `(IRoughParams)rough` (null-check QI) → `SignType=ToKompas`, `rp.RoughParamText` (null-check) `.Str = value` +→ `Update()` (FALSE → откат `Delete`) → `Valid` (false → откат) → читаем `rp.RoughParamText.Str` обратно +→ `DrawingAnnotationResult{Value=read-back, ViewNumber}`. + +**`AddTextCore`**: `RequireNonEmptyText(text)` + `RequireFiniteCoords(x,y,angleDeg)` → +`RequireDrawingContainer` → `dc.DrawingTexts` (null-check) → `.Add()` (null-check) → `X/Y/Angle` → +`(IText)dt` (null-check QI) `.Str = text` → `Update()` (FALSE → откат `Delete`) → `Valid` (false → откат) +→ читаем `((IText)dt).Str` обратно → `DrawingAnnotationResult{Value=read-back, ViewNumber}`. + +**`SetTechnicalRequirementsCore`**: `RequireNonEmptyText(text)` → нормализация `text.Replace("\r\n","\n")` +→ `RequireDrawingDocument()` → `dd.TechnicalDemand` (null-check) → `td.Text` (null-check) `.Str = text` → +`td.Update()` (FALSE → ошибка; объект уровня документа — отката `Delete` НЕ делаем, перезапись идемпотентна) +→ вернуть число непустых-после-trim хвоста строк (`TrimEnd('\n').Split('\n').Length`). + +**`RequireDrawingContainer(viewNumber)`** = `FindView` → `(IDrawingContainer)view` (null → «вид не приводится +к IDrawingContainer»). **`RequireDrawingDocument()`** = `RequireActiveDrawing()` → `(IDrawingDocument)doc` +(null → «чертёж не приводится к IDrawingDocument»). + +RCW точечно не освобождаем (консистентно с остальным `DrawingService`; долг v2-2). + +## Тестирование + +### Unit (`RoughSignTypesTests`, `DrawingValidationTests`) +- `RoughSignTypes.Parse`: `delete/without/none` (+ рус. синонимы) → enum; неизвестное → `ArgumentException`; null → `ArgumentNullException`. +- `RequireNonEmptyText`: бросает на null/пусто/пробелы; пропускает непустое. + +### Integration (`DrawingRoughTests`, `DrawingTextTests`, `DrawingTechReqTests`; наследуют `IntegrationTestBase`) +Шероховатость: +1. **Ставится + round-trip**: `value="Ra 1.6"`, `signType=delete` → `Value=="Ra 1.6"` (read-back из COM), + попадание в целевой вид (`Roughs.Count` +1, адресация по `viewNumber`). +2. **Знак без значения**: `value=""` → ставится (Valid), `Roughs.Count` +1. +3. **Нет видов** → понятная ошибка. 4. **Несуществующий `viewNumber>0`** → ошибка. + +Текст: +5. **Ставится + round-trip**: `text` → `Value==text` (read-back), `DrawingTexts.Count` +1 (по ДЕЛЬТЕ — + вид уже мог содержать подпись), адресация по целевому `viewNumber`. +6. **Многострочный** (`"строка1\nстрока2"`) → `Value` сохраняет обе строки (round-trip `\n`). +7. **Пустой текст** → `ArgumentException` (до Add). 8. **Нет видов** → ошибка. 9. **Несуществующий `viewNumber>0`** → ошибка. + +Тех. требования: +10. **Задаются + round-trip**: многострочный текст → `lines==2`; `ReadTechnicalRequirementsAsync` возвращает + тот же текст; повторный вызов с другим текстом перезаписывает (read-back = новый, без накопления). +11. **Пустой текст** → `ArgumentException`. 12. **Активный документ не чертёж** → понятная ошибка. + +## Дальнейшее (вне спека) +- Привязка шероховатости/выносок к геометрии (`BaseObject`); выноски (`Leaders`), обозначения баз + (`Bases`), допуски формы (`Tolerances`); рамка/формат листа; ассоциативная привязка размеров. diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingAnnotationResult.cs b/src/Kompas.Mcp.Core/Drawings/DrawingAnnotationResult.cs new file mode 100644 index 0000000..ebfbfad --- /dev/null +++ b/src/Kompas.Mcp.Core/Drawings/DrawingAnnotationResult.cs @@ -0,0 +1,11 @@ +namespace Kompas.Mcp.Core.Drawings; + +/// Результат простановки текстового обозначения (шероховатость/надпись) на виде. +public sealed record DrawingAnnotationResult +{ + /// Содержимое обозначения, прочитанное обратно из COM (значение Ra/Rz либо текст надписи). + public required string Value { get; init; } + + /// Номер вида, на котором поставлено обозначение. + public required int ViewNumber { get; init; } +} diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs index ba87a2f..00d0224 100644 --- a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs +++ b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs @@ -287,6 +287,148 @@ public sealed class DrawingService public Task GetViewAngularDimensionCountAsync(int viewNumber, CancellationToken ct = default) => _dispatcher.InvokeAsync(() => RequireSymbols2DContainer(viewNumber).Symbols.AngleDimensions?.Count ?? 0, ct); + // ───────────────────────── Текстовые обозначения (инкремент 6) ───────────────────────── + + /// + /// Поставить знак шероховатости на виде в точке (,) + /// (ЛОКАЛЬНАЯ СК вида, мм). — текст параметра (Ra/Rz; пусто = знак без + /// значения). — тип знака. — угол наклона + /// оси знака (°). Возвращает значение (read-back) и номер вида. + /// + public Task AddRoughAsync(int viewNumber, double x, double y, string? value, + RoughSignType signType, double angleDeg, CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => AddRoughCore(viewNumber, x, y, value, signType, angleDeg), ct); + + private DrawingAnnotationResult AddRoughCore(int viewNumber, double x, double y, string? value, + RoughSignType signType, double angleDeg) + { + DrawingValidation.RequireFiniteCoords(x, y, angleDeg); + var text = string.IsNullOrWhiteSpace(value) ? string.Empty : value; + + var (view, symbols) = RequireSymbols2DContainer(viewNumber); + var roughs = symbols.Roughs + ?? throw new InvalidOperationException("Коллекция Roughs недоступна на виде."); + var rough = roughs.Add() + ?? throw new InvalidOperationException("Roughs.Add вернул null."); + try + { + rough.BranchX0 = x; rough.BranchY0 = y; rough.Angle = angleDeg; + var rp = rough as IRoughParams + ?? throw new InvalidOperationException("Знак шероховатости не приводится к IRoughParams."); + rp.SignType = RoughSignTypes.ToKompas(signType); + var paramText = rp.RoughParamText + ?? throw new InvalidOperationException("RoughParamText недоступен (текст значения)."); + paramText.Str = text; + + if (!rough.Update()) + throw new InvalidOperationException("IRough.Update вернул FALSE — знак не построен."); + if (!rough.Valid) + throw new InvalidOperationException("Знак шероховатости построен невалидным."); + + var readBack = rp.RoughParamText?.Str ?? string.Empty; // read-back из COM + return new DrawingAnnotationResult { Value = readBack, ViewNumber = view.Number }; + } + catch + { + try { rough.Delete(); } catch { /* лучшее усилие */ } + throw; + } + } + + /// Число знаков шероховатости на виде (для проверки попадания в вид). + public Task GetViewRoughCountAsync(int viewNumber, CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => RequireSymbols2DContainer(viewNumber).Symbols.Roughs?.Count ?? 0, ct); + + /// + /// Поставить свободную текстовую надпись на виде в точке (,) + /// (ЛОКАЛЬНАЯ СК вида, мм) стилем по умолчанию. — содержимое (\n — многострочно). + /// — угол наклона текста (°). Возвращает текст (read-back) и номер вида. + /// + public Task AddTextAsync(int viewNumber, double x, double y, string text, + double angleDeg, CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => AddTextCore(viewNumber, x, y, text, angleDeg), ct); + + private DrawingAnnotationResult AddTextCore(int viewNumber, double x, double y, string text, double angleDeg) + { + DrawingValidation.RequireNonEmptyText(text, nameof(text)); + DrawingValidation.RequireFiniteCoords(x, y, angleDeg); + + var (view, container) = RequireDrawingContainer(viewNumber); + var texts = container.DrawingTexts + ?? throw new InvalidOperationException("Коллекция DrawingTexts недоступна на виде."); + var dt = texts.Add() + ?? throw new InvalidOperationException("DrawingTexts.Add вернул null."); + try + { + dt.X = x; dt.Y = y; dt.Angle = angleDeg; + var content = dt as IText + ?? throw new InvalidOperationException("Надпись не приводится к IText."); + content.Str = text; + + if (!dt.Update()) + throw new InvalidOperationException("IDrawingText.Update вернул FALSE — надпись не построена."); + if (!dt.Valid) + throw new InvalidOperationException("Надпись построена невалидной."); + + var readBack = ((IText)dt).Str ?? string.Empty; // read-back из COM + return new DrawingAnnotationResult { Value = readBack, ViewNumber = view.Number }; + } + catch + { + try { dt.Delete(); } catch { /* лучшее усилие */ } + throw; + } + } + + /// Число текстовых надписей на виде (для проверки попадания в вид; текст в + /// IDrawingContainer, а не в IView.ObjectCount). + public Task GetViewTextCountAsync(int viewNumber, CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => RequireDrawingContainer(viewNumber).Container.DrawingTexts?.Count ?? 0, ct); + + /// + /// Задать технические требования активного чертежа (единый блок над основной надписью; перезаписывает + /// прежние). — строки через \n. Возвращает число строк. + /// + public Task SetTechnicalRequirementsAsync(string text, CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => SetTechnicalRequirementsCore(text), ct); + + private int SetTechnicalRequirementsCore(string text) + { + DrawingValidation.RequireNonEmptyText(text, nameof(text)); + var normalized = text.Replace("\r\n", "\n"); + + var td = RequireTechnicalDemand(); + var content = td.Text + ?? throw new InvalidOperationException("Текст технических требований недоступен (Text == null)."); + content.Str = normalized; // Str замещает содержимое (как у штампа) + if (!td.Update()) + throw new InvalidOperationException("ITechnicalDemand.Update вернул FALSE — требования не заданы."); + + // Число содержательных строк: хвостовые пустые строки отбрасываем ("a\n" → 1). + return normalized.TrimEnd('\n').Split('\n').Length; + } + + /// Прочитать текст технических требований активного чертежа (для проверки/диагностики). + public Task ReadTechnicalRequirementsAsync(CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => RequireTechnicalDemand().Text?.Str ?? string.Empty, ct); + + private ITechnicalDemand RequireTechnicalDemand() + { + var doc = RequireActiveDrawing() as IDrawingDocument + ?? throw new InvalidOperationException("Активный чертёж не приводится к IDrawingDocument."); + return doc.TechnicalDemand + ?? throw new InvalidOperationException("У чертежа недоступны технические требования (TechnicalDemand == null)."); + } + + /// Вид + его IDrawingContainer (QI от вида). Для текстовых надписей (DrawingTexts). + private (IView View, IDrawingContainer Container) RequireDrawingContainer(int viewNumber) + { + var view = FindView(viewNumber); + var container = view as IDrawingContainer + ?? throw new InvalidOperationException("Вид не приводится к IDrawingContainer."); + return (view, container); + } + /// Вид + его ISymbols2DContainer (QI от вида). Общий для линейных/диаметральных/… размеров. private (IView View, ISymbols2DContainer Symbols) RequireSymbols2DContainer(int viewNumber) { diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs b/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs index 2ce1ef0..2cbefa9 100644 --- a/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs +++ b/src/Kompas.Mcp.Core/Drawings/DrawingValidation.cs @@ -48,6 +48,13 @@ public static class DrawingValidation throw new ArgumentOutOfRangeException(nameof(radius), "Радиус должен быть конечным и > 0."); } + /// Проверить, что текст не пустой и не только из пробелов. + public static void RequireNonEmptyText(string? text, string paramName) + { + if (string.IsNullOrWhiteSpace(text)) + throw new ArgumentException("Текст не должен быть пустым.", paramName); + } + /// Минимальное расстояние между выносными точками линейного размера (мм). private const double MinPointDistance = 1e-7; diff --git a/src/Kompas.Mcp.Core/Drawings/RoughSignType.cs b/src/Kompas.Mcp.Core/Drawings/RoughSignType.cs new file mode 100644 index 0000000..fcbaaa8 --- /dev/null +++ b/src/Kompas.Mcp.Core/Drawings/RoughSignType.cs @@ -0,0 +1,41 @@ +using Kompas6Constants; + +namespace Kompas.Mcp.Core.Drawings; + +/// Тип знака шероховатости (обёртка над ). +public enum RoughSignType +{ + /// Без указания вида обработки. + NoProcessing, + /// С удалением слоя материала. + DeleteMaterial, + /// Без удаления слоя материала. + WithoutDeleteMaterial, +} + +/// Маппинг типа знака шероховатости ↔ перечисление КОМПАС и разбор строки. +public static class RoughSignTypes +{ + public static ksRoughSignEnum ToKompas(RoughSignType type) => type switch + { + RoughSignType.NoProcessing => ksRoughSignEnum.ksNoProcessingType, + RoughSignType.DeleteMaterial => ksRoughSignEnum.ksDeleteMaterial, + RoughSignType.WithoutDeleteMaterial => ksRoughSignEnum.ksWithoutDeleteMaterial, + _ => throw new ArgumentOutOfRangeException(nameof(type), type, "Неизвестный тип знака шероховатости."), + }; + + /// Разобрать строку типа знака (англ./рус.) в . + public static RoughSignType Parse(string value) + { + ArgumentNullException.ThrowIfNull(value); + return value.Trim().ToLowerInvariant() switch + { + "delete" or "deletematerial" or "с удалением" or "с удалением материала" => RoughSignType.DeleteMaterial, + "without" or "withoutdelete" or "без удаления" or "без удаления материала" => RoughSignType.WithoutDeleteMaterial, + "none" or "noprocessing" or "без указания" or "любая" => RoughSignType.NoProcessing, + _ => throw new ArgumentException( + $"Неизвестный тип знака шероховатости '{value}'. Допустимо: delete, without, none.", + nameof(value)), + }; + } +} diff --git a/src/Kompas.Mcp.Host/Tools/DrawingTools.cs b/src/Kompas.Mcp.Host/Tools/DrawingTools.cs index b74aba3..a729a70 100644 --- a/src/Kompas.Mcp.Host/Tools/DrawingTools.cs +++ b/src/Kompas.Mcp.Host/Tools/DrawingTools.cs @@ -127,4 +127,54 @@ public sealed class DrawingTools(KompasSession session, DrawingService drawing) var r = await drawing.AddAngularDimensionAsync(viewNumber, xc, yc, x1, y1, x2, y2, x3, y3, t); return $"Угловой размер поставлен на виде {r.ViewNumber}, {r.Value:0.###}°."; } + + [McpServerTool(Name = "drawing_add_rough")] + [Description("Поставить знак шероховатости на виде активного чертежа в точке (x,y) в ЛОКАЛЬНОЙ СК вида " + + "(мм). value — текст параметра (например \"Ra 1.6\" или \"Rz 40\"; пусто = знак без значения). " + + "signType: delete (с удалением слоя материала) | without (без удаления) | none (без указания вида " + + "обработки). angle — угол наклона оси знака в градусах. viewNumber — номер вида из " + + "drawing_create_standard_views (0 = первый/главный). Возвращает значение и номер вида.")] + public async Task AddRough( + [Description("X положения знака (СК вида, мм)")] double x, + [Description("Y положения знака")] double y, + [Description("Текст параметра, напр. \"Ra 1.6\" (пусто = без значения)")] string value = "", + [Description("Тип знака: delete | without | none")] string signType = "delete", + [Description("Угол наклона оси знака, градусы")] double angle = 0, + [Description("Номер вида (0 = первый/главный)")] int viewNumber = 0) + { + await session.ConnectAsync(); + var st = RoughSignTypes.Parse(signType); + var r = await drawing.AddRoughAsync(viewNumber, x, y, value, st, angle); + var shown = string.IsNullOrEmpty(r.Value) ? "(без значения)" : r.Value; + return $"Знак шероховатости поставлен на виде {r.ViewNumber}: {shown}."; + } + + [McpServerTool(Name = "drawing_add_text")] + [Description("Поставить свободную текстовую надпись на виде активного чертежа в точке (x,y) в ЛОКАЛЬНОЙ " + + "СК вида (мм) стилем по умолчанию. text — содержимое надписи (\\n — несколько строк). angle — угол " + + "наклона текста в градусах. viewNumber — номер вида из drawing_create_standard_views (0 = первый/" + + "главный). Возвращает поставленный текст и номер вида.")] + public async Task AddText( + [Description("X точки привязки (СК вида, мм)")] double x, + [Description("Y точки привязки")] double y, + [Description("Текст надписи (\\n — многострочно)")] string text = "", + [Description("Угол наклона текста, градусы")] double angle = 0, + [Description("Номер вида (0 = первый/главный)")] int viewNumber = 0) + { + await session.ConnectAsync(); + var r = await drawing.AddTextAsync(viewNumber, x, y, text, angle); + return $"Надпись поставлена на виде {r.ViewNumber}."; + } + + [McpServerTool(Name = "drawing_set_technical_requirements")] + [Description("Задать технические требования активного чертежа — единый текстовый блок над основной " + + "надписью (ГОСТ). text — содержимое (\\n разделяет пункты/строки, например \"1. ...\\n2. ...\"). " + + "Перезаписывает прежние технические требования (не добавляет). Возвращает число строк.")] + public async Task SetTechnicalRequirements( + [Description("Текст требований (\\n — строки)")] string text) + { + await session.ConnectAsync(); + var lines = await drawing.SetTechnicalRequirementsAsync(text); + return $"Технические требования заданы ({lines} стр.)."; + } } diff --git a/tests/Kompas.Mcp.Tests/DrawingValidationTests.cs b/tests/Kompas.Mcp.Tests/DrawingValidationTests.cs index 8d6584d..b072e47 100644 --- a/tests/Kompas.Mcp.Tests/DrawingValidationTests.cs +++ b/tests/Kompas.Mcp.Tests/DrawingValidationTests.cs @@ -80,4 +80,15 @@ public sealed class DrawingValidationTests [Fact] public void RequirePositiveRadius_accepts_positive() => Assert.Null(Record.Exception(() => DrawingValidation.RequirePositiveRadius(15))); + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void RequireNonEmptyText_throws_on_empty(string? text) + => Assert.Throws(() => DrawingValidation.RequireNonEmptyText(text, "text")); + + [Fact] + public void RequireNonEmptyText_accepts_non_empty() + => Assert.Null(Record.Exception(() => DrawingValidation.RequireNonEmptyText("Ra 1.6", "text"))); } diff --git a/tests/Kompas.Mcp.Tests/Integration/DrawingRoughTests.cs b/tests/Kompas.Mcp.Tests/Integration/DrawingRoughTests.cs new file mode 100644 index 0000000..d58ba0c --- /dev/null +++ b/tests/Kompas.Mcp.Tests/Integration/DrawingRoughTests.cs @@ -0,0 +1,107 @@ +using Kompas.Mcp.Core.Documents; +using Kompas.Mcp.Core.Drawings; +using Kompas.Mcp.Core.Modeling; + +namespace Kompas.Mcp.Tests.Integration; + +/// Интеграция: знак шероховатости на виде (API7 ISymbols2DContainer.Roughs + IRoughParams). +[Trait("Category", "Integration")] +[Collection(KompasCollection.Name)] +public sealed class DrawingRoughTests : IntegrationTestBase +{ + private readonly DocumentService _docs; + private readonly PartModeler _modeler; + private readonly DrawingService _drawing; + + public DrawingRoughTests(KompasFixture fx) : base(fx) + { + _docs = new DocumentService(fx.Session, fx.Dispatcher); + _modeler = new PartModeler(fx.Session, fx.Dispatcher); + _drawing = new DrawingService(fx.Session, fx.Dispatcher); + } + + private async Task BuildAndSaveBoxAsync() + { + var path = TestPaths.NewFile(".m3d"); + await _docs.CreateAsync(KompasDocumentType.Part); + try + { + var s = await _modeler.OpenSketchAsync(BasePlane.XOY); + await _modeler.AddRectangleAsync(s, 0, 0, 40, 30); + await _modeler.CloseSketchAsync(s); + await _modeler.ExtrudeAsync(s, depth: 20); + await _modeler.RebuildAsync(); + await _docs.SaveAsAsync(path); + } + finally { await _docs.CloseAsync(save: false); } + return path; + } + + [Fact] + public async Task Rough_is_placed_with_value_and_targets_view() + { + var partFile = await BuildAndSaveBoxAsync(); + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + var views = await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150); + var target = views.ViewNumbers[0]; + + var before = await _drawing.GetViewRoughCountAsync(target); + var r = await _drawing.AddRoughAsync(target, x: 20, y: 25, value: "Ra 1.6", + signType: RoughSignType.DeleteMaterial, angleDeg: 0); + var after = await _drawing.GetViewRoughCountAsync(target); + + Assert.Equal(target, r.ViewNumber); + Assert.Equal("Ra 1.6", r.Value); // read-back из COM + Assert.Equal(before + 1, after); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Rough_without_value_is_placed() + { + var partFile = await BuildAndSaveBoxAsync(); + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150); + var before = await _drawing.GetViewRoughCountAsync(0); + var r = await _drawing.AddRoughAsync(0, x: 15, y: 15, value: "", + signType: RoughSignType.NoProcessing, angleDeg: 0); + var after = await _drawing.GetViewRoughCountAsync(0); + Assert.Equal(before + 1, after); + Assert.Equal(string.Empty, r.Value); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task No_views_throws() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await Assert.ThrowsAsync(() => + _drawing.AddRoughAsync(0, x: 0, y: 0, value: "Ra 1.6", + signType: RoughSignType.DeleteMaterial, angleDeg: 0)); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Unknown_view_number_throws() + { + var partFile = await BuildAndSaveBoxAsync(); + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150); + await Assert.ThrowsAsync(() => + _drawing.AddRoughAsync(999, x: 0, y: 0, value: "Ra 1.6", + signType: RoughSignType.DeleteMaterial, angleDeg: 0)); + } + finally { await _docs.CloseAsync(save: false); } + } +} diff --git a/tests/Kompas.Mcp.Tests/Integration/DrawingTechReqTests.cs b/tests/Kompas.Mcp.Tests/Integration/DrawingTechReqTests.cs new file mode 100644 index 0000000..d6c447f --- /dev/null +++ b/tests/Kompas.Mcp.Tests/Integration/DrawingTechReqTests.cs @@ -0,0 +1,76 @@ +using Kompas.Mcp.Core.Documents; +using Kompas.Mcp.Core.Drawings; + +namespace Kompas.Mcp.Tests.Integration; + +/// Интеграция: технические требования чертежа (API7 IDrawingDocument.TechnicalDemand). +[Trait("Category", "Integration")] +[Collection(KompasCollection.Name)] +public sealed class DrawingTechReqTests : IntegrationTestBase +{ + private readonly DocumentService _docs; + private readonly DrawingService _drawing; + + public DrawingTechReqTests(KompasFixture fx) : base(fx) + { + _docs = new DocumentService(fx.Session, fx.Dispatcher); + _drawing = new DrawingService(fx.Session, fx.Dispatcher); + } + + [Fact] + public async Task Requirements_are_set_and_read_back() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + var text = "1. Общие допуски по ГОСТ 30893.1.\n2. Острые кромки притупить."; + var lines = await _drawing.SetTechnicalRequirementsAsync(text); + Assert.Equal(2, lines); + + var readBack = await _drawing.ReadTechnicalRequirementsAsync(); + Assert.Contains("Общие допуски", readBack); + Assert.Contains("Острые кромки", readBack); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Overwrite_replaces_previous() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await _drawing.SetTechnicalRequirementsAsync("1. Первая редакция."); + await _drawing.SetTechnicalRequirementsAsync("1. Вторая редакция.\n2. Ещё пункт."); + var readBack = await _drawing.ReadTechnicalRequirementsAsync(); + + Assert.Contains("Вторая редакция", readBack); + Assert.DoesNotContain("Первая редакция", readBack); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Empty_text_throws() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await Assert.ThrowsAsync(() => + _drawing.SetTechnicalRequirementsAsync(" ")); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Active_document_not_drawing_throws() + { + await _docs.CreateAsync(KompasDocumentType.Part); // деталь, не чертёж + try + { + await Assert.ThrowsAsync(() => + _drawing.SetTechnicalRequirementsAsync("1. Требование.")); + } + finally { await _docs.CloseAsync(save: false); } + } +} diff --git a/tests/Kompas.Mcp.Tests/Integration/DrawingTextTests.cs b/tests/Kompas.Mcp.Tests/Integration/DrawingTextTests.cs new file mode 100644 index 0000000..195cf8d --- /dev/null +++ b/tests/Kompas.Mcp.Tests/Integration/DrawingTextTests.cs @@ -0,0 +1,115 @@ +using Kompas.Mcp.Core.Documents; +using Kompas.Mcp.Core.Drawings; +using Kompas.Mcp.Core.Modeling; + +namespace Kompas.Mcp.Tests.Integration; + +/// Интеграция: свободная текстовая надпись на виде (API7 IDrawingContainer.DrawingTexts + IText). +[Trait("Category", "Integration")] +[Collection(KompasCollection.Name)] +public sealed class DrawingTextTests : IntegrationTestBase +{ + private readonly DocumentService _docs; + private readonly PartModeler _modeler; + private readonly DrawingService _drawing; + + public DrawingTextTests(KompasFixture fx) : base(fx) + { + _docs = new DocumentService(fx.Session, fx.Dispatcher); + _modeler = new PartModeler(fx.Session, fx.Dispatcher); + _drawing = new DrawingService(fx.Session, fx.Dispatcher); + } + + private async Task BuildAndSaveBoxAsync() + { + var path = TestPaths.NewFile(".m3d"); + await _docs.CreateAsync(KompasDocumentType.Part); + try + { + var s = await _modeler.OpenSketchAsync(BasePlane.XOY); + await _modeler.AddRectangleAsync(s, 0, 0, 40, 30); + await _modeler.CloseSketchAsync(s); + await _modeler.ExtrudeAsync(s, depth: 20); + await _modeler.RebuildAsync(); + await _docs.SaveAsAsync(path); + } + finally { await _docs.CloseAsync(save: false); } + return path; + } + + [Fact] + public async Task Text_is_placed_and_targets_view() + { + var partFile = await BuildAndSaveBoxAsync(); + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + var views = await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150); + var target = views.ViewNumbers[0]; + + var before = await _drawing.GetViewTextCountAsync(target); + var r = await _drawing.AddTextAsync(target, x: 30, y: 45, text: "Образец надписи", angleDeg: 0); + var after = await _drawing.GetViewTextCountAsync(target); + + Assert.Equal(target, r.ViewNumber); + Assert.Equal("Образец надписи", r.Value); // read-back из COM + Assert.Equal(before + 1, after); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Multiline_text_round_trips() + { + var partFile = await BuildAndSaveBoxAsync(); + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150); + var r = await _drawing.AddTextAsync(0, x: 10, y: 10, text: "Строка один\nСтрока два", angleDeg: 0); + Assert.Contains("Строка один", r.Value); + Assert.Contains("Строка два", r.Value); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Empty_text_throws() + { + var partFile = await BuildAndSaveBoxAsync(); + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150); + await Assert.ThrowsAsync(() => + _drawing.AddTextAsync(0, x: 10, y: 10, text: " ", angleDeg: 0)); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task No_views_throws() + { + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await Assert.ThrowsAsync(() => + _drawing.AddTextAsync(0, x: 0, y: 0, text: "Текст", angleDeg: 0)); + } + finally { await _docs.CloseAsync(save: false); } + } + + [Fact] + public async Task Unknown_view_number_throws() + { + var partFile = await BuildAndSaveBoxAsync(); + await _docs.CreateAsync(KompasDocumentType.Drawing); + try + { + await _drawing.CreateStandardViewsAsync(partFile, 1.0, 100, 150); + await Assert.ThrowsAsync(() => + _drawing.AddTextAsync(999, x: 0, y: 0, text: "Текст", angleDeg: 0)); + } + finally { await _docs.CloseAsync(save: false); } + } +} diff --git a/tests/Kompas.Mcp.Tests/RoughSignTypesTests.cs b/tests/Kompas.Mcp.Tests/RoughSignTypesTests.cs new file mode 100644 index 0000000..1273cae --- /dev/null +++ b/tests/Kompas.Mcp.Tests/RoughSignTypesTests.cs @@ -0,0 +1,29 @@ +using Kompas.Mcp.Core.Drawings; + +namespace Kompas.Mcp.Tests; + +[Trait("Category", "Unit")] +public sealed class RoughSignTypesTests +{ + [Theory] + [InlineData("delete", RoughSignType.DeleteMaterial)] + [InlineData("without", RoughSignType.WithoutDeleteMaterial)] + [InlineData("none", RoughSignType.NoProcessing)] + [InlineData(" DELETE ", RoughSignType.DeleteMaterial)] + [InlineData("с удалением", RoughSignType.DeleteMaterial)] + [InlineData("без удаления", RoughSignType.WithoutDeleteMaterial)] + [InlineData("без указания", RoughSignType.NoProcessing)] + public void Parse_maps_known(string value, RoughSignType expected) + => Assert.Equal(expected, RoughSignTypes.Parse(value)); + + [Fact] + public void Parse_throws_on_unknown() + => Assert.Throws(() => RoughSignTypes.Parse("polished")); + + [Fact] + public void Parse_throws_on_null() + => Assert.Throws(() => RoughSignTypes.Parse(null!)); + + // ToKompas (→ ksRoughSignEnum) намеренно НЕ покрыт unit-тестом: тестовый проект не ссылается на + // Kompas6Constants (граница проекта, как у AngleDimensionTypes/DimensionOrientations). +} From d8edb18f06869beb5e5baf1f8ac7ca01f747c507 Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 21:22:35 +0300 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20=D1=82=D0=B5=D0=BA=D1=81=D1=82?= =?UTF-8?q?=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=BE=D0=B1=D0=BE=D0=B7=D0=BD=D0=B0?= =?UTF-8?q?=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D0=B5=D1=80=D1=82=D0=B5?= =?UTF-8?q?=D0=B6=D0=B0=20=E2=80=94=20README,=20ARCHITECTURE,=20OPEN=5FQUE?= =?UTF-8?q?STIONS,=20presentation,=20CLAUDE.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 81 инструментов, 267 тестов. 2D-чертёж: добавлены шероховатость, свободный текст, технические требования (инкремент 6). Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 4 ++-- README.md | 6 +++--- docs/ARCHITECTURE.md | 13 ++++++++----- docs/OPEN_QUESTIONS.md | 13 ++++++++++++- docs/presentation.html | 15 ++++++++------- 5 files changed, 33 insertions(+), 18 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 758eccf..4ee08a4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,7 +25,7 @@ The base is committed to the repo (canonical) — no regeneration step. It cover **v1 + v2 + STEP/assembly + direct B-rep edit + structural model inspection implemented and working** (full sketch→feature→inspect→STEP round-trip + move_face + describe_model validated end-to-end). Stack: **.NET 8 (`net8.0-windows`, x64), C#**, MCP via the official `ModelContextProtocol` SDK over **stdio**. -**78 MCP tools, 241 tests green (150 unit + 91 integration).** v2 added: sketch-on-face (by point and by index), revolve (boss/cut + sketch axis), fillet/chamfer (edge-by-point and by index), and Query tools `get_part_info` (МЦХ), `get_bounding_box`, `list_faces`, `list_edges`. After v2: `import_step`, `export_step` (`ConversionService`, `ConversionTools`), `list_components` (assembly traversal via `TopPart → IParts7`). `move_face` (`FaceEditService`, `EditTools`) — direct B-rep face editing. After move_face: **structural model inspection** — `describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure` (`ModelInspectionService`, `InspectionTools`). `describe_model` is the preferred first call over `model_snapshot` (no token cost for image context; gives feature tree, bodies, variables, topology summary, МЦХ). Package A «richer sketches»: 7 new sketch primitives — `sketch_add_arc`, `sketch_add_arc_3points`, `sketch_add_ellipse`, `sketch_add_polyline`, `sketch_add_polygon`, `sketch_add_spline`, `sketch_add_point`. `PartModeler` refactored into partial classes: `PartModeler.cs` (core), `PartModeler.Sketch.cs` (2D primitives), `PartModeler.Features.cs` (extrude/revolve/fillet/chamfer). Static `SketchGeometry` class in `Core/Modeling`. Package B «forming ops» complete: **`shell`** (оболочка, `o3d_shellOperation=43`) + **`rib`** (ребро жёсткости, `o3d_ribOperation=44`) + **`sweep`** (кинематическая операция, `o3d_baseEvolution=45`) + **`loft`** (по сечениям, `o3d_baseLoft=30`). Auxiliary geometry (start of package E): **`sketch_create_on_offset_plane`** (смещённая плоскость, `o3d_planeOffset=14`) — unlocked `loft`. Additional Edit tools: **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`**. Package C «patterns & mirror» complete: **`linear_pattern`** (линейный массив, `o3d_meshCopy=35`) + **`circular_pattern`** (круговой массив, `o3d_circularCopy=36`) + **`mirror_operation`** (зеркальная копия операций, `o3d_mirrorOperation=48`) + **`mirror_body`** (зеркало тела, `o3d_mirrorAllOperation=49`). **`hole`** (`HoleService`, `FeatureTools`) — цилиндрическое отверстие (сквозное или глухое) через **API7** (`IModelContainer`/`IHole3D`/`IHoleDisposal`); первая формообразующая операция на API7 (прецедент ранее только у `move_face`). **`hole_counterbore`** — отверстие с цековкой (`ksHTCounterbore`, `ISpotfacingHoleParameters`). **`hole_countersink`** — отверстие с зенковкой (`ksHTCountersinking`, `ICountersinkHoleParameters`). **`hole_conic`** — коническое отверстие (`ksHTConic`, `IConicHoleParameters`: `ConicType=ksCNAngle`, `ConicAngle`); завершает набор типов отверстий. `HoleCore` рефакторен: принимает `ksHoleTypeEnum holeType` + `Action configure` (настройка `HoleParameters` после установки `HoleType`, т.к. параметрический подынтерфейс недоступен до фиксации типа). Базовый `hole` = `ksHTBase` + `configure=null`. **`draft`** (уклон, `o3d_incline=42`) — наклон граней на угол относительно нейтральной координатной плоскости; реализован через **API5** `ksInclineDefinition` (операция называется Incline в API5, не Draft). Package D «parametrics» started: **`create_variable`**, **`set_variable`**, **`delete_variable`** (`VariableService`, `VariableTools`) — CRUD переменных модели через API5. `list_variables` исправлен (читает `ksPart.GetFeature().VariableCollection`, а не `ksPart.VariableCollection()`). **Ограничение:** переменная управляет геометрией только в параметрической модели (где размеры эскиза связаны с именем переменной); наши эскизы строятся литеральными координатами → `set_variable` хранит/вычисляет значение, но геометрию не меняет. Связь эскизных размеров с переменными (API2D) — не реализована. **Assembly class:** **`assembly_add_component`** (`AssemblyService`, `AssemblyTools`, namespace `Kompas.Mcp.Core.Assemblies`) — вставка компонента (.m3d/.a3d) из файла в активную сборку с заданием положения origin (мм, мировая СК сборки); возвращает индекс и имя вставленного компонента. **`assembly_add_mate`** — наложить сопряжение между гранями двух компонентов активной сборки, выбранными по мировым точкам; `mateType`: `coincidence` (грани заподлицо) | `distance` (зазор `value` мм, `value>0`); решатель позиционирует компоненты; возвращает статус (`valid`). Подтверждено вживую: `coincidence` (ширина сборки 120→40 мм), `distance(30)` (→70 мм). **2D-чертёж (веха, инкремент 3):** **`drawing_create_standard_views`** (`DrawingService`, `DrawingTools`, namespace `Kompas.Mcp.Core.Drawings`) — создать стандартные ассоциативные виды (спереди/сверху/слева) сохранённой 3D-модели (.m3d/.a3d) на активном чертеже; возвращает число созданных видов (3) и их номера (`ViewNumbers`). **`drawing_fill_title_block`** — заполнить графы основной надписи (штампа) активного чертежа: `designation` (обозначение, графа 2), `name` (наименование изделия, графа 1), `material` (материал, графа 3); передаются только нужные поля (null/пусто пропускается, нужно хотя бы одно); возвращает число заполненных граф. **`drawing_add_linear_dimension`** — поставить линейный размер на виде активного чертежа: точки (x1,y1)-(x2,y2) в локальной СК вида (мм), положение размерной линии (x3,y3), `orientation` (horizontal|vertical|parallel), `viewNumber` (0=первый вид); значение измеряется автоматически; возвращает значение и номер вида. **`drawing_add_diametral_dimension`** — поставить диаметральный размер (Ø) окружности: центр (xc,yc), `radius`, `angle` (направление выноски, градусы), `viewNumber`; значение = 2·radius, измеряется автоматически; возвращает диаметр и номер вида. **2D-чертёж (инкремент 5, базовое семейство размеров завершено):** **`drawing_add_radial_dimension`** — радиальный размер (R) окружности/дуги на виде: центр (xc,yc), `radius`, `angle` (направление выноски, °), `viewNumber`; значение измеряется автоматически и = **РАДИУСУ** (не диаметру — вопреки справке SDK); возвращает радиус и номер вида. **`drawing_add_angular_dimension`** — угловой размер между лучами (xc,yc)→(x1,y1) и (xc,yc)→(x2,y2) на виде: (x3,y3) — положение размерной дуги (задаёт её радиус), `angleType` (`min`|`max`|`more`) выбирает измеряемый угол, `viewNumber`; значение (градусы) измеряется автоматически; возвращает угол (°) и номер вида. +**81 MCP tools, 267 tests green (163 unit + 104 integration).** v2 added: sketch-on-face (by point and by index), revolve (boss/cut + sketch axis), fillet/chamfer (edge-by-point and by index), and Query tools `get_part_info` (МЦХ), `get_bounding_box`, `list_faces`, `list_edges`. After v2: `import_step`, `export_step` (`ConversionService`, `ConversionTools`), `list_components` (assembly traversal via `TopPart → IParts7`). `move_face` (`FaceEditService`, `EditTools`) — direct B-rep face editing. After move_face: **structural model inspection** — `describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure` (`ModelInspectionService`, `InspectionTools`). `describe_model` is the preferred first call over `model_snapshot` (no token cost for image context; gives feature tree, bodies, variables, topology summary, МЦХ). Package A «richer sketches»: 7 new sketch primitives — `sketch_add_arc`, `sketch_add_arc_3points`, `sketch_add_ellipse`, `sketch_add_polyline`, `sketch_add_polygon`, `sketch_add_spline`, `sketch_add_point`. `PartModeler` refactored into partial classes: `PartModeler.cs` (core), `PartModeler.Sketch.cs` (2D primitives), `PartModeler.Features.cs` (extrude/revolve/fillet/chamfer). Static `SketchGeometry` class in `Core/Modeling`. Package B «forming ops» complete: **`shell`** (оболочка, `o3d_shellOperation=43`) + **`rib`** (ребро жёсткости, `o3d_ribOperation=44`) + **`sweep`** (кинематическая операция, `o3d_baseEvolution=45`) + **`loft`** (по сечениям, `o3d_baseLoft=30`). Auxiliary geometry (start of package E): **`sketch_create_on_offset_plane`** (смещённая плоскость, `o3d_planeOffset=14`) — unlocked `loft`. Additional Edit tools: **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`**. Package C «patterns & mirror» complete: **`linear_pattern`** (линейный массив, `o3d_meshCopy=35`) + **`circular_pattern`** (круговой массив, `o3d_circularCopy=36`) + **`mirror_operation`** (зеркальная копия операций, `o3d_mirrorOperation=48`) + **`mirror_body`** (зеркало тела, `o3d_mirrorAllOperation=49`). **`hole`** (`HoleService`, `FeatureTools`) — цилиндрическое отверстие (сквозное или глухое) через **API7** (`IModelContainer`/`IHole3D`/`IHoleDisposal`); первая формообразующая операция на API7 (прецедент ранее только у `move_face`). **`hole_counterbore`** — отверстие с цековкой (`ksHTCounterbore`, `ISpotfacingHoleParameters`). **`hole_countersink`** — отверстие с зенковкой (`ksHTCountersinking`, `ICountersinkHoleParameters`). **`hole_conic`** — коническое отверстие (`ksHTConic`, `IConicHoleParameters`: `ConicType=ksCNAngle`, `ConicAngle`); завершает набор типов отверстий. `HoleCore` рефакторен: принимает `ksHoleTypeEnum holeType` + `Action configure` (настройка `HoleParameters` после установки `HoleType`, т.к. параметрический подынтерфейс недоступен до фиксации типа). Базовый `hole` = `ksHTBase` + `configure=null`. **`draft`** (уклон, `o3d_incline=42`) — наклон граней на угол относительно нейтральной координатной плоскости; реализован через **API5** `ksInclineDefinition` (операция называется Incline в API5, не Draft). Package D «parametrics» started: **`create_variable`**, **`set_variable`**, **`delete_variable`** (`VariableService`, `VariableTools`) — CRUD переменных модели через API5. `list_variables` исправлен (читает `ksPart.GetFeature().VariableCollection`, а не `ksPart.VariableCollection()`). **Ограничение:** переменная управляет геометрией только в параметрической модели (где размеры эскиза связаны с именем переменной); наши эскизы строятся литеральными координатами → `set_variable` хранит/вычисляет значение, но геометрию не меняет. Связь эскизных размеров с переменными (API2D) — не реализована. **Assembly class:** **`assembly_add_component`** (`AssemblyService`, `AssemblyTools`, namespace `Kompas.Mcp.Core.Assemblies`) — вставка компонента (.m3d/.a3d) из файла в активную сборку с заданием положения origin (мм, мировая СК сборки); возвращает индекс и имя вставленного компонента. **`assembly_add_mate`** — наложить сопряжение между гранями двух компонентов активной сборки, выбранными по мировым точкам; `mateType`: `coincidence` (грани заподлицо) | `distance` (зазор `value` мм, `value>0`); решатель позиционирует компоненты; возвращает статус (`valid`). Подтверждено вживую: `coincidence` (ширина сборки 120→40 мм), `distance(30)` (→70 мм). **2D-чертёж (веха, инкремент 3):** **`drawing_create_standard_views`** (`DrawingService`, `DrawingTools`, namespace `Kompas.Mcp.Core.Drawings`) — создать стандартные ассоциативные виды (спереди/сверху/слева) сохранённой 3D-модели (.m3d/.a3d) на активном чертеже; возвращает число созданных видов (3) и их номера (`ViewNumbers`). **`drawing_fill_title_block`** — заполнить графы основной надписи (штампа) активного чертежа: `designation` (обозначение, графа 2), `name` (наименование изделия, графа 1), `material` (материал, графа 3); передаются только нужные поля (null/пусто пропускается, нужно хотя бы одно); возвращает число заполненных граф. **`drawing_add_linear_dimension`** — поставить линейный размер на виде активного чертежа: точки (x1,y1)-(x2,y2) в локальной СК вида (мм), положение размерной линии (x3,y3), `orientation` (horizontal|vertical|parallel), `viewNumber` (0=первый вид); значение измеряется автоматически; возвращает значение и номер вида. **`drawing_add_diametral_dimension`** — поставить диаметральный размер (Ø) окружности: центр (xc,yc), `radius`, `angle` (направление выноски, градусы), `viewNumber`; значение = 2·radius, измеряется автоматически; возвращает диаметр и номер вида. **2D-чертёж (инкремент 5, базовое семейство размеров завершено):** **`drawing_add_radial_dimension`** — радиальный размер (R) окружности/дуги на виде: центр (xc,yc), `radius`, `angle` (направление выноски, °), `viewNumber`; значение измеряется автоматически и = **РАДИУСУ** (не диаметру — вопреки справке SDK); возвращает радиус и номер вида. **`drawing_add_angular_dimension`** — угловой размер между лучами (xc,yc)→(x1,y1) и (xc,yc)→(x2,y2) на виде: (x3,y3) — положение размерной дуги (задаёт её радиус), `angleType` (`min`|`max`|`more`) выбирает измеряемый угол, `viewNumber`; значение (градусы) измеряется автоматически; возвращает угол (°) и номер вида. **2D-чертёж (инкремент 6, текстовые обозначения):** **`drawing_add_rough`** — знак шероховатости на виде: `x,y` (положение, ЛСК вида, мм), `value` (текст параметра, напр. "Ra 1.6"; пусто = без значения), `signType` (`delete`|`without`|`none`), `angle` (наклон оси, °), `viewNumber`; возвращает значение (read-back) и номер вида. **`drawing_add_text`** — свободная текстовая надпись на виде стилем по умолчанию: `x,y` (точка привязки), `text` (`\n` — многострочно), `angle`, `viewNumber`; возвращает текст (read-back) и номер вида. **`drawing_set_technical_requirements`** — технические требования чертежа (единый блок над штампом, уровень документа): `text` (строки через `\n`); перезаписывает прежние; возвращает число строк. See [`README.md`](README.md) and [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md); design decisions/caveats in [`docs/OPEN_QUESTIONS.md`](docs/OPEN_QUESTIONS.md). @@ -57,7 +57,7 @@ Key implementation facts (don't relearn): - **Structural model inspection** (`ModelInspectionService`, `InspectionTools`): `describe_model` — one-call structural "passport" (bounding box + МЦХ + bodies + topology summary + feature tree + variables); preferred over snapshot. `list_features` — feature tree with params (depth/radius/legs). `list_bodies` — list solid/surface bodies with face count. `list_variables` — model variables (name/expression/value, external/info flags); reads via `ksPart.GetFeature().VariableCollection` (all variables, including user-created) with fallback to `ksPart.VariableCollection()` (external-only — bug was fixed). `describe_face` — drill-down by index (type, area, normal, radius, edge count). `describe_edge` — drill-down by index (type, length, adjacent faces, vertices). `measure` — distance/angle between two objects (face|edge|vertex by index, unit `ST_MIX_MM`). - **Variable management (package D start, `VariableService`, `VariableTools`)**: `create_variable(name, value, note?, external?)` — creates a model variable; `set_variable(name, expression)` — sets expression (constant `"30"` or formula `"width*2+5"`); `delete_variable(name)` — deletes (fails if dependents exist). **Key API facts (don't relearn):** variable creation MUST use `ksPart.GetFeature().VariableCollection` (property on root ksFeature) — NOT `ksPart.VariableCollection()` (returns external-only). Expression is the leading field; value is derived. Changes applied via `ksPart.RebuildModel()` (return checked); after rebuild the RCW variable is stale → re-read via fresh collection (`ReadValueFresh`). Dependent variables recalculate automatically. Deletion fails if dependents exist (RemoveVariable returns FALSE). **Geometry limitation:** variables control geometry only in a parametric model where sketch dimensions are linked to variable names; our sketches are built with literal coordinates → `set_variable` stores/computes the value but does NOT change geometry. Linking sketch dimensions to variables (parametric sketches via API2D) is not yet implemented. - **Feature tree API** (don't relearn): read via API5 `ksPart.GetFeature()` → `(ksFeature).SubFeatureCollection(true,false)` → `ksFeatureCollection`. Cast `(ksFeature)part` does NOT work (RCW QI returns null) — must use `GetFeature()`. `ksFeature.type` returns only coarse `o3d_entity` and does NOT distinguish operations; precise type and params come from `ksFeature.GetObject()` → `ksEntity.GetDefinition()` and matching definition type (`ksBossExtrusionDefinition.GetSideParam`, `ksFilletDefinition.radius`, `ksChamferDefinition.GetChamferParam`, …). Node name ("Элемент выдавливания:1", "Скругление:1") is localized by КОМПАС itself. -- **STEP import/export, `list_components`, `move_face`, `split_solid_by_plane`, `move_body`, `boolean_union`, full inspection layer, richer sketch primitives (package A), `shell`, `rib`, `sweep`, `loft` (package B complete), `sketch_create_on_offset_plane` (package E start), `linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body` (package C complete), `hole`, `hole_counterbore`, `hole_countersink`, `hole_conic` (all API7 via `HoleService`; `hole_conic` uses `ksHTConic`/`IConicHoleParameters`), `draft` (API5 `ksInclineDefinition`), `create_variable`/`set_variable`/`delete_variable` (package D start), `assembly_add_component`, `assembly_add_mate` (both API7, `AssemblyService`; mate types `coincidence`/`distance` verified), `drawing_create_standard_views` (API7, `DrawingService`, namespace `Kompas.Mcp.Core.Drawings`), `drawing_fill_title_block` (API7, `DrawingService`; заполнение основной надписи/штампа через `IStamp`), `drawing_add_linear_dimension` (API7, `DrawingService`; линейный размер на виде через `ISymbols2DContainer`/`LineDimensions.Add`/`ILineDimension`; координаты в локальной СК вида), `drawing_add_diametral_dimension` (API7, `DrawingService`; диаметральный размер через `ISymbols2DContainer.DiametralDimensions.Add`/`IDiametralDimension`; `Xc/Yc/Radius` в локальной СК вида, `Angle` в радианах, `NominalValue`=2·Radius), `drawing_add_radial_dimension` (API7, `DrawingService`; радиальный размер R через `ISymbols2DContainer.RadialDimensions.Add`/`IRadialDimension`; `Xc/Yc/Radius`+`Angle` (рад), `DimensionType=true`; **`NominalValue`=Radius, НЕ диаметр** — вопреки справке SDK, подтверждено спайком), `drawing_add_angular_dimension` (API7, `DrawingService`; угловой размер через `ISymbols2DContainer.AngleDimensions.Add(ksDrADimension=10)`/`IAngleDimension`; вершина `Xc/Yc` + точки сторон `X1/Y1`,`X2/Y2` + положение дуги `X3/Y3` (локальная СК вида); измеряемый угол выбирает `DimensionType`=`ksAngleDimTypeEnum` через enum `AngleDimensionType{Min,Max,More}`+`AngleDimensionTypes.Parse/ToKompas`; на лучах 0°/45° → min=45°/max=135°(супплемент)/more=315°(рефлексный); `NominalValue` в градусах; `(x3,y3)` лишь позиционирует дугу, угол НЕ выбирает) are done.** Базовое семейство размеров 2D-чертежа завершено (линейный, диаметральный, радиальный, угловой). Not yet done: parametric sketches — **investigated, unavailable via COM API** (`ksCDimWithVariable` cannot be constructed from external automation; see `docs/superpowers/specs/2026-05-27-parametric-sketch-findings.md`); 2D-чертёж: ассоциативная привязка размеров к геометрии (`BaseObject`/`BaseObject1/2`), рамка/формат листа, текстовые обозначения (шероховатость `Roughs`, допуски формы `Tolerances`, выноски `Leaders`, тех. требования) — далее; additional mate types (parallel/perpendicular/concentric/angle/tangency); package E continuation (axis, angle plane). Known caveat: boss/cut direction on a selected face depends on face-normal orientation (`forward` may need flipping — agent picks via snapshot or `describe_face` normal). See `docs/OPEN_QUESTIONS.md` → «Ревью v2». +- **STEP import/export, `list_components`, `move_face`, `split_solid_by_plane`, `move_body`, `boolean_union`, full inspection layer, richer sketch primitives (package A), `shell`, `rib`, `sweep`, `loft` (package B complete), `sketch_create_on_offset_plane` (package E start), `linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body` (package C complete), `hole`, `hole_counterbore`, `hole_countersink`, `hole_conic` (all API7 via `HoleService`; `hole_conic` uses `ksHTConic`/`IConicHoleParameters`), `draft` (API5 `ksInclineDefinition`), `create_variable`/`set_variable`/`delete_variable` (package D start), `assembly_add_component`, `assembly_add_mate` (both API7, `AssemblyService`; mate types `coincidence`/`distance` verified), `drawing_create_standard_views` (API7, `DrawingService`, namespace `Kompas.Mcp.Core.Drawings`), `drawing_fill_title_block` (API7, `DrawingService`; заполнение основной надписи/штампа через `IStamp`), `drawing_add_linear_dimension` (API7, `DrawingService`; линейный размер на виде через `ISymbols2DContainer`/`LineDimensions.Add`/`ILineDimension`; координаты в локальной СК вида), `drawing_add_diametral_dimension` (API7, `DrawingService`; диаметральный размер через `ISymbols2DContainer.DiametralDimensions.Add`/`IDiametralDimension`; `Xc/Yc/Radius` в локальной СК вида, `Angle` в радианах, `NominalValue`=2·Radius), `drawing_add_radial_dimension` (API7, `DrawingService`; радиальный размер R через `ISymbols2DContainer.RadialDimensions.Add`/`IRadialDimension`; `Xc/Yc/Radius`+`Angle` (рад), `DimensionType=true`; **`NominalValue`=Radius, НЕ диаметр** — вопреки справке SDK, подтверждено спайком), `drawing_add_angular_dimension` (API7, `DrawingService`; угловой размер через `ISymbols2DContainer.AngleDimensions.Add(ksDrADimension=10)`/`IAngleDimension`; вершина `Xc/Yc` + точки сторон `X1/Y1`,`X2/Y2` + положение дуги `X3/Y3` (локальная СК вида); измеряемый угол выбирает `DimensionType`=`ksAngleDimTypeEnum` через enum `AngleDimensionType{Min,Max,More}`+`AngleDimensionTypes.Parse/ToKompas`; на лучах 0°/45° → min=45°/max=135°(супплемент)/more=315°(рефлексный); `NominalValue` в градусах; `(x3,y3)` лишь позиционирует дугу, угол НЕ выбирает), `drawing_add_rough` (API7, `DrawingService`; знак шероховатости через `ISymbols2DContainer.Roughs.Add()`/`IRough` (`BranchX0/Y0`,`Angle`) + `(IRoughParams)rough` QI: `SignType`=`ksRoughSignEnum` через enum `RoughSignType{NoProcessing,DeleteMaterial,WithoutDeleteMaterial}`+`RoughSignTypes.Parse/ToKompas`, значение Ra/Rz — `RoughParamText.Str`; возвращает значение read-back), `drawing_add_text` (API7, `DrawingService`; свободная надпись через `(IDrawingContainer)view.DrawingTexts.Add()`/`IDrawingText` (`X/Y/Angle`) + `(IText)dt.Str`=текст; **текст в `IDrawingContainer`, НЕ в `ISymbols2DContainer`, и НЕ в `IView.ObjectCount`** — счёт по `DrawingTexts.Count`; `Height` НЕ задаём — это высота блока, не шрифт), `drawing_set_technical_requirements` (API7, `DrawingService`; тех. требования уровня ДОКУМЕНТА через `(IDrawingDocument)doc.TechnicalDemand`/`ITechnicalDemand`: `td.Text.Str`=текст → `td.Update()`; `IsCreated` False→True при первом задании; перезаписывает; многострочно `\n`) are done.** `DrawingAnnotationResult{Value(read-back),ViewNumber}` — общий результат rough/text. Базовое семейство размеров 2D-чертежа завершено (линейный, диаметральный, радиальный, угловой); текстовые обозначения (шероховатость, надпись, тех. требования) завершены. Not yet done: parametric sketches — **investigated, unavailable via COM API** (`ksCDimWithVariable` cannot be constructed from external automation; see `docs/superpowers/specs/2026-05-27-parametric-sketch-findings.md`); 2D-чертёж: ассоциативная привязка размеров/шероховатости к геометрии (`BaseObject`/`BaseObject1/2`), рамка/формат листа, выноски (`Leaders`), обозначения баз (`Bases`), допуски формы (`Tolerances`) — далее; additional mate types (parallel/perpendicular/concentric/angle/tangency); package E continuation (axis, angle plane). Known caveat: boss/cut direction on a selected face depends on face-normal orientation (`forward` may need flipping — agent picks via snapshot or `describe_face` normal). See `docs/OPEN_QUESTIONS.md` → «Ревью v2». - **"STEP import without history"** detected structurally: `bodyCount > 0 && no formative features && features.Count <= bodyCount+1` (only origin + body). STEP with edits (move_face: "Смещённая плоскость", "Разрезать", "Переместить грани", "Булева операция") — that already has history. - **Topology/measure API**: `ksFaceDefinition.EdgeCollection` / `GetCylinderParam` / `GetSurface().GetNormal` + `normalOrientation`; `ksEdgeDefinition.GetAdjacentFace(bool)` / `GetVertex(bool)` → `ksVertexDefinition.GetPoint`; bodies via `ksPart.BodyCollection()` → `ksBody` (`IsSolid` / `FaceCollection`); all variables via `ksPart.GetFeature().VariableCollection` → `ksVariable` (external-only: `ksPart.VariableCollection()` — do NOT use for reading all variables); measurements via `ksPart.GetMeasurer()` → `ksMeasurer` (`SetObject1/2`, `unit=ST_MIX_MM`, `Calc`, `distance`/`MinDistance`/`angle` in degrees / `IsAngleValid`). - **STEP import COM pattern** (verified): `IApplication.get_Converter((object)(int)ksConverterFromSTEP=-3)` (pass format code, not DLL path) → `IConverter.ConverterParameters(cmd)` → set `IAdditionConvertParameters.Format=ksConverterFromSTEP` → `IKompasDocument3D1.ConvertFromAdditionFormat(path, prm)`. Export: `ConvertToAdditionFormat` with format codes for AP203/AP214/AP242. Param co-classes (AdditionConvertParameters etc.) are NOT CoCreatable — only via converter factories. Assembly traversal: `IKompasDocument3D.TopPart → IPart7.Parts (IParts7)`. Extract component: `prm.NeedCreateComponentsFiles=true` (writes .m3d files next to STEP) + `IPart7.OpenSourceDocument`. diff --git a/README.md b/README.md index 70f7486..306aeb0 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ src/Kompas.Mcp.Host/bin/Release/net8.0-windows/kompas-mcp.exe } ``` -## Инструменты (78 инструментов) +## Инструменты (81 инструмент) | Группа | Инструменты | |---|---| @@ -54,7 +54,7 @@ src/Kompas.Mcp.Host/bin/Release/net8.0-windows/kompas-mcp.exe | Variables | `create_variable`, `set_variable`, `delete_variable` | | Conversion | `import_step`, `export_step` | | Assembly | `assembly_add_component`, `assembly_add_mate` | -| Drawing | `drawing_create_standard_views`, `drawing_fill_title_block`, `drawing_add_linear_dimension`, `drawing_add_diametral_dimension`, `drawing_add_radial_dimension`, `drawing_add_angular_dimension` | +| Drawing | `drawing_create_standard_views`, `drawing_fill_title_block`, `drawing_add_linear_dimension`, `drawing_add_diametral_dimension`, `drawing_add_radial_dimension`, `drawing_add_angular_dimension`, `drawing_add_rough`, `drawing_add_text`, `drawing_set_technical_requirements` | | Validation | `validate_part` | ### Типовой сценарий @@ -73,7 +73,7 @@ src/Kompas.Mcp.Host/bin/Release/net8.0-windows/kompas-mcp.exe ``` src/Kompas.Mcp.Core/ COM-слой: STA-диспетчер, подключение, документы, эскизы/операции, конвертация, снимок, инспекция модели src/Kompas.Mcp.Host/ MCP-сервер (stdio) + определения инструментов -tests/Kompas.Mcp.Tests/ 241 тест: unit + integration (integration требуют КОМПАС) +tests/Kompas.Mcp.Tests/ 267 тестов: unit + integration (integration требуют КОМПАС) libs/kompas-interop/ вендорские interop-сборки КОМПАС (из SDK Samples/Common) docs/ архитектура, план, презентация, MD-база знаний SDK (Kompas3D_SDK/) usecases/ полигон обкатки подходов (в .gitignore); приёмы поднимаются в навык kompas-3d diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 6fb576e..88639b0 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,6 +1,6 @@ # Архитектура MCP-сервера КОМПАС-3D (предлагаемый вариант) -> Статус: **реализовано и работает** (v1+v2+STEP/assembly+direct-edit+inspection+package-A «богатые эскизы»+package-B «shell+rib+sweep+loft»+package-C «массивы и зеркало»+package-D start «переменные»+package-E «offset plane»+`hole`+`hole_counterbore`+`hole_countersink`+`hole_conic`+`draft`+`assembly_add_component`+`assembly_add_mate`+`drawing_create_standard_views`+`drawing_fill_title_block`+`drawing_add_linear_dimension`+`drawing_add_diametral_dimension`+`drawing_add_radial_dimension`+`drawing_add_angular_dimension` (веха «2D-чертёж», инкремент 5)). Актуализировано по коду. +> Статус: **реализовано и работает** (v1+v2+STEP/assembly+direct-edit+inspection+package-A «богатые эскизы»+package-B «shell+rib+sweep+loft»+package-C «массивы и зеркало»+package-D start «переменные»+package-E «offset plane»+`hole`+`hole_counterbore`+`hole_countersink`+`hole_conic`+`draft`+`assembly_add_component`+`assembly_add_mate`+`drawing_create_standard_views`+`drawing_fill_title_block`+`drawing_add_linear_dimension`+`drawing_add_diametral_dimension`+`drawing_add_radial_dimension`+`drawing_add_angular_dimension`+`drawing_add_rough`+`drawing_add_text`+`drawing_set_technical_requirements` (веха «2D-чертёж», инкремент 6 — текстовые обозначения)). Актуализировано по коду. > Сопутствующий контекст по COM API КОМПАС — в [`../CLAUDE.md`](../CLAUDE.md). > Имена интерфейсов и перечислений сверены со справкой SDK по MD-базе знаний `docs/Kompas3D_SDK/` (субагент `kompas-sdk-research`). @@ -113,7 +113,7 @@ MCP client ──stdio──> Host (поток-пул, async) |---|---| | **Kompas.Mcp.Host** | Точка входа. Сборка MCP-сервера (stdio), DI (в т.ч. `ConversionService`), логи в stderr, старт и владение STA-потоком, graceful shutdown. Определения инструментов по категориям (System / Documents / Sketch / Features / Query / Conversion). **Тонкий слой**: валидация аргументов → постановка задачи на STA-поток → форматирование результата/ошибки в MCP-ответ. | | **Kompas.Mcp.Core** | COM-слой. Менеджер соединения, менеджер документов, построитель эскизов и операций, `ConversionService` (STEP импорт/экспорт), `QueryService` (МЦХ, грани, рёбра, компоненты), `ModelInspectionService` (дерево операций, тела, переменные, drill-down, измерения), `AssemblyService` (вставка компонентов в сборку, namespace `Kompas.Mcp.Core.Assemblies`), `DrawingService` (стандартные виды чертежа, namespace `Kompas.Mcp.Core.Drawings`), снимок. Все паттерны API5/API7 живут здесь. | -| **Kompas.Mcp.Tests** | Юнит (без COM) + интеграционные (требуют КОМПАС). 241 тест (150 unit + 91 integration). Все интеграционные классы наследуют `IntegrationTestBase` (`IAsyncLifetime`), который вызывает `DocumentService.CloseAllAsync` после каждого теста. | +| **Kompas.Mcp.Tests** | Юнит (без COM) + интеграционные (требуют КОМПАС). 267 тестов (163 unit + 104 integration). Все интеграционные классы наследуют `IntegrationTestBase` (`IAsyncLifetime`), который вызывает `DocumentService.CloseAllAsync` после каждого теста. | Принцип: **только `Core` знает про COM**. `Host`/Tools оперируют доменными DTO и вызывают `Core`; `Host` не содержит бизнес-логики. @@ -121,7 +121,7 @@ MCP client ──stdio──> Host (поток-пул, async) --- -## 5. Карта инструментов (78 инструментов) +## 5. Карта инструментов (81 инструмент) Сгруппированы вокруг центрального цикла «эскиз ↔ операция». Имена — `snake_case`. @@ -215,6 +215,9 @@ MCP client ──stdio──> Host (поток-пул, async) - `drawing_add_diametral_dimension(xc,yc,radius, angle, viewNumber)` — поставить диаметральный размер (Ø) окружности на виде активного чертежа. `xc,yc` — центр, `radius` — радиус (мм, локальная СК вида); `angle` — направление выноски (градусы → радианы через `DimensionAngles.ToRadians`); `viewNumber` — номер вида (0=первый). Значение (диаметр = 2·radius) измеряется автоматически. Реализовано: общий хелпер `RequireSymbols2DContainer(viewNumber)` (переиспользуется с линейным размером) → `DiametralDimensions.Add()` → `IDiametralDimension` (`Xc`, `Yc`, `Radius`, `Angle` в радианах, `AutoNominalValue=true`) → `Update()` → `Valid` → `((IDimensionText)dim).NominalValue`. Размер «свободный» (без `BaseObject`). Валидатор `DrawingValidation.RequirePositiveRadius`. `DimensionAngles.ToRadians` добавлен в `DimensionOrientation.cs`. - `drawing_add_radial_dimension(xc,yc,radius, angle, viewNumber)` — поставить радиальный размер (R) окружности/дуги на виде активного чертежа. `xc,yc` — центр, `radius` — радиус (мм, локальная СК вида); `angle` — направление выноски (°, по умолчанию 0); `viewNumber` — номер вида. Возвращаемое значение равно **радиусу** (не диаметру). Реализовано: `RequireSymbols2DContainer(viewNumber)` → `RadialDimensions.Add()` → `IRadialDimension` (`Xc`, `Yc`, `Radius`, `Angle` в радианах, `DimensionType=true`, `AutoNominalValue=true`) → `Update()` → `Valid` → `NominalValue`. Размер «свободный» (без `BaseObject`). Переиспользует `RequirePositiveRadius` и `DimensionAngles.ToRadians`. - `drawing_add_angular_dimension(xc,yc, x1,y1, x2,y2, x3,y3, angleType, viewNumber)` — поставить угловой размер между двумя сторонами на виде активного чертежа. `xc,yc` — вершина угла; `x1,y1` — точка на стороне 1; `x2,y2` — точка на стороне 2; `x3,y3` — положение размерной дуги (задаёт её радиус); `angleType` = `"min"` (острый) | `"max"` (тупой, 180°-min) | `"more"` (рефлексный >180°); `viewNumber` — номер вида. Значение в градусах измеряется автоматически. Реализовано: `RequireSymbols2DContainer(viewNumber)` → `AngleDimensions.Add(ksDrADimension)` → `IAngleDimension` (`Xc`, `Yc`, `X1`, `Y1`, `X2`, `Y2`, `X3`, `Y3`, `DimensionType=ksAngleDimTypeEnum`, `AutoNominalValue=true`) → `Update()` → `Valid` → `NominalValue`. Новый enum `AngleDimensionType {Min, Max, More}` + `AngleDimensionTypes.Parse/ToKompas` в `DimensionOrientation.cs`; 9 unit-тестов для маппинга. Размер «свободный» (без `BaseObject`). Валидаторы `RequireFiniteCoords` + `RequireDistinctPoints`. +- `drawing_add_rough(x,y, value?, signType, angle, viewNumber)` — поставить знак шероховатости на виде. `x,y` — положение знака в локальной СК вида (мм); `value` — текст параметра (напр. `"Ra 1.6"`; пусто = знак без значения); `signType`: `"delete"` (с удалением слоя материала) | `"without"` (без удаления) | `"none"` (без указания); `angle` — угол наклона оси знака (°, по умолч. 0); `viewNumber` — номер вида. Реализовано: `ISymbols2DContainer.Roughs.Add()` → `IRough` (`BranchX0/Y0/Angle`) → `(IRoughParams)rough` (`SignType=ksRoughSignEnum`, `RoughParamText.Str = value`) → `Update()` → `Valid`. Новый enum `RoughSignType {NoProcessing, DeleteMaterial, WithoutDeleteMaterial}` + `RoughSignTypes.Parse/ToKompas` в `Drawings/RoughSignType.cs`. Возвращает `DrawingAnnotationResult { Value, ViewNumber }`. +- `drawing_add_text(x,y, text, angle, viewNumber)` — свободная текстовая надпись на виде стилем по умолчанию. `x,y` — точка привязки (СК вида, мм); `text` — содержимое (`\n` — многострочно); `angle` — угол (°, по умолч. 0); `viewNumber` — номер вида. Реализовано: `(IDrawingContainer)view.DrawingTexts.Add()` → `IDrawingText` (`X/Y/Angle`) → `(IText)dt.Str = text` → `Update()` → `Valid`. ВАЖНО: текст живёт в `IDrawingContainer` (контейнер геометрии вида), НЕ в `ISymbols2DContainer`; попадание проверяется через `DrawingTexts.Count`. Возвращает `DrawingAnnotationResult { Value, ViewNumber }`. +- `drawing_set_technical_requirements(text)` — технические требования чертежа (единый текстовый блок, уровень документа, не вида). `text` — строки через `\n`. Реализовано: `(IDrawingDocument)doc.TechnicalDemand` → `td.Text.Str = text` → `td.Update()`. Перезаписывает прежние (не добавляет). Возвращает число строк. **Vision — визуальная обратная связь (fallback)** - `model_snapshot` — отрендерить активный 3D-документ в PNG и вернуть **как image-контент MCP**, @@ -349,14 +352,14 @@ dotnet build -c Release -r win-x64 # сборка ## 10. Дорожная карта -**Реализовано (v1+v2+STEP/assembly+direct-edit+inspection+package-A+package-B+package-C+package-D start+package-E start+hole+hole_counterbore+hole_countersink+hole_conic+draft+assembly_add_component+assembly_add_mate+drawing_create_standard_views+drawing_fill_title_block+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension):** документы, эскизы (полный набор 2D-примитивов: линия, окружность, дуга, дуга по 3 точкам, прямоугольник, эллипс, ломаная, правильный многоугольник, сплайн NURBS, точка), **вспомогательная геометрия (`sketch_create_on_offset_plane`)**, выдавливание/вырез, вращение, скругление/фаска, **оболочка (`shell`)**, **ребро жёсткости (`rib`)**, **кинематическая операция (`sweep`)**, **операция по сечениям (`loft`)**, **линейный/круговой массив и зеркало (`linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body`)**, **отверстие (`hole`, API7)**, **цековка (`hole_counterbore`, API7)**, **зенковка (`hole_countersink`, API7)**, **коническое отверстие (`hole_conic`, API7)**, **уклон (`draft`, API5 `ksInclineDefinition`)**, снимок; `get_part_info`, `get_bounding_box`, `list_faces`, `list_edges`; `import_step`, `export_step`, `list_components`; **`move_face`**, **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`** (прямое редактирование и булевы операции); **`describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure`** (структурный осмотр модели); **`create_variable`, `set_variable`, `delete_variable`** (управление переменными, package D start); **`assembly_add_component`** (вставка компонента в сборку, API7, `AssemblyService`); **`assembly_add_mate`** (сопряжения `coincidence`/`distance`, API7, `IMateConstraints3D`); **`drawing_create_standard_views`** (стандартные ассоциативные виды чертежа, API7, `DrawingService`); **`drawing_fill_title_block`** (заполнение основной надписи/штампа: обозначение, наименование, материал; `IStamp.Text[id].Str`, API7, `DrawingService`); **`drawing_add_linear_dimension`** (линейный размер на виде чертежа: `ISymbols2DContainer`/`LineDimensions.Add`/`ILineDimension`, координаты в локальной СК вида, API7, `DrawingService`); **`drawing_add_diametral_dimension`** (диаметральный размер Ø: `ISymbols2DContainer.DiametralDimensions.Add`/`IDiametralDimension`, Xc/Yc/Radius/Angle в радианах, API7, `DrawingService`); **`drawing_add_radial_dimension`** (радиальный размер R: `ISymbols2DContainer.RadialDimensions.Add`/`IRadialDimension`, значение = радиус, API7, `DrawingService`); **`drawing_add_angular_dimension`** (угловой размер: `ISymbols2DContainer.AngleDimensions.Add`/`IAngleDimension`, `angleType`=min/max/more, значение в градусах, API7, `DrawingService`). Класс «2D-чертёж» завершён: стандартные виды, основная надпись, размеры — линейный, диаметральный, радиальный, угловой. +**Реализовано (v1+v2+STEP/assembly+direct-edit+inspection+package-A+package-B+package-C+package-D start+package-E start+hole+hole_counterbore+hole_countersink+hole_conic+draft+assembly_add_component+assembly_add_mate+drawing_create_standard_views+drawing_fill_title_block+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension+drawing_add_rough+drawing_add_text+drawing_set_technical_requirements):** документы, эскизы (полный набор 2D-примитивов: линия, окружность, дуга, дуга по 3 точкам, прямоугольник, эллипс, ломаная, правильный многоугольник, сплайн NURBS, точка), **вспомогательная геометрия (`sketch_create_on_offset_plane`)**, выдавливание/вырез, вращение, скругление/фаска, **оболочка (`shell`)**, **ребро жёсткости (`rib`)**, **кинематическая операция (`sweep`)**, **операция по сечениям (`loft`)**, **линейный/круговой массив и зеркало (`linear_pattern`, `circular_pattern`, `mirror_operation`, `mirror_body`)**, **отверстие (`hole`, API7)**, **цековка (`hole_counterbore`, API7)**, **зенковка (`hole_countersink`, API7)**, **коническое отверстие (`hole_conic`, API7)**, **уклон (`draft`, API5 `ksInclineDefinition`)**, снимок; `get_part_info`, `get_bounding_box`, `list_faces`, `list_edges`; `import_step`, `export_step`, `list_components`; **`move_face`**, **`split_solid_by_plane`**, **`move_body`**, **`boolean_union`** (прямое редактирование и булевы операции); **`describe_model`, `list_features`, `list_bodies`, `list_variables`, `describe_face`, `describe_edge`, `measure`** (структурный осмотр модели); **`create_variable`, `set_variable`, `delete_variable`** (управление переменными, package D start); **`assembly_add_component`** (вставка компонента в сборку, API7, `AssemblyService`); **`assembly_add_mate`** (сопряжения `coincidence`/`distance`, API7, `IMateConstraints3D`); **`drawing_create_standard_views`** (стандартные ассоциативные виды чертежа, API7, `DrawingService`); **`drawing_fill_title_block`** (заполнение основной надписи/штампа: обозначение, наименование, материал; `IStamp.Text[id].Str`, API7, `DrawingService`); **`drawing_add_linear_dimension`** (линейный размер на виде чертежа: `ISymbols2DContainer`/`LineDimensions.Add`/`ILineDimension`, координаты в локальной СК вида, API7, `DrawingService`); **`drawing_add_diametral_dimension`** (диаметральный размер Ø: `ISymbols2DContainer.DiametralDimensions.Add`/`IDiametralDimension`, Xc/Yc/Radius/Angle в радианах, API7, `DrawingService`); **`drawing_add_radial_dimension`** (радиальный размер R: `ISymbols2DContainer.RadialDimensions.Add`/`IRadialDimension`, значение = радиус, API7, `DrawingService`); **`drawing_add_angular_dimension`** (угловой размер: `ISymbols2DContainer.AngleDimensions.Add`/`IAngleDimension`, `angleType`=min/max/more, значение в градусах, API7, `DrawingService`); **`drawing_add_rough`** (знак шероховатости: `ISymbols2DContainer.Roughs.Add`/`IRough`/`IRoughParams`, `signType`=delete/without/none, API7, `DrawingService`); **`drawing_add_text`** (свободная текстовая надпись на виде: `IDrawingContainer.DrawingTexts.Add`/`IDrawingText`/`IText`, API7, `DrawingService`); **`drawing_set_technical_requirements`** (технические требования чертежа: `IDrawingDocument.TechnicalDemand`/`ITechnicalDemand`/`IText`, уровень документа, API7, `DrawingService`). Класс «2D-чертёж» (инкремент 6): стандартные виды, основная надпись, размеры (линейный, диаметральный, радиальный, угловой), текстовые обозначения (шероховатость, свободный текст, технические требования). **Следующие приоритеты:** 1. Пакет D «параметрика» (продолжение) — связь размеров эскизов с переменными (параметрические эскизы через API2D). ⚠️ **Исследовано**: `ksCDimWithVariable` недоступен из внешней автоматизации — см. `docs/superpowers/specs/2026-05-27-parametric-sketch-findings.md`. 2. Пакет E «вспомогательная геометрия» (продолжение) — ось, точка, плоскость по трём точкам / по углу. 3. Рассечение/перемещение тела как MCP-инструменты (`SplitSolids`/`BodyRepositions`) — механика есть, продуктизация не закончена. 4. Свойства документа: `IPropertyMng` / `IPropertyKeeper`. -5. **2D-чертёж (продолжение):** базовое семейство размеров реализовано — линейный, диаметральный, радиальный, угловой (`drawing_add_linear_dimension`, `drawing_add_diametral_dimension`, `drawing_add_radial_dimension`, `drawing_add_angular_dimension`). Нереализовано: ассоциативная привязка размеров к геометрии (`BaseObject`), рамка/формат листа, текстовые обозначения (шероховатость, допуски формы, выноски, технические требования). +5. **2D-чертёж (продолжение):** инкремент 6 добавил текстовые обозначения — `drawing_add_rough` (шероховатость), `drawing_add_text` (свободный текст), `drawing_set_technical_requirements` (тех. требования). Нереализовано: ассоциативная привязка размеров и шероховатости к геометрии (`BaseObject`), рамка/формат листа, выноски (`Leaders`), обозначения баз (`Bases`), допуски формы (`Tolerances`). 6. Сборки — продолжение: дополнительные типы сопряжений (`parallel`, `perpendicular`, `concentric`, `angle`, `tangency`; `coincidence`/`distance` реализованы); авто-позиционирование компонентов; спецификации (`ISpecification`). 7. Транспорт **HTTP/SSE** — как опция для удалённых клиентов. diff --git a/docs/OPEN_QUESTIONS.md b/docs/OPEN_QUESTIONS.md index 84d2399..d13446a 100644 --- a/docs/OPEN_QUESTIONS.md +++ b/docs/OPEN_QUESTIONS.md @@ -208,4 +208,15 @@ stateful-сессии? Пока полагаемся на последовате `drawing_add_angular_dimension(xc,yc, x1,y1, x2,y2, x3,y3, angleType="min", viewNumber)` — угловой размер. `angleType` = `"min"` (острый) | `"max"` (тупой) | `"more"` (рефлексный >180°). Паттерн API7: `RequireSymbols2DContainer(viewNumber)` → `AngleDimensions.Add(ksDrADimension)` → `IAngleDimension` (`Xc`,`Yc`,`X1`,`Y1`,`X2`,`Y2`,`X3`,`Y3`, `DimensionType=ksAngleDimTypeEnum`, `AutoNominalValue=true`) → `Update()` → `Valid` → `NominalValue` в градусах. Новый enum `AngleDimensionType {Min,Max,More}` + `AngleDimensionTypes.Parse/ToKompas` в `DimensionOrientation.cs` (+9 unit-тестов для маппинга). -Итог: **78 инструментов, 241 тест (150 unit + 91 integration).** Класс «2D-чертёж» — виды, штамп, размеры (линейный, диаметральный, радиальный, угловой) — завершён. Нереализовано: ассоциативная привязка размеров к геометрии (`BaseObject`), рамка/формат листа, текстовые обозначения (шероховатость, допуски формы, выноски, тех. требования). +Итог: **78 инструментов, 241 тест (150 unit + 91 integration).** Базовое семейство размеров завершено — виды, штамп, размеры (линейный, диаметральный, радиальный, угловой). Нереализовано: текстовые обозначения (шероховатость, допуски формы, выноски, тех. требования), ассоциативная привязка, рамка/формат. + +### ✅ Текстовые обозначения на чертеже — реализованы (инкремент 6 вехи «2D-чертёж») +**Решено.** Три новых инструмента завершают класс «2D-чертёж» на уровне текстовых аннотаций: + +`drawing_add_rough(x,y, value?, signType, angle=0, viewNumber)` — знак шероховатости на виде. Паттерн API7: `ISymbols2DContainer.Roughs.Add()` → `IRough` (`BranchX0/Y0/Angle`) → `(IRoughParams)rough` (`SignType=ksRoughSignEnum`, `RoughParamText.Str = value`) → `Update()` → `Valid`. Новый enum `RoughSignType {NoProcessing, DeleteMaterial, WithoutDeleteMaterial}` + `RoughSignTypes.Parse/ToKompas` в `Drawings/RoughSignType.cs`. Возвращает `DrawingAnnotationResult { Value, ViewNumber }`. + +`drawing_add_text(x,y, text, angle=0, viewNumber)` — свободная текстовая надпись на виде. Паттерн API7: `(IDrawingContainer)view.DrawingTexts.Add()` → `IDrawingText` (`X/Y/Angle`) → `(IText)dt.Str = text` → `Update()` → `Valid`. ВАЖНО: текст живёт в `IDrawingContainer`, а не `ISymbols2DContainer`; проверяется через `DrawingTexts.Count`. Возвращает `DrawingAnnotationResult { Value, ViewNumber }`. + +`drawing_set_technical_requirements(text)` — технические требования документа (уровень документа, не вида). Паттерн API7: `(IDrawingDocument)doc.TechnicalDemand` → `td.Text.Str = text` → `td.Update()`. Перезаписывает прежние. Возвращает число строк. + +Итог: **81 инструмент, 267 тестов (163 unit + 104 integration).** Нереализовано: ассоциативная привязка размеров и шероховатости к геометрии (`BaseObject`), рамка/формат листа, выноски (`Leaders`), обозначения баз (`Bases`), допуски формы (`Tolerances`). diff --git a/docs/presentation.html b/docs/presentation.html index 4bd8e92..f83f8d3 100644 --- a/docs/presentation.html +++ b/docs/presentation.html @@ -128,7 +128,7 @@
- Статус: v3+ работает — эскиз→операции→STEP→сборка→move_face→структурный осмотр→богатые эскизы→shell+rib+sweep+loft+массивы+зеркало+hole+hole_counterbore+hole_countersink+hole_conic+draft+переменные+assembly_add_component+assembly_add_mate+drawing_create_standard_views+drawing_fill_title_block+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension (78 инструментов) + Статус: v3+ работает — эскиз→операции→STEP→сборка→move_face→структурный осмотр→богатые эскизы→shell+rib+sweep+loft+массивы+зеркало+hole+hole_counterbore+hole_countersink+hole_conic+draft+переменные+assembly_add_component+assembly_add_mate+drawing_create_standard_views+drawing_fill_title_block+drawing_add_linear_dimension+drawing_add_diametral_dimension+drawing_add_radial_dimension+drawing_add_angular_dimension+drawing_add_rough+drawing_add_text+drawing_set_technical_requirements (81 инструмент)

КОМПАС-3D MCP-сервер
управление CAD языком LLM

MCP-сервер, который превращает операции КОМПАС-3D — создание документов, эскизы, 3D-операции, параметры — в инструменты для языковой модели. Под капотом — @@ -261,7 +261,7 @@ впереди.

-
Общий прогрессv3+: STEP · move_face · структурный осмотр · богатые эскизы (пакет A) · shell+rib+sweep+loft (пакет B) · массивы+зеркало (пакет C) · переменные (пакет D start) · offset-plane (пакет E start) · hole (API7) · hole_counterbore · hole_countersink · hole_conic · draft (API5) · assembly_add_component · assembly_add_mate · drawing_create_standard_views · drawing_fill_title_block · drawing_add_linear_dimension · drawing_add_diametral_dimension · drawing_add_radial_dimension · drawing_add_angular_dimension · навык kompas-3d · 78 инструментов · 241 тест
+
Общий прогрессv3+: STEP · move_face · структурный осмотр · богатые эскизы (пакет A) · shell+rib+sweep+loft (пакет B) · массивы+зеркало (пакет C) · переменные (пакет D start) · offset-plane (пакет E start) · hole (API7) · hole_counterbore · hole_countersink · hole_conic · draft (API5) · assembly_add_component · assembly_add_mate · drawing_create_standard_views · drawing_fill_title_block · drawing_add_linear_dimension · drawing_add_diametral_dimension · drawing_add_radial_dimension · drawing_add_angular_dimension · drawing_add_rough · drawing_add_text · drawing_set_technical_requirements · навык kompas-3d · 81 инструмент · 267 тестов
@@ -297,7 +297,7 @@

Инструменты v3+ ГОТОВО

-

78 инструментов, отдаются по MCP-протоколу

+

81 инструмент, отдаются по MCP-протоколу

  • System: connect · status · set_visible
  • Documents: create · open · save · save_as · close · active
  • @@ -310,8 +310,8 @@
  • Variables: create_variable · set_variable · delete_variable (пакет D)
  • Conversion: import_step · export_step
  • Assembly: assembly_add_component (вставка компонента .m3d/.a3d в сборку, API7) · assembly_add_mate (сопряжения coincidence/distance, API7)
  • -
  • Drawing: drawing_create_standard_views (стандартные ассоциативные виды чертежа, API7) · drawing_fill_title_block (основная надпись/штамп: обозначение, наименование, материал, API7) · drawing_add_linear_dimension (линейный размер на виде, ISymbols2DContainer, API7) · drawing_add_diametral_dimension (диаметральный размер Ø, IDiametralDimension, API7) · drawing_add_radial_dimension (радиальный размер R, IRadialDimension, API7) · drawing_add_angular_dimension (угловой размер, IAngleDimension, angleType=min/max/more, API7)
  • -
  • 2D-чертёж: ассоциативная привязка размеров к геометрии (BaseObject), рамка/формат, текстовые обозначения (шероховатость, допуски, выноски, тех. требования) · пакет E (ось, угловая плоскость) · пакет D параметрика: параметрические эскизы (API2D) — исследовано, недоступно через COM API · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency)
  • +
  • Drawing: drawing_create_standard_views (стандартные ассоциативные виды чертежа, API7) · drawing_fill_title_block (основная надпись/штамп: обозначение, наименование, материал, API7) · drawing_add_linear_dimension (линейный размер на виде, ISymbols2DContainer, API7) · drawing_add_diametral_dimension (диаметральный размер Ø, IDiametralDimension, API7) · drawing_add_radial_dimension (радиальный размер R, IRadialDimension, API7) · drawing_add_angular_dimension (угловой размер, IAngleDimension, angleType=min/max/more, API7) · drawing_add_rough (знак шероховатости, IRough/IRoughParams, signType=delete/without/none, API7) · drawing_add_text (свободный текст на виде, IDrawingContainer/IDrawingText, API7) · drawing_set_technical_requirements (тех. требования документа, IDrawingDocument/TechnicalDemand, API7)
  • +
  • 2D-чертёж: ассоциативная привязка размеров и шероховатости к геометрии (BaseObject), рамка/формат, выноски (Leaders), обозначения баз (Bases), допуски формы (Tolerances) · пакет E (ось, угловая плоскость) · пакет D параметрика: параметрические эскизы (API2D) — исследовано, недоступно через COM API · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency)
@@ -322,7 +322,7 @@
  • Unit-тесты — без COM: диспетчер, enum-маппинг, StepFormat, InspectionText
  • Интеграционные тесты с КОМПАС: подключение, документы, снимок, цикл, STEP round-trip, сборка, move_face, инспекция
  • -
  • Итого 241 тест зелёный (150 unit + 91 integration)
  • +
  • Итого 267 тестов зелёных (163 unit + 104 integration)
  • Сборка kompas-mcp.exe, README с конфигом клиента
  • Навык kompas-3d (методика) + полигон usecases/
  • In-process тест MCP-клиента, релизный publish
  • @@ -355,7 +355,8 @@
    2D-чертёж · инкремент 3 ✓

    Линейные размеры

    drawing_add_linear_dimension (ISymbols2DContainer/LineDimensions.Add/ILineDimension, локальная СК вида, API7) · ViewNumbers в результате видов · 75 инструментов · 203 теста

    2D-чертёж · инкремент 4 ✓

    Диаметральный размер

    drawing_add_diametral_dimension (ISymbols2DContainer.DiametralDimensions.Add/IDiametralDimension, Xc/Yc/Radius/Angle рад, API7) · RequireSymbols2DContainer общий хелпер · DimensionAngles.ToRadians · 76 инструментов · 218 тестов

    2D-чертёж · инкремент 5 ✓

    Радиальный и угловой размеры

    drawing_add_radial_dimension (IRadialDimension, DimensionType=true, API7) · drawing_add_angular_dimension (IAngleDimension, angleType=min/max/more, AngleDimensionType enum, API7) · базовое семейство размеров завершено · 78 инструментов · 241 тест

    -
    далее · в работе ▶

    Оформление чертежа

    Ассоциативная привязка размеров (BaseObject) · рамка/формат · текстовые обозначения (шероховатость, допуски, выноски) · пакет E (ось, угловая плоскость) · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency) · пакет D параметрика — параметрические эскизы недоступны через COM API

    +
    2D-чертёж · инкремент 6 ✓

    Текстовые обозначения

    drawing_add_rough (IRough/IRoughParams, signType=delete/without/none, API7) · drawing_add_text (IDrawingContainer/IDrawingText/IText, API7) · drawing_set_technical_requirements (IDrawingDocument/TechnicalDemand, уровень документа, API7) · DrawingAnnotationResult · RoughSignType enum · 81 инструмент · 267 тестов

    +
    далее · в работе ▶

    Оформление чертежа

    Ассоциативная привязка размеров и шероховатости к геометрии (BaseObject) · рамка/формат · выноски (Leaders) · обозначения баз (Bases) · допуски формы (Tolerances) · пакет E (ось, угловая плоскость) · прочие типы сопряжений (parallel/perpendicular/concentric/angle/tangency) · пакет D параметрика — параметрические эскизы недоступны через COM API