From 8c778a449d617eb054011a158ac3a7d3a53ea91a Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Tue, 26 May 2026 10:03:53 +0300 Subject: [PATCH] =?UTF-8?q?@=20feat(query):=20=D0=B3=D0=B0=D0=B1=D0=B0?= =?UTF-8?q?=D1=80=D0=B8=D1=82=D1=8B=20=D0=B4=D0=B5=D1=82=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=20(get=5Fbounding=5Fbox)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QueryService.GetBoundingBoxAsync через API5 ksPart.GetGabarit(full=false) → габаритный параллелепипед (мм) + размеры по осям. Помогает агенту оценить протяжённость модели и подбирать точки для select-by-point (грани/рёбра). Новый инструмент get_bounding_box; запись BoundingBox. Тест: цилиндр R10×H20 → X,Y ∈ [-10;10], Z ∈ [0;20] (расширен QueryTests). Презентация: 26 инструментов. Co-Authored-By: Claude Opus 4.7 @ --- docs/presentation.html | 8 +++--- src/Kompas.Mcp.Core/Query/BoundingBox.cs | 16 +++++++++++ src/Kompas.Mcp.Core/Query/QueryService.cs | 28 +++++++++++++++++++ src/Kompas.Mcp.Host/Tools/QueryTools.cs | 10 +++++++ .../Integration/QueryTests.cs | 8 ++++++ 5 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 src/Kompas.Mcp.Core/Query/BoundingBox.cs diff --git a/docs/presentation.html b/docs/presentation.html index 3568828..d12625b 100644 --- a/docs/presentation.html +++ b/docs/presentation.html @@ -125,7 +125,7 @@
- Статус: v1 работает — цикл эскиз→операции→снимок через MCP (25 инструментов) + Статус: v1 работает — цикл эскиз→операции→снимок через MCP (26 инструментов)

КОМПАС-3D MCP-сервер
управление CAD языком LLM

MCP-сервер, который превращает операции КОМПАС-3D — создание документов, эскизы, 3D-операции, параметры — в инструменты для языковой модели. Под капотом — @@ -282,15 +282,15 @@

Инструменты v1 ГОТОВО

-

25 инструментов, отдаются по MCP-протоколу

+

26 инструментов, отдаются по MCP-протоколу

  • System: connect · status · set_visible
  • Documents: create · open · save · save_as · close · active
  • Sketch: create · create_on_face · add line/circle/rectangle/axis · close
  • Features: extrude · revolve · fillet_edge/chamfer_edge 🆕 · rebuild
  • Vision: model_snapshot 👁️
  • -
  • Query: get_part_info (объём/масса/площадь/центр масс)
  • -
  • Query: select_face · list_bodies (далее)
  • +
  • Query: get_part_info · get_bounding_box 🆕
  • +
  • Query: list_bodies · list_faces (далее)
diff --git a/src/Kompas.Mcp.Core/Query/BoundingBox.cs b/src/Kompas.Mcp.Core/Query/BoundingBox.cs new file mode 100644 index 0000000..fd625d7 --- /dev/null +++ b/src/Kompas.Mcp.Core/Query/BoundingBox.cs @@ -0,0 +1,16 @@ +namespace Kompas.Mcp.Core.Query; + +/// Габаритный параллелепипед детали (мировые координаты модели, мм). +public sealed record BoundingBox +{ + public required double MinX { get; init; } + public required double MinY { get; init; } + public required double MinZ { get; init; } + public required double MaxX { get; init; } + public required double MaxY { get; init; } + public required double MaxZ { get; init; } + + public double SizeX => MaxX - MinX; + public double SizeY => MaxY - MinY; + public double SizeZ => MaxZ - MinZ; +} diff --git a/src/Kompas.Mcp.Core/Query/QueryService.cs b/src/Kompas.Mcp.Core/Query/QueryService.cs index ea835be..734034a 100644 --- a/src/Kompas.Mcp.Core/Query/QueryService.cs +++ b/src/Kompas.Mcp.Core/Query/QueryService.cs @@ -60,4 +60,32 @@ public sealed class QueryService if (Marshal.IsComObject(part)) Marshal.ReleaseComObject(part); } }, ct); + + /// Габаритный параллелепипед активной детали (по телам), мм. + public Task GetBoundingBoxAsync(CancellationToken ct = default) + => _dispatcher.InvokeAsync(() => + { + var doc3d = _session.Kompas.ActiveDocument3D() as ksDocument3D + ?? throw new InvalidOperationException("Нет активного 3D-документа."); + var part = doc3d.GetPart((short)Part_Type.pTop_Part) as ksPart + ?? throw new InvalidOperationException("Не удалось получить вершинный компонент (ksPart)."); + try + { + // full=false → только тела (без вспомогательной геометрии); customizable игнорируется. + if (!part.GetGabarit(false, false, + out double x1, out double y1, out double z1, + out double x2, out double y2, out double z2)) + throw new InvalidOperationException("GetGabarit вернул FALSE (модель пуста?)."); + + return new BoundingBox + { + MinX = Math.Min(x1, x2), MinY = Math.Min(y1, y2), MinZ = Math.Min(z1, z2), + MaxX = Math.Max(x1, x2), MaxY = Math.Max(y1, y2), MaxZ = Math.Max(z1, z2), + }; + } + finally + { + if (Marshal.IsComObject(part)) Marshal.ReleaseComObject(part); + } + }, ct); } diff --git a/src/Kompas.Mcp.Host/Tools/QueryTools.cs b/src/Kompas.Mcp.Host/Tools/QueryTools.cs index 2cc4b3f..a24663c 100644 --- a/src/Kompas.Mcp.Host/Tools/QueryTools.cs +++ b/src/Kompas.Mcp.Host/Tools/QueryTools.cs @@ -18,4 +18,14 @@ public sealed class QueryTools(KompasSession session, QueryService query) return $"Объём: {i.Volume:F2} мм³; масса: {i.Mass:F4} кг; площадь: {i.Area:F2} мм²; " + $"центр масс: ({i.CenterX:F2}, {i.CenterY:F2}, {i.CenterZ:F2})."; } + + [McpServerTool(Name = "get_bounding_box")] + [Description("Габариты активной детали: координаты габаритного параллелепипеда (мм) и его размеры. Помогает оценить протяжённость модели и подобрать точки для выбора граней/рёбер.")] + public async Task GetBoundingBox() + { + await session.ConnectAsync(); + var b = await query.GetBoundingBoxAsync(); + return $"Габарит: X [{b.MinX:F2}; {b.MaxX:F2}], Y [{b.MinY:F2}; {b.MaxY:F2}], Z [{b.MinZ:F2}; {b.MaxZ:F2}]; " + + $"размеры (Д×Ш×В): {b.SizeX:F2} × {b.SizeY:F2} × {b.SizeZ:F2} мм."; + } } diff --git a/tests/Kompas.Mcp.Tests/Integration/QueryTests.cs b/tests/Kompas.Mcp.Tests/Integration/QueryTests.cs index 942da2d..b390c1c 100644 --- a/tests/Kompas.Mcp.Tests/Integration/QueryTests.cs +++ b/tests/Kompas.Mcp.Tests/Integration/QueryTests.cs @@ -51,6 +51,14 @@ public sealed class QueryTests // Масса стального цилиндра (плотность ≈ 7.856 г/см³): V[см³]·ρ ≈ 6.283·7.856 ≈ 49.36 г = 0.0494 кг. Assert.InRange(info.Mass, 0.045, 0.055); + + // Габарит цилиндра R10×H20 на XOY: X,Y ∈ [-10;10], Z ∈ [0;20]. + var bb = await _query.GetBoundingBoxAsync(); + Assert.InRange(bb.MinX, -10.1, -9.9); + Assert.InRange(bb.MaxX, 9.9, 10.1); + Assert.InRange(bb.MinZ, -0.1, 0.1); + Assert.InRange(bb.MaxZ, 19.9, 20.1); + Assert.InRange(bb.SizeZ, 19.9, 20.1); } finally {