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); }