Files
kompas3d-mcp/docs/OPEN_QUESTIONS.md
T
mikhail 01f5f37c67 @
feat(sketch): эскиз на выбранной грани + МЦХ через API5

sketch_create_on_face: OpenSketchOnFaceAsync выбирает плоскую грань по точке
(ksPart.EntityCollection(o3d_face).SelectByPoint) и создаёт на ней эскиз —
ключевой шаг итеративного цикла «построил → выбрал грань → новый эскиз».
Общее ядро создания эскиза вынесено в CreateSketchOn.

QueryService переписан на API5 ksPart.CalcMassInertiaProperties(ST_MIX_MM|ST_MIX_KG):
- API7 IMassInertiaParam7.Calculate() непригоден — флаг Actual «залипает» после
  первого расчёта, повторный запрос отдавал устаревший объём (баг кэша);
- API5-маршрут считает по запросу и согласован с построением через ksPart;
- единицы (мм³/мм²/кг/мм) задаются битовым вектором.

Тест Sketch_on_face_adds_boss_on_top: запрос → штифт R5×H10 на верхней грани
цилиндра → повторный запрос видит прирост ≈785 мм³ (проверяет и грань, и кэш МЦХ).
Презентация: 20 инструментов, 15 тестов; OPEN_QUESTIONS обновлён.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@
2026-05-26 09:52:56 +03:00

93 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Открытые вопросы для проработки
Журнал спорных моментов и решений, принятых автономно (ночная сессия 2026-05-25/26).
Помечено: ⚠️ = требует вашего решения; ✅ = решено по умолчанию, можно пересмотреть.
---
## ⚠️ 1. API5 vs API7 для построения 3D
**Контекст.** Примеры SDK строят 3D через **API5** (`ksPart.NewEntity(o3d_*)`
`ksBossExtrusionDefinition``Create()`). API7 предлагает `IPart7``IModelContainer`
`IExtrusions.Add()`.
**Решение по умолчанию (✅ в коде):** в v1 строю 3D через **API5 `ksPart`** (надёжно, повторяет
рабочие примеры Step3d1). API7 использую для приложения/документов/версии.
**На проработку:** переводить ли операции на чистый API7 позже (плюс — единообразие, минус — риск).
## ✅ 2. Точка входа подключения — API5
Для построения 3D нужен `KompasObject` (API5), а для снимка — `ksDocument3D` (API5).
Поэтому `KompasSession` подключается через `KOMPAS.Application.5``KompasObject`, затем
`ksGetApplication7()``IApplication`. Держит обе ссылки. (Ранее в спайке заходили через `.7`.)
## ✅ 3. Состав проектов v1
Вместо 4 проектов (Host/Tools/Core/Interop) сделано компактно: **Core** (COM + сервисы) +
**Host** (MCP + определения инструментов) + **Tests**. Interop — вендорские DLL в `libs/`.
Разнести на больше проектов можно позже.
## ✅ 4. Тестовые артефакты
Тестовые документы КОМПАС сохраняю в `.scratch/` (gitignore). Снимки рендера — туда же,
для визуальной проверки.
---
## Само-ревью кода (ночная сессия) — итоги
**Исправлено сразу:**
- C1/C2 — утечки COM и устаревшие id: `PartModeler` освобождает RCW и сбрасывает реестр
(`ResetAsync`/`Dispose`), `DocumentTools` сбрасывает реестр при create/open/close;
`DocumentService` освобождает транзитные `IDocuments`/`IKompasDocument`.
- M3 — `KompasSession.Dispose`: ограниченное ожидание (5 c) вместо вечного блока.
- M4 — `ExtrudeAsync`: убран `dynamic`, конкретные `ksBossExtrusionDefinition`/
`ksCutExtrusionDefinition`; `throughAll` разрешён только для выреза.
- m7 — `extrude_cut`: дефолт `throughAll=false`, без молчаливой подмены `depth`.
- Регрессионный тест: после `ResetAsync` старый id эскиза недействителен.
**⚠️ Отложено на проработку (из ревью):**
- M5 — отмена/насос сообщений: `CancellationToken` не прерывает уже идущий COM-вызов; зависший
вызов (модальный диалог КОМПАС) блокирует всю очередь. Возможное решение — диспетчер с насосом
сообщений + подавление диалогов. Связано с [конкурентностью MCP].
- m6 — `colorBPP=24` для снимка: для GIF (палитра) может не подойти; снимок по умолчанию PNG.
- m8 — приведения enum к `short` для `GetPart/NewEntity/GetDefaultEntity`: на v24 работает
(тесты зелёные), но стоит сверить точные типы параметров в interop.
- m10 — `_app/_kompas` читаются из `IsConnected/Status()` вне STA-потока без `volatile`
(доброкачественное устаревшее чтение).
- m11 — трансляция `COMException`/HRESULT в понятные сообщения (сейчас понятны только наши
`InvalidOperationException`); добавить текст последней ошибки КОМПАС.
## Журнал решений по ходу
(дополняется автоматически во время работы)
### ⚠️ Конкурентность вызовов MCP и состояние сессии
MCP-сервер обрабатывает запросы **конкурентно**. Цикл моделирования с реестром эскизов по id
(`sketch_create``sketch_add_*`) предполагает, что клиент **ждёт ответа** на каждый вызов перед
следующим (нормальное поведение LLM-клиентов). При «конвейерной» отправке зависимых вызовов
возможна гонка (id ещё не зарегистрирован). STA-диспетчер сериализует COM, но не порядок постановки задач.
**На проработку:** нужна ли серверная сериализация вызовов инструментов (очередь) для надёжности
stateful-сессии? Пока полагаемся на последовательное поведение клиента.
### ✅ Возврат изображения: ImageContentBlock.FromBytes
Поле `ImageContentBlock.Data` хранит **base64-байты**, а не сырые. Сырые байты PNG нужно
передавать через `ImageContentBlock.FromBytes(bytes, mimeType)` — он сам кодирует. Прямое
присваивание `Data = rawBytes` портит изображение на проводе. Исправлено в VisionTools.
### ✅ МЦХ (get_part_info): API5 `CalcMassInertiaProperties`, а не API7
Сначала пробовали API7 `IMassInertiaParam7` (от `TopPart`). Две проблемы:
1. **Единицы** — отдаёт в единицах отображения МЦХ документа (по умолчанию см³/см²/г), зависит от настроек.
2. **Залипающий кэш** — после первого расчёта свойство `Actual` остаётся `TRUE` и не сбрасывается
при изменении геометрии через API5; `Calculate()` возвращает `FALSE` и не пересчитывает.
Сценарий «запрос → достройка → запрос» отдавал **устаревшее** значение. Сброс через
`RebuildModel`, переключение `MassSettingMode` — не помогли.
**Решение (✅ в коде):** считаем через API5 **`ksPart.CalcMassInertiaProperties(bitVector)`** →
`ksMassInertiaParam` (`v`/`m`/`F`/`xc`/`yc`/`zc`). Считает «по запросу» (без залипания), единицы
задаются битовым вектором: `ST_MIX_MM (0x1) | ST_MIX_KG (0x10)`**мм³, мм², кг, мм**.
Согласовано с тем, что деталь строится через API5 `ksPart`. Проверено двумя тестами:
цилиндр R10×H20 (V≈6283 мм³, S≈1885 мм², m≈0.0494 кг, Zc=10 мм) и «запрос → штифт на грани → запрос»
(виден корректный прирост ≈785 мм³). Материал по умолчанию — сталь (ρ≈7.856 г/см³).
### ✅ Снимок 3D: рендер через файл, а не resultArrayBytes
`ksDocument3D.SaveAsToRasterFormat(fileName, param)` при **непустом** `fileName` возвращает TRUE,
пишет корректный PNG на диск, но `param.resultArrayBytes` остаётся **пустым**. Поэтому
`SnapshotService` рендерит во временный файл и читает байты обратно (надёжно проверено на v24 Home).
**На проработку:** пустое имя файла + `returnResultAsArrayBytes=true` для чистого in-memory —
не проверено; текущий путь через temp-файл работает.