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>
14 KiB
Дизайн: текстовые обозначения чертежа — шероховатость, текст, тех. требования (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)
Шероховатость:
- Ставится + round-trip:
value="Ra 1.6",signType=delete→Value=="Ra 1.6"(read-back из COM), попадание в целевой вид (Roughs.Count+1, адресация поviewNumber). - Знак без значения:
value=""→ ставится (Valid),Roughs.Count+1. - Нет видов → понятная ошибка. 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); рамка/формат листа; ассоциативная привязка размеров.