diff --git a/src/Kompas.Mcp.Core/Modeling/PartModeler.Features.cs b/src/Kompas.Mcp.Core/Modeling/PartModeler.Features.cs index 39be616..ce3b205 100644 --- a/src/Kompas.Mcp.Core/Modeling/PartModeler.Features.cs +++ b/src/Kompas.Mcp.Core/Modeling/PartModeler.Features.cs @@ -237,7 +237,8 @@ public sealed partial class PartModeler public Task RibAsync(int sketchId, double thickness, string side = "up", bool symmetric = true, double angle = 0, CancellationToken ct = default) => _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 sketch = RequireSketch(sketchId); CloseSketchCore(sketch); // эскиз должен быть закрыт перед операцией diff --git a/src/Kompas.Mcp.Host/Tools/FeatureTools.cs b/src/Kompas.Mcp.Host/Tools/FeatureTools.cs index 9fd020b..5ded76b 100644 --- a/src/Kompas.Mcp.Host/Tools/FeatureTools.cs +++ b/src/Kompas.Mcp.Host/Tools/FeatureTools.cs @@ -105,7 +105,7 @@ public sealed class FeatureTools(KompasSession session, PartModeler modeler) } [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 Rib(int sketchId, double thickness, string side = "up", bool symmetric = true, double angle = 0) { await session.ConnectAsync(); diff --git a/tests/Kompas.Mcp.Tests/Integration/FeatureOpsTests.cs b/tests/Kompas.Mcp.Tests/Integration/FeatureOpsTests.cs index 5b919f5..5429d0c 100644 --- a/tests/Kompas.Mcp.Tests/Integration/FeatureOpsTests.cs +++ b/tests/Kompas.Mcp.Tests/Integration/FeatureOpsTests.cs @@ -63,10 +63,10 @@ public sealed class FeatureOpsTests await _modeler.CloseSketchAsync(sBody); await _modeler.ExtrudeAsync(sBody, depth: 30); 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). - // side=up (ортогонально, +Y), несимметрично → растёт от Y=0 вглубь тела на 5 мм. + // Ребро-косынка: разомкнутый отрезок во внутреннем углу, на XOZ (Y=0). + // Контур висит в зазоре (не касается полок); side=left, несимметрично → толщина 5 мм. var sRib = await _modeler.OpenSketchAsync(BasePlane.XOZ); await _modeler.AddLineAsync(sRib, 25, 10, 10, 25); // висит в пустом углу, не касаясь полок await _modeler.CloseSketchAsync(sRib);