fix(feature): правки rib по ревью Codex

- thickness через RequirePositive (NaN-safe) + проверка angle на IsFinite
- описание side нейтральное (ksRibSideEnum), без 'ортогонально'
- тест: проверка объёма L-уголка (before), комментарий side=left

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-26 22:55:48 +03:00
parent fc99739e1e
commit d318525e45
3 changed files with 6 additions and 5 deletions
@@ -237,7 +237,8 @@ public sealed partial class PartModeler
public Task<int> RibAsync(int sketchId, double thickness, string side = "up", bool symmetric = true, double angle = 0, CancellationToken ct = default) public Task<int> RibAsync(int sketchId, double thickness, string side = "up", bool symmetric = true, double angle = 0, CancellationToken ct = default)
=> _dispatcher.InvokeAsync(() => => _dispatcher.InvokeAsync(() =>
{ {
if (thickness <= 0) throw new ArgumentOutOfRangeException(nameof(thickness), "Толщина должна быть > 0."); SketchGeometry.RequirePositive(thickness, nameof(thickness)); // ловит и NaN (!(NaN>0))
if (!double.IsFinite(angle)) throw new ArgumentException("Угол уклона должен быть конечным числом.", nameof(angle));
var sideCode = SketchGeometry.RibSide(side); var sideCode = SketchGeometry.RibSide(side);
var sketch = RequireSketch(sketchId); var sketch = RequireSketch(sketchId);
CloseSketchCore(sketch); // эскиз должен быть закрыт перед операцией CloseSketchCore(sketch); // эскиз должен быть закрыт перед операцией
+1 -1
View File
@@ -105,7 +105,7 @@ public sealed class FeatureTools(KompasSession session, PartModeler modeler)
} }
[McpServerTool(Name = "rib")] [McpServerTool(Name = "rib")]
[Description("Построить ребро жёсткости от разомкнутого контура эскиза до тела. sketchId — эскиз с разомкнутым контуром (отрезок/ломаная) на плоскости, пересекающей тело. thickness — толщина стенки ребра (мм). side — направление достройки до тела: left|right (вдоль плоскости эскиза) или up|down (ортогонально плоскости). symmetric=true — толщина симметрична плоскости эскиза, false — в одну сторону. angle — уклон стенок (градусы). Возвращает id операции.")] [Description("Построить ребро жёсткости от разомкнутого контура эскиза до тела. sketchId — эскиз с разомкнутым контуром (отрезок/ломаная) на плоскости, пересекающей тело. thickness — толщина стенки ребра (мм). side — направление достройки полотна до тела (ksRibSideEnum): left|right|up|down (если ребро не строится — перебрать значения). symmetric=true — толщина симметрична плоскости эскиза, false — в одну сторону. angle — уклон стенок (градусы). Возвращает id операции.")]
public async Task<string> Rib(int sketchId, double thickness, string side = "up", bool symmetric = true, double angle = 0) public async Task<string> Rib(int sketchId, double thickness, string side = "up", bool symmetric = true, double angle = 0)
{ {
await session.ConnectAsync(); await session.ConnectAsync();
@@ -63,10 +63,10 @@ public sealed class FeatureOpsTests
await _modeler.CloseSketchAsync(sBody); await _modeler.CloseSketchAsync(sBody);
await _modeler.ExtrudeAsync(sBody, depth: 30); await _modeler.ExtrudeAsync(sBody, depth: 30);
var before = (await _query.GetPartInfoAsync()).Volume; var before = (await _query.GetPartInfoAsync()).Volume;
Assert.True(before > 0); Assert.InRange(before, 11250 * 0.95, 11250 * 1.05); // L-уголок 375·30
// Ребро-косынка: разомкнутый отрезок-диагональ во внутреннем углу, на XOZ (Y=0). // Ребро-косынка: разомкнутый отрезок во внутреннем углу, на XOZ (Y=0).
// side=up (ортогонально, +Y), несимметрично → растёт от Y=0 вглубь тела на 5 мм. // Контур висит в зазоре (не касается полок); side=left, несимметрично → толщина 5 мм.
var sRib = await _modeler.OpenSketchAsync(BasePlane.XOZ); var sRib = await _modeler.OpenSketchAsync(BasePlane.XOZ);
await _modeler.AddLineAsync(sRib, 25, 10, 10, 25); // висит в пустом углу, не касаясь полок await _modeler.AddLineAsync(sRib, 25, 10, 10, 25); // висит в пустом углу, не касаясь полок
await _modeler.CloseSketchAsync(sRib); await _modeler.CloseSketchAsync(sRib);