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