Files
kompas3d-mcp/docs/superpowers/specs/2026-05-27-drawing-text-annotations-design.md
T
mikhail 5272066bef feat(drawing): текстовые обозначения — шероховатость, текст, тех. требования
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) <noreply@anthropic.com>
2026-05-27 21:13:11 +03:00

14 KiB
Raw Blame History

Дизайн: текстовые обозначения чертежа — шероховатость, текст, тех. требования (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.Count2 (вид уже содержал 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-тест; ToKompasksRoughSignEnum НЕ покрываем unit — граница проекта, как у AngleDimensionTypes/DimensionOrientations).

Реализация

AddRoughCore: нормализация value (null/whitespace → "") → RequireFiniteCoords(x,y,angleDeg)RequireSymbols2DContainersymbols.Roughs (null-check) → .Add() (null-check) → BranchX0/Y0/Angle(IRoughParams)rough (null-check QI) → SignType=ToKompas, rp.RoughParamText (null-check) .Str = valueUpdate() (FALSE → откат Delete) → Valid (false → откат) → читаем rp.RoughParamText.Str обратно → DrawingAnnotationResult{Value=read-back, ViewNumber}.

AddTextCore: RequireNonEmptyText(text) + RequireFiniteCoords(x,y,angleDeg)RequireDrawingContainerdc.DrawingTexts (null-check) → .Add() (null-check) → X/Y/Angle(IText)dt (null-check QI) .Str = textUpdate() (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 = texttd.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=deleteValue=="Ra 1.6" (read-back из COM), попадание в целевой вид (Roughs.Count +1, адресация по viewNumber).
  2. Знак без значения: value="" → ставится (Valid), Roughs.Count +1.
  3. Нет видов → понятная ошибка. 4. Несуществующий viewNumber>0 → ошибка.

Текст: 5. Ставится + round-trip: textValue==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); рамка/формат листа; ассоциативная привязка размеров.