using System.Runtime.Versioning; using Kompas.Mcp.Core.Threading; using Kompas6Constants; using KompasAPI7; namespace Kompas.Mcp.Core.Drawings; /// /// Операции с 2D-чертежами через API7 (IViews). Все вызовы — на STA-потоке /// . /// [SupportedOSPlatform("windows")] public sealed class DrawingService { private readonly KompasSession _session; private readonly KompasDispatcher _dispatcher; public DrawingService(KompasSession session, KompasDispatcher dispatcher) { _session = session ?? throw new ArgumentNullException(nameof(session)); _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher)); } /// /// Создать на активном чертеже стандартные ассоциативные виды (спереди/сверху/слева) сохранённой /// 3D-модели (.m3d/.a3d). Главный вид привязывается к точке /// (,) листа, мм; масштаб — . /// public Task CreateStandardViewsAsync(string partFilePath, double scale, double x, double y, CancellationToken ct = default) => _dispatcher.InvokeAsync(() => CreateStandardViewsCore(partFilePath, scale, x, y), ct); // Стандартная тройка проекций: ksPtFront=1, ksPtUp=3, ksPtLeft=5 (ksRelativeProjectionTypeEnum). private static readonly object[] StandardProjections = { 1, 3, 5 }; private const int ExpectedCreated = 3; private const double GapMm = 20; // зазоры между видами (DX=DY) private DrawingViewsResult CreateStandardViewsCore(string partFilePath, double scale, double x, double y) { var path = DrawingValidation.NormalizeModelPath(partFilePath); DrawingValidation.RequireScale(scale); if (!double.IsFinite(x) || !double.IsFinite(y)) throw new ArgumentException("Координаты привязки вида должны быть конечными числами."); if (!File.Exists(path)) throw new FileNotFoundException($"Файл модели не найден: {path}", path); if (new FileInfo(path).Length == 0) throw new InvalidOperationException($"Файл модели пуст (не сохранён?): {path}"); var views = RequireActiveDrawingViews(); var before = views.Count; if (!views.AddStandartViews(path, "#Спереди", StandardProjections, x, y, scale, GapMm, GapMm)) throw new InvalidOperationException( $"AddStandartViews вернул FALSE — виды не созданы (файл модели или проекция недоступны): {path}"); var created = views.Count - before; if (created != ExpectedCreated) throw new InvalidOperationException( $"Ожидалось {ExpectedCreated} вида, создано {created} (было {before}, стало {views.Count})."); // Гарантия непустоты: у спроецированных видов должна быть геометрия (иначе модель не // спроецировалась — пустые виды). Системный вид #0 имеет ObjectCount 0, поэтому суммируем. if (TotalObjectCount(views) <= 0) throw new InvalidOperationException( "Стандартные виды созданы, но пусты (модель не спроецировалась). Проверьте файл модели."); return new DrawingViewsResult { Created = created, Total = views.Count }; } private IViews RequireActiveDrawingViews() { var doc = _session.Application.ActiveDocument ?? throw new InvalidOperationException("Нет активного документа. Создайте чертёж: document_create drawing."); if (doc.DocumentType != DocumentTypeEnum.ksDocumentDrawing) throw new InvalidOperationException( $"Активный документ не является чертежом (тип: {doc.DocumentType}). Создайте чертёж: document_create drawing."); if (doc is not IKompasDocument2D doc2d) throw new InvalidOperationException("Активный документ не приводится к IKompasDocument2D."); return doc2d.ViewsAndLayersManager?.Views ?? throw new InvalidOperationException("Не удалось получить коллекцию видов чертежа."); } private static int TotalObjectCount(IViews views) { int sum = 0; foreach (var o in views) if (o is IView v) sum += v.ObjectCount; return sum; } }