v1 · готово ✓
Цикл моделирования
Документы, эскизы, выдавливание/вырез, снимок модели — работает
-
v2 · в работе
Операции и выборка
Эскиз на грани ✓ · далее: вращение, скругление/фаска, массивы, список тел
+
v2 · в работе
Операции и выборка
Эскиз на грани ✓ · вращение ✓ · далее: скругление/фаска, массивы, список тел
v3
Параметрика
Переменные IVariable7, свойства IPropertyMng, формулы
v4
2D-черчение
Виды, размеры, тексты, штриховки; спецификации
v5
Сборки и экспорт
Компоненты, сопряжения, конвертеры (STEP), HTTP/SSE-транспорт
diff --git a/src/Kompas.Mcp.Core/Modeling/PartModeler.cs b/src/Kompas.Mcp.Core/Modeling/PartModeler.cs
index 5a1e019..f208cba 100644
--- a/src/Kompas.Mcp.Core/Modeling/PartModeler.cs
+++ b/src/Kompas.Mcp.Core/Modeling/PartModeler.cs
@@ -15,6 +15,7 @@ namespace Kompas.Mcp.Core.Modeling;
public sealed class PartModeler : IDisposable
{
private const int MainLineStyle = 1; // системный стиль «Основная»
+ private const int AxisLineStyle = 3; // системный стиль «Осевая» (ось вращения)
private readonly KompasSession _session;
private readonly KompasDispatcher _dispatcher;
@@ -124,6 +125,15 @@ public sealed class PartModeler : IDisposable
Seg(x1, y2, x1, y1);
}, ct);
+ ///
Добавить осевую линию (стиль «осевая») в эскиз — ось для операции вращения.
+ public Task AddAxisAsync(int sketchId, double x1, double y1, double x2, double y2, CancellationToken ct = default)
+ => _dispatcher.InvokeAsync(() =>
+ {
+ var editor = RequireOpenSketch(sketchId).Editor!;
+ if (editor.ksLineSeg(x1, y1, x2, y2, AxisLineStyle) == 0)
+ throw new InvalidOperationException("ksLineSeg (ось) вернул 0 (ось не создана).");
+ }, ct);
+
///
Завершить редактирование эскиза.
public Task CloseSketchAsync(int sketchId, CancellationToken ct = default)
=> _dispatcher.InvokeAsync(() => CloseSketchCore(RequireSketch(sketchId)), ct);
@@ -188,6 +198,54 @@ public sealed class PartModeler : IDisposable
return id;
}, ct);
+ ///
+ /// Вращать эскиз вокруг его осевой линии (добавьте её через AddAxis). —
+ /// вырезание вместо добавления материала. Угол — в градусах.
+ /// Возвращает id операции.
+ ///
+ public Task
RevolveAsync(
+ int sketchId, double angle = 360, bool cut = false, bool forward = true,
+ CancellationToken ct = default)
+ => _dispatcher.InvokeAsync(() =>
+ {
+ if (angle is <= 0 or > 360)
+ throw new ArgumentOutOfRangeException(nameof(angle), "Угол вращения должен быть в (0; 360].");
+ var sketch = RequireSketch(sketchId);
+ CloseSketchCore(sketch); // эскиз должен быть закрыт перед операцией
+
+ var part = GetTopPart();
+ var type = cut ? Obj3dType.o3d_cutRotated : Obj3dType.o3d_bossRotated;
+ var entity = part.NewEntity((short)type) as ksEntity
+ ?? throw new InvalidOperationException("NewEntity операции вращения вернул null.");
+
+ if (cut)
+ {
+ var def = entity.GetDefinition() as ksCutRotatedDefinition
+ ?? throw new InvalidOperationException("GetDefinition() выреза вращением вернул не ksCutRotatedDefinition.");
+ def.directionType = (short)Direction_Type.dtNormal;
+ def.SetThinParam(false, 0, 0, 0);
+ def.SetSideParam(forward, angle);
+ def.SetSketch(sketch.Entity);
+ }
+ else
+ {
+ var def = entity.GetDefinition() as ksBossRotatedDefinition
+ ?? throw new InvalidOperationException("GetDefinition() вращения вернул не ksBossRotatedDefinition.");
+ def.directionType = (short)Direction_Type.dtNormal;
+ def.toroidShapeType = false; // сфероид (сплошное тело), не тороид
+ def.SetThinParam(false, 0, 0, 0);
+ def.SetSideParam(forward, angle);
+ def.SetSketch(sketch.Entity);
+ }
+
+ if (!entity.Create())
+ throw new InvalidOperationException("Create() операции вращения вернул FALSE.");
+
+ var id = _nextId++;
+ _features[id] = entity;
+ return id;
+ }, ct);
+
/// Перестроить документ.
public Task RebuildAsync(CancellationToken ct = default)
=> _dispatcher.InvokeAsync(() =>
diff --git a/src/Kompas.Mcp.Host/Tools/FeatureTools.cs b/src/Kompas.Mcp.Host/Tools/FeatureTools.cs
index 6d6a27b..a1f94eb 100644
--- a/src/Kompas.Mcp.Host/Tools/FeatureTools.cs
+++ b/src/Kompas.Mcp.Host/Tools/FeatureTools.cs
@@ -31,6 +31,30 @@ public sealed class FeatureTools(KompasSession session, PartModeler modeler)
return $"Вырез (cut) создан, id={id}.";
}
+ [McpServerTool(Name = "revolve_boss")]
+ [Description("Вращать эскиз вокруг его осевой линии, добавив материал. Эскиз должен содержать профиль и осевую линию (sketch_add_axis). angle — угол в градусах (по умолчанию 360). Возвращает id операции.")]
+ public async Task RevolveBoss(
+ int sketchId,
+ [Description("Угол вращения, градусы (0..360]")] double angle = 360,
+ [Description("Прямое направление")] bool forward = true)
+ {
+ await session.ConnectAsync();
+ var id = await modeler.RevolveAsync(sketchId, angle, cut: false, forward: forward);
+ return $"Вращение (boss) создано, id={id}.";
+ }
+
+ [McpServerTool(Name = "revolve_cut")]
+ [Description("Вырезать вращением эскиза вокруг его осевой линии. Эскиз должен содержать профиль и осевую линию (sketch_add_axis). angle — угол в градусах (по умолчанию 360). Возвращает id операции.")]
+ public async Task RevolveCut(
+ int sketchId,
+ [Description("Угол вращения, градусы (0..360]")] double angle = 360,
+ [Description("Прямое направление")] bool forward = true)
+ {
+ await session.ConnectAsync();
+ var id = await modeler.RevolveAsync(sketchId, angle, cut: true, forward: forward);
+ return $"Вырез вращением (cut) создан, id={id}.";
+ }
+
[McpServerTool(Name = "rebuild")]
[Description("Перестроить активный документ.")]
public async Task Rebuild()
diff --git a/src/Kompas.Mcp.Host/Tools/SketchTools.cs b/src/Kompas.Mcp.Host/Tools/SketchTools.cs
index 482ba5e..5895405 100644
--- a/src/Kompas.Mcp.Host/Tools/SketchTools.cs
+++ b/src/Kompas.Mcp.Host/Tools/SketchTools.cs
@@ -45,6 +45,15 @@ public sealed class SketchTools(KompasSession session, PartModeler modeler)
return "Отрезок добавлен.";
}
+ [McpServerTool(Name = "sketch_add_axis")]
+ [Description("Добавить осевую линию (ось вращения) в открытый эскиз — нужна для revolve_boss/revolve_cut. Две точки в плоскости эскиза, мм.")]
+ public async Task AddAxis(int sketchId, double x1, double y1, double x2, double y2)
+ {
+ await session.ConnectAsync();
+ await modeler.AddAxisAsync(sketchId, x1, y1, x2, y2);
+ return "Осевая линия добавлена.";
+ }
+
[McpServerTool(Name = "sketch_add_rectangle")]
[Description("Добавить прямоугольник по двум противоположным углам в открытый эскиз (мм).")]
public async Task AddRectangle(int sketchId, double x1, double y1, double x2, double y2)
diff --git a/tests/Kompas.Mcp.Tests/Integration/ModelingTests.cs b/tests/Kompas.Mcp.Tests/Integration/ModelingTests.cs
index bafa373..15c611c 100644
--- a/tests/Kompas.Mcp.Tests/Integration/ModelingTests.cs
+++ b/tests/Kompas.Mcp.Tests/Integration/ModelingTests.cs
@@ -92,6 +92,34 @@ public sealed class ModelingTests
}
}
+ [Fact]
+ public async Task Revolve_rectangle_makes_tube()
+ {
+ await _docs.CreateAsync(KompasDocumentType.Part);
+ try
+ {
+ // Профиль-прямоугольник [10..15]×[0..20] + осевая по локальной оси Y (x=0).
+ // Вращение 360° вокруг оси → труба: внеш. R15, внутр. R10, высота 20.
+ var s = await _modeler.OpenSketchAsync(BasePlane.XOY);
+ await _modeler.AddAxisAsync(s, 0, 0, 0, 20);
+ await _modeler.AddRectangleAsync(s, 10, 0, 15, 20);
+ await _modeler.CloseSketchAsync(s);
+ var rev = await _modeler.RevolveAsync(s, angle: 360);
+ Assert.True(rev > 0);
+ await _modeler.RebuildAsync();
+
+ var info = await _query.GetPartInfoAsync();
+
+ // Объём трубы = π·(15² − 10²)·20 = π·2500 ≈ 7853.98 мм³.
+ var expected = Math.PI * (15 * 15 - 10 * 10) * 20;
+ Assert.InRange(info.Volume, expected * 0.97, expected * 1.03);
+ }
+ finally
+ {
+ await _docs.CloseAsync(save: false);
+ }
+ }
+
[Fact]
public async Task Reset_invalidates_sketch_ids()
{