feat(query): инструмент get_part_info (МЦХ детали)

QueryService через IMassInertiaParam7: объём, масса, площадь, центр масс.
Единицы выставляются детерминированно (мм/кг) через LengthUnits/MassUnits —
иначе КОМПАС отдаёт значения в единицах отображения МЦХ (по умолчанию см/г).
Calculate() возвращает FALSE даже при успехе → опираемся на свойство Actual.

Интеграционный тест: цилиндр R10×H20 → V≈6283 мм³, S≈1885 мм², m≈0.049 кг, Zc=10 мм.
Находка задокументирована в OPEN_QUESTIONS; презентация обновлена (19 инструментов, 14 тестов).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@
This commit is contained in:
2026-05-26 09:35:57 +03:00
parent 60cf26f739
commit b73748f84b
7 changed files with 172 additions and 5 deletions
+12
View File
@@ -0,0 +1,12 @@
namespace Kompas.Mcp.Core.Query;
/// <summary>Массово-центровочные характеристики детали (в единицах документа, по умолчанию мм).</summary>
public sealed record PartInfo
{
public required double Volume { get; init; } // объём, мм³
public required double Mass { get; init; } // масса, кг (по материалу/плотности)
public required double Area { get; init; } // площадь поверхности, мм²
public required double CenterX { get; init; } // центр масс, X
public required double CenterY { get; init; }
public required double CenterZ { get; init; }
}
+61
View File
@@ -0,0 +1,61 @@
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Kompas.Mcp.Core.Threading;
using Kompas6Constants;
using KompasAPI7;
namespace Kompas.Mcp.Core.Query;
/// <summary>Запросы к активной 3D-модели: массово-центровочные характеристики.</summary>
[SupportedOSPlatform("windows")]
public sealed class QueryService
{
private readonly KompasSession _session;
private readonly KompasDispatcher _dispatcher;
public QueryService(KompasSession session, KompasDispatcher dispatcher)
{
_session = session ?? throw new ArgumentNullException(nameof(session));
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
}
/// <summary>Рассчитать и вернуть МЦХ активной детали (объём, масса, площадь, центр масс).</summary>
public Task<PartInfo> GetPartInfoAsync(CancellationToken ct = default)
=> _dispatcher.InvokeAsync(() =>
{
var doc3d = _session.Application.ActiveDocument as IKompasDocument3D
?? throw new InvalidOperationException("Активный документ не является 3D-моделью.");
var part = doc3d.TopPart
?? throw new InvalidOperationException("Не удалось получить вершинный компонент.");
try
{
var mass = (IMassInertiaParam7)part;
// Детерминированные единицы: длина — мм, масса — кг. Иначе КОМПАС вернёт
// значения в единицах отображения МЦХ (по умолчанию см/г), что зависит от настроек.
mass.LengthUnits = ksLengthUnitsEnum.ksLUnMM;
mass.MassUnits = ksMassUnitsEnum.ksMUnKG;
// Calculate() возвращает FALSE и при успехе (когда расчёт уже актуален),
// поэтому ориентируемся на свойство Actual, а не на возвращаемое значение.
mass.Calculate();
if (!mass.Actual)
throw new InvalidOperationException("МЦХ не рассчитаны (модель пуста или не перестроена?).");
return new PartInfo
{
Volume = mass.Volume,
Mass = mass.Mass,
Area = mass.Area,
CenterX = mass.Xc,
CenterY = mass.Yc,
CenterZ = mass.Zc,
};
}
finally
{
// part и его QI-приведение mass — один RCW; release один раз.
if (Marshal.IsComObject(part)) Marshal.ReleaseComObject(part);
}
}, ct);
}
+2
View File
@@ -1,6 +1,7 @@
using Kompas.Mcp.Core;
using Kompas.Mcp.Core.Documents;
using Kompas.Mcp.Core.Modeling;
using Kompas.Mcp.Core.Query;
using Kompas.Mcp.Core.Threading;
using Kompas.Mcp.Core.Vision;
using Microsoft.Extensions.DependencyInjection;
@@ -19,6 +20,7 @@ builder.Services.AddSingleton<KompasSession>();
builder.Services.AddSingleton<DocumentService>();
builder.Services.AddSingleton<PartModeler>();
builder.Services.AddSingleton<SnapshotService>();
builder.Services.AddSingleton<QueryService>();
// MCP-сервер поверх stdio; инструменты находятся по атрибутам в этой сборке.
builder.Services
+21
View File
@@ -0,0 +1,21 @@
using System.ComponentModel;
using Kompas.Mcp.Core;
using Kompas.Mcp.Core.Query;
using ModelContextProtocol.Server;
namespace Kompas.Mcp.Host.Tools;
/// <summary>Инструменты запросов к модели.</summary>
[McpServerToolType]
public sealed class QueryTools(KompasSession session, QueryService query)
{
[McpServerTool(Name = "get_part_info")]
[Description("Массово-центровочные характеристики активной детали: объём (мм³), масса (кг), площадь (мм²) и центр масс. Полезно для числовой проверки построения.")]
public async Task<string> GetPartInfo()
{
await session.ConnectAsync();
var i = await query.GetPartInfoAsync();
return $"Объём: {i.Volume:F2} мм³; масса: {i.Mass:F4} кг; площадь: {i.Area:F2} мм²; " +
$"центр масс: ({i.CenterX:F2}, {i.CenterY:F2}, {i.CenterZ:F2}).";
}
}