using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Kompas.Mcp.Core.Threading;
using Kompas6Constants;
using KompasAPI7;
namespace Kompas.Mcp.Core.Query;
/// Запросы к активной 3D-модели: массово-центровочные характеристики.
[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));
}
/// Рассчитать и вернуть МЦХ активной детали (объём, масса, площадь, центр масс).
public Task 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);
}