feat(drawing): формат и ориентация листа (drawing_set_sheet_format)
Задать формат (A0–A5/user) и ориентацию (книжная/альбомная) листа чертежа через API7 ILayoutSheet.Format (ISheetFormat). Стандартный формат — размеры авто; user — явные width/height (landscape игнорируется, ориентация из соотношения сторон). - DrawingService.SetSheetFormatAsync + RequireLayoutSheet - PaperFormat (enum + Parse/ToKompas/FromKompas), SheetFormatResult - DrawingValidation.ValidateFormatDimensions (user: >0; стандартный: размеры запрещены) - 19 unit + 7 интеграционных тестов (всего 304 зелёных), сборка Release чистая Спайк подтвердил: дефолт A4 portrait; стандартный формат пересчитывает W/H авто (A3 landscape→420×297); user применяет width/height. Ревью спека pi/glm-5.1 + pi/kimi-k2.6 учтено (FromKompas для дружелюбного имени, запрет размеров у стандартного, sheetNumber>0, landscape игнорируется для user). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -84,6 +84,63 @@ public sealed class DrawingService
|
||||
?? throw new InvalidOperationException("У листа оформления нет основной надписи (Stamp).");
|
||||
}
|
||||
|
||||
/// <summary>Лист оформления чертежа по номеру (1-based) с диагностикой (номер > 0, лист существует).</summary>
|
||||
private ILayoutSheet RequireLayoutSheet(int sheetNumber)
|
||||
{
|
||||
if (sheetNumber <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(sheetNumber), "Номер листа должен быть > 0.");
|
||||
var doc2d = RequireActiveDrawing();
|
||||
var sheets = doc2d.LayoutSheets
|
||||
?? throw new InvalidOperationException("Не удалось получить листы оформления чертежа.");
|
||||
return sheets.ItemByNumber[sheetNumber] as ILayoutSheet
|
||||
?? throw new InvalidOperationException($"На чертеже нет листа оформления #{sheetNumber}.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Задать формат (<paramref name="format"/>: A0–A5 или user) и ориентацию листа
|
||||
/// <paramref name="sheetNumber"/> активного чертежа. Для стандартного формата размеры авто
|
||||
/// (<paramref name="width"/>/<paramref name="height"/> запрещены); для user — заданные width/height (мм),
|
||||
/// при этом <paramref name="landscape"/> игнорируется (ориентация из соотношения сторон). Возвращает
|
||||
/// итоговый формат, размеры и ориентацию (read-back из COM).
|
||||
/// </summary>
|
||||
public Task<SheetFormatResult> SetSheetFormatAsync(PaperFormat format, bool landscape, double width,
|
||||
double height, int sheetNumber = 1, CancellationToken ct = default)
|
||||
=> _dispatcher.InvokeAsync(() => SetSheetFormatCore(format, landscape, width, height, sheetNumber), ct);
|
||||
|
||||
private SheetFormatResult SetSheetFormatCore(PaperFormat format, bool landscape, double width,
|
||||
double height, int sheetNumber)
|
||||
{
|
||||
DrawingValidation.ValidateFormatDimensions(format, width, height);
|
||||
|
||||
var sheet = RequireLayoutSheet(sheetNumber);
|
||||
var fmt = sheet.Format
|
||||
?? throw new InvalidOperationException("У листа недоступен формат (Format == null).");
|
||||
fmt.Format = PaperFormats.ToKompas(format);
|
||||
if (format == PaperFormat.User)
|
||||
{
|
||||
// Для пользовательского ориентация задаётся соотношением width/height — VerticalOrientation не трогаем.
|
||||
fmt.FormatWidth = width;
|
||||
fmt.FormatHeight = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt.VerticalOrientation = !landscape; // стандартный: размеры авто по формату+ориентации
|
||||
}
|
||||
// FormatMultiplicity оставляем на COM-дефолте (1).
|
||||
if (!sheet.Update())
|
||||
throw new InvalidOperationException("ILayoutSheet.Update вернул FALSE — формат листа не задан.");
|
||||
|
||||
var fmt2 = sheet.Format
|
||||
?? throw new InvalidOperationException("Формат листа недоступен после Update (Format == null).");
|
||||
return new SheetFormatResult
|
||||
{
|
||||
Format = PaperFormats.FromKompas(fmt2.Format).ToString(),
|
||||
Width = fmt2.FormatWidth,
|
||||
Height = fmt2.FormatHeight,
|
||||
Landscape = !fmt2.VerticalOrientation,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Поставить линейный размер на виде активного чертежа между точками (x1,y1)-(x2,y2) в ЛОКАЛЬНОЙ
|
||||
/// СК вида (мм); размерная линия проходит через (x3,y3). <paramref name="viewNumber"/> — номер вида
|
||||
|
||||
@@ -55,6 +55,26 @@ public static class DrawingValidation
|
||||
throw new ArgumentException("Текст не должен быть пустым.", paramName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверить размеры формата листа: для <see cref="PaperFormat.User"/> — ширина и высота оба
|
||||
/// конечны и > 0; для стандартного формата — оба должны быть 0 (размеры авто, задавать нельзя).
|
||||
/// </summary>
|
||||
public static void ValidateFormatDimensions(PaperFormat format, double width, double height)
|
||||
{
|
||||
if (format == PaperFormat.User)
|
||||
{
|
||||
if (!double.IsFinite(width) || width <= 0 || !double.IsFinite(height) || height <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(width),
|
||||
"Для format=user ширина и высота должны быть конечными и > 0.");
|
||||
}
|
||||
else if (width != 0 || height != 0)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Ширина/высота задаются только для format=user; для стандартного формата размеры авто (передайте 0).",
|
||||
nameof(width));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Минимальное расстояние между выносными точками линейного размера (мм).</summary>
|
||||
private const double MinPointDistance = 1e-7;
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
using Kompas6Constants;
|
||||
|
||||
namespace Kompas.Mcp.Core.Drawings;
|
||||
|
||||
/// <summary>Формат листа чертежа (обёртка над <see cref="ksDocumentFormatEnum"/>).</summary>
|
||||
public enum PaperFormat
|
||||
{
|
||||
/// <summary>A0 (841×1189 мм).</summary>
|
||||
A0,
|
||||
/// <summary>A1 (594×841 мм).</summary>
|
||||
A1,
|
||||
/// <summary>A2 (420×594 мм).</summary>
|
||||
A2,
|
||||
/// <summary>A3 (297×420 мм).</summary>
|
||||
A3,
|
||||
/// <summary>A4 (210×297 мм).</summary>
|
||||
A4,
|
||||
/// <summary>A5 (148×210 мм).</summary>
|
||||
A5,
|
||||
/// <summary>Пользовательский формат с явной шириной/высотой.</summary>
|
||||
User,
|
||||
}
|
||||
|
||||
/// <summary>Маппинг формата листа ↔ перечисление КОМПАС и разбор строки.</summary>
|
||||
public static class PaperFormats
|
||||
{
|
||||
public static ksDocumentFormatEnum ToKompas(PaperFormat format) => format switch
|
||||
{
|
||||
PaperFormat.A0 => ksDocumentFormatEnum.ksFormatA0,
|
||||
PaperFormat.A1 => ksDocumentFormatEnum.ksFormatA1,
|
||||
PaperFormat.A2 => ksDocumentFormatEnum.ksFormatA2,
|
||||
PaperFormat.A3 => ksDocumentFormatEnum.ksFormatA3,
|
||||
PaperFormat.A4 => ksDocumentFormatEnum.ksFormatA4,
|
||||
PaperFormat.A5 => ksDocumentFormatEnum.ksFormatA5,
|
||||
PaperFormat.User => ksDocumentFormatEnum.ksFormatUser,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(format), format, "Неизвестный формат листа."),
|
||||
};
|
||||
|
||||
/// <summary>Обратный маппинг (для read-back дружелюбного имени).</summary>
|
||||
public static PaperFormat FromKompas(ksDocumentFormatEnum format) => format switch
|
||||
{
|
||||
ksDocumentFormatEnum.ksFormatA0 => PaperFormat.A0,
|
||||
ksDocumentFormatEnum.ksFormatA1 => PaperFormat.A1,
|
||||
ksDocumentFormatEnum.ksFormatA2 => PaperFormat.A2,
|
||||
ksDocumentFormatEnum.ksFormatA3 => PaperFormat.A3,
|
||||
ksDocumentFormatEnum.ksFormatA4 => PaperFormat.A4,
|
||||
ksDocumentFormatEnum.ksFormatA5 => PaperFormat.A5,
|
||||
ksDocumentFormatEnum.ksFormatUser => PaperFormat.User,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(format), format, "Неизвестный формат листа КОМПАС."),
|
||||
};
|
||||
|
||||
/// <summary>Разобрать строку формата (A0..A5 / user, регистр/пробелы) в <see cref="PaperFormat"/>.</summary>
|
||||
public static PaperFormat Parse(string value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(value);
|
||||
return value.Trim().ToLowerInvariant() switch
|
||||
{
|
||||
"a0" => PaperFormat.A0,
|
||||
"a1" => PaperFormat.A1,
|
||||
"a2" => PaperFormat.A2,
|
||||
"a3" => PaperFormat.A3,
|
||||
"a4" => PaperFormat.A4,
|
||||
"a5" => PaperFormat.A5,
|
||||
"user" or "custom" or "пользовательский" => PaperFormat.User,
|
||||
_ => throw new ArgumentException(
|
||||
$"Неизвестный формат листа '{value}'. Допустимо: A0, A1, A2, A3, A4, A5, user.",
|
||||
nameof(value)),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Kompas.Mcp.Core.Drawings;
|
||||
|
||||
/// <summary>Результат задания формата листа чертежа (read-back из COM).</summary>
|
||||
public sealed record SheetFormatResult
|
||||
{
|
||||
/// <summary>Итоговый формат («A0»…«A5» или «User»).</summary>
|
||||
public required string Format { get; init; }
|
||||
|
||||
/// <summary>Ширина листа, мм.</summary>
|
||||
public required double Width { get; init; }
|
||||
|
||||
/// <summary>Высота листа, мм.</summary>
|
||||
public required double Height { get; init; }
|
||||
|
||||
/// <summary>Альбомная ориентация (true) либо книжная (false).</summary>
|
||||
public required bool Landscape { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user