feat(feature): операция Ребро жёсткости (rib)
RibAsync (o3d_ribOperation): SetSketch + index/angle/side + SetThinParam. SketchGeometry.RibSide маппинг (left/right/up/down). Инструмент rib в FeatureTools. Эмпирически: контур ребра висит в зазоре (не касается тела), side=left для косынки. Integration: L-уголок + ребро в углу → объём растёт. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
# Дизайн: пакет B (шаг 2) — операция «Ребро жёсткости» (rib)
|
||||
|
||||
**Дата:** 2026-05-26
|
||||
**Статус:** на ревью (автономный режим; ревьюер — Codex)
|
||||
|
||||
## Цель
|
||||
|
||||
Добавить формообразующую операцию **«Ребро жёсткости»** (rib) — достроить тонкую стенку от
|
||||
разомкнутого контура эскиза до тела. Второй шаг пакета B. Один MCP-инструмент `rib`.
|
||||
|
||||
## Сигнатуры COM (рефлексия interop + SDK-база + ksConstants3D.h)
|
||||
|
||||
```
|
||||
Obj3dType.o3d_ribOperation = 44
|
||||
ksRibDefinition:
|
||||
int index // сегмент эскиза, задающий уклон (0 — первый сегмент)
|
||||
double angle // угол уклона стенок, градусы (0 — вертикальные)
|
||||
int side // направление достройки: ksRibSideEnum
|
||||
bool SetSketch(object) / GetSketch()
|
||||
bool SetThinParam(short thinType, double normalThickness, double reverseThickness)
|
||||
ksRibSideEnum: ksRibSideLeft=0, ksRibSideRight=1, ksRibSideUp=2, ksRibSideDown=3
|
||||
Direction_Type (thinType): dtNormal=0, dtReverse=1, dtBoth=2, dtMiddlePlane=3
|
||||
```
|
||||
|
||||
**Паттерн:** `NewEntity(o3d_ribOperation)` → `GetDefinition()` → `SetSketch` →
|
||||
`index`/`angle`/`side`/`SetThinParam` → `Create()`. Порядок: сначала `SetSketch`, затем
|
||||
параметры, затем `Create()`.
|
||||
|
||||
**Эскиз:** разомкнутый контур (отрезок/ломаная) на плоскости, пересекающей тело; КОМПАС
|
||||
сам «дотягивает» ребро до тела.
|
||||
|
||||
## Новый MCP-инструмент (группа Feature)
|
||||
|
||||
| Инструмент | Параметры | Поведение |
|
||||
|---|---|---|
|
||||
| `rib` | `sketchId: int`, `thickness: double`, `side: string = "up"`, `symmetric: bool = true`, `angle: double = 0` | Построить ребро жёсткости от разомкнутого контура эскиза `sketchId` до тела. `thickness` — толщина стенки (мм). `side` ∈ {left,right,up,down} — направление достройки. `symmetric=true` — толщина симметрична плоскости эскиза; `false` — в одну сторону. `angle` — уклон стенок (°). |
|
||||
|
||||
**Маппинги:**
|
||||
- `side`: `left→0, right→1, up→2, down→3` (через `SketchGeometry.RibSide(string)`, unit-тест).
|
||||
- `symmetric=true → SetThinParam(dtBoth=2, thickness/2, thickness/2)`;
|
||||
`false → SetThinParam(dtNormal=0, thickness, 0)`.
|
||||
- `index = 0` (фиксировано — первый сегмент контура).
|
||||
|
||||
## Реализация
|
||||
|
||||
- **Метод** `RibAsync(int sketchId, double thickness, string side, bool symmetric, double angle, CancellationToken)`
|
||||
в `PartModeler.Features.cs`. Эскиз закрывается перед операцией (`CloseSketchCore`, как
|
||||
`ExtrudeAsync`/`RevolveAsync`); берётся `sketch.Entity` из реестра по id. Возвращает id операции.
|
||||
- **Маппинг side** — `SketchGeometry.RibSide(string)` (public static, unit-тест; бросает
|
||||
`ArgumentException` на неизвестное значение).
|
||||
- **Инструмент** `rib` в `FeatureTools.cs`.
|
||||
- **Валидация** (inline): `thickness > 0`; `side` — известное значение (через `RibSide`).
|
||||
`Create()==FALSE` → `InvalidOperationException` (контур не пересекает тело / некорректное
|
||||
направление?).
|
||||
- Транзитный `ksRibDefinition` не освобождается — консистентно с прочими операциями (долг v2-2).
|
||||
|
||||
## Тестирование
|
||||
|
||||
**Unit:** `SketchGeometry.RibSide` — маппинг строк в коды и бросок на неизвестном значении.
|
||||
|
||||
**Integration** (`FeatureOpsTests`): Г-образный уголок (L-профиль на XOZ, замкнутая ломаная
|
||||
`(0,0)(40,0)(40,5)(5,5)(5,40)(0,40)`, extrude по Y на 30 → объём 375·30=11250) → эскиз ребра
|
||||
на XOZ: разомкнутый отрезок-диагональ во внутреннем углу (например `(25,10)→(10,25)`, **висит в зазоре, не касаясь полок**) →
|
||||
`RibAsync(sketchId, thickness=5, side="left", symmetric=false)` → объём увеличивается
|
||||
(добавлена косынка): `after > before`, прирост правдоподобный (`after ∈ (before, before·1.3)`).
|
||||
|
||||
**Проверено эмпирически (важно для контракта):** контур ребра должен **висеть в зазоре**
|
||||
между полками (не касаться граней тела концами — иначе `Create()==FALSE`); КОМПАС сам
|
||||
дотягивает полотно до тела в направлении `side`. Для косынки во внутреннем углу сработало
|
||||
`side="left"`, `symmetric=false` (толщина в прямом направлении нормали плоскости).
|
||||
Reference in New Issue
Block a user