Инкремент 9. 83 инструмента, 331 тест. + заметка о ревью реализации в спеке (Codex + pi/glm-5.1 + pi/kimi-k2.6). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10 KiB
Дизайн: линия-выноска с текстом (drawing_add_leader) через API7
Дата: 2026-05-28 Статус: дизайн согласован, спайк проведён, ревью Codex + pi/glm-5.1 + pi/kimi-k2.6 учтено — к реализации
Правки по ревью реализации (Codex + pi/glm-5.1 + pi/kimi-k2.6)
- Проверка возврата
AddBranchByPoint/SetBranchTextPosition(обаbool) — ранняя диагностика вместо позднегоRPC_E_SERVERFAULT(Codex, glm). - RU-алиасы в сообщении
ShelfDirections.Parseи в[Description]инструмента (glm, kimi). - Интеграционный тест направления полки параметризован
Right/Left/Up/Down— покрывает всю поверхностьToKompasна реальном COM (glm, kimi). - Отклонено (обоснование): unit-тест
ToKompas(граница проекта — тест не ссылается наKompas6Constants); e2e-тест tool-обёртки (тонкая,Parse+сервис покрыты);angleDeg(уILeader/IBaseLeaderнет свойства Angle — ориентация геометрическая); выравнивание defaulttextуAddText(вне объёма; required-контрактAddLeaderкорректнее).
Правки по ревью спека (Codex + pi/glm-5.1 + pi/kimi-k2.6)
- Сигнатура
DrawingValidation.RequireNonEmptyText(text, nameof(text))(двухаргументный — как есть). - QI с диагностикой:
bl as IBranchs ?? throw,bl as ILeader ?? throw(не прямой cast); read-backleader.TextOnShelf?.Str ?? string.Empty; двухшаговый null-checkLeaders(коллекция) иAdd()— какAddRoughCore. ShelfDirections.ToKompas(Auto)бросаетArgumentOutOfRangeException(Auto обрабатывается в сервисе ДО вызова — «не задавать ShelfDirection»; прямой вызов для Auto — ошибка). RU-алиасыParse:авто/вправо/влево/вверх/вниз.- Вырожденная выноска:
RequireDistinctPoints(x, y, textX, textY)(остриё ≠ полка; есть валидатор). - Критический порядок (комментарий в коде):
AddBranchByPointДОSetBranchTextPosition/Update(иначе RPC_E_SERVERFAULT — выноска без ветвей). - Тесты: пустой текст —
""И" ";viewNumber=0резолвится в первый вид; путьshelfDirection=auto(ShelfDirection не задаётся). XML-<summary>членовShelfDirection— «в ЛОКАЛЬНОЙ СК вида». - Нейминг COM-объекта —
baseLeader(неbl).GetViewLeaderCountAsyncсчитает ВСЕ подтипы выносок (для v1 ок; фильтр — при добавлении ksDrPosLeader/… — в «Дальнейшее»).
Цель
Веха 2D-ЧЕРТЁЖ, инкремент 9. Поставить на виде линию-выноску (leader) с текстовой надписью на полке — поясняющее обозначение, указывающее стрелкой на элемент (примечание, материал детали, и т.п.).
Спайк: последовательность подтверждена вживую (НЕ разучивать)
Спайк (_SpikeLeader, прогнан на реальном КОМПАС, затем удалён). Ключ: только что созданная
выноска имеет 0 ответвлений — любые операции над ответвлением (SetSignPosition) и Update на
выноске без ветвей падают с RPC_E_SERVERFAULT; сначала нужно добавить ответвление через IBranchs.
IBaseLeader bl = symbols.Leaders.Add(DrawingObjectTypeEnum.ksDrLeader); // ksDrLeader=20
((IBranchs)bl).AddBranchByPoint(0, x, y); // QI; ответвление 0 — остриё (куда указывает стрелка)
bl.SetBranchTextPosition(textX, textY); // положение полки/текста
((ILeader)bl).TextOnShelf.Str = text; // надпись на полке (.Str — наш interop)
// опц.: ((ILeader)bl).ShelfDirection = ksShelfDirectionEnum.ksLSRight;
bl.Update(); // True, bl.Valid == True
Проверено: AddBranchByPoint(0,x,y) → BranchCount=1; Update=True, Valid=True,
TextOnShelf.Str round-trip; Leaders.Count +1. Работает с явной ShelfDirection и без неё.
BaseLeader реализует IBaseLeader/IDrawingObject; IBranchs и ILeader — COM-QI от него.
Интерфейсы: ILeaders.Add(DrawingObjectTypeEnum) → BaseLeader (для обычной выноски ksDrLeader=20);
IBranchs.AddBranchByPoint(int index, double x, double y); IBaseLeader.SetBranchTextPosition(x,y) /
Update / Valid / Delete / ArrowType (ksArrowEnum); ILeader.TextOnShelf (IText),
ShelfDirection (ksShelfDirectionEnum: ksLSNone=0/ksLSRight=1/ksLSUp=2/ksLSDown=3/ksLSLeft=-1).
MCP-инструмент
| Инструмент | Параметры | Поведение |
|---|---|---|
drawing_add_leader |
x,y (остриё — куда указывает стрелка), textX,textY (полка/якорь текста), text, shelfDirection="auto" (auto|right|left|up|down), viewNumber=0 |
Поставить выноску на виде: стрелка из полки указывает в (x,y), текст text на полке у (textX,textY). Координаты — ЛОКАЛЬНАЯ СК вида (мм). shelfDirection — направление полки (auto = по умолчанию КОМПАС). Возвращает текст (read-back) и номер вида. |
Архитектура
В DrawingService (namespace Kompas.Mcp.Core.Drawings).
AddLeaderAsync(viewNumber, x, y, textX, textY, text, shelfDirection, ct)→DrawingAnnotationResult(переиспользуем:Value=read-back текст,ViewNumber).- Использует существующий
RequireSymbols2DContainer(viewNumber)(выноски вISymbols2DContainer.Leaders). - Новый файл
src/Kompas.Mcp.Core/Drawings/ShelfDirection.cs:enum ShelfDirection {Auto,Right,Left,Up,Down}(XML-<summary>на членах) +ShelfDirections.Parse(string)/ToKompas(ShelfDirection)→ksShelfDirectionEnumпо образцуAngleDimensionTypes.Auto→ не задаватьShelfDirection(оставить дефолт КОМПАС). - Счётчик
GetViewLeaderCountAsync(viewNumber)(для теста попадания в вид).
Реализация
AddLeaderCore: RequireNonEmptyText(text) + RequireFiniteCoords(x,y,textX,textY) →
RequireSymbols2DContainer → symbols.Leaders (null-check) → .Add(ksDrLeader) (null-check) →
внутри try/catch+Delete: ((IBranchs)bl).AddBranchByPoint(0, x, y) (QI null-check),
bl.SetBranchTextPosition(textX, textY), ((ILeader)bl).TextOnShelf (null-check) .Str = text,
если shelfDirection != Auto: ((ILeader)bl).ShelfDirection = ShelfDirections.ToKompas(...) →
bl.Update() (FALSE → откат) → bl.Valid (false → откат) → read-back ((ILeader)bl).TextOnShelf.Str
→ DrawingAnnotationResult{Value=read-back, ViewNumber}.
RCW точечно не освобождаем (консистентно; долг v2-2).
Валидация (чистые static, unit)
RequireNonEmptyText(text, nameof(text)),RequireFiniteCoords(x,y,textX,textY),RequireDistinctPoints(x, y, textX, textY)(остриё ≠ полка) — все уже есть.ShelfDirections.Parse—auto/right/left/up/down(+ рус.авто/вправо/влево/вверх/вниз, регистр/пробелы); неизвестное →ArgumentException; null →ArgumentNullException.ToKompas(→ksShelfDirectionEnum) НЕ покрываем unit (граница проекта); бросаетArgumentOutOfRangeExceptionнаAuto.
Тестирование
Unit (ShelfDirectionsTests)
Parse:auto/right/left/up/down(+ регистр, рус.) → enum; неизвестное →ArgumentException; null →ArgumentNullException.
Integration (DrawingLeaderTests; модель — коробка + стандартные виды)
- Ставится + round-trip + viewNumber=0:
text="Примечание 1",shelfDirection=auto,viewNumber=0→Value=="Примечание 1"(read-back),viewNumber=0резолвится в первый вид (r.ViewNumberсовпал),Leaders.Countцелевого вида +1. - shelfDirection=left (не-auto путь) на целевом виде → ставится,
Leaders.Count+1. - Пустой текст (
""и" ") →ArgumentException(до Add). - Вырожденная (остриё совпадает с полкой) →
ArgumentException(до Add). - Нет видов → понятная ошибка. 6. Несуществующий
viewNumber>0→ понятная ошибка.
Дальнейшее (вне спека)
- Многострочный текст полки / текст под полкой (
TextUnderShelf); несколько ответвлений (AddBranchByPointс разными индексами); привязка к геометрии (IBranchs.SetBaseObject); тип стрелки (ArrowType); специальные выноски (позиция/клеймо/маркер:ksDrPosLeader/ksDrBrandLeader/ksDrMarkerLeader). Базы (Bases), допуски формы (Tolerances).