5eee7ad1af
Веха СБОРКИ, инкремент 1. Новый AssemblyService (API7, паттерн HoleService): IParts7.AddFromFile → Placement.SetOrigin → RebuildModel. Новый AssemblyTools (MCP-инструмент assembly_add_component), регистрация в DI. Ключевая находка: UpdatePlacement возвращает FALSE для вручную позиционируемого компонента (не ошибка), позицию применяет SetOrigin + RebuildModel(true). Валидация — чистый AssemblyValidation (расширение .m3d/.a3d, нормализация пути, конечность координат). RequireActiveAssembly — раздельные ошибки по типу документа. Тесты: +14 unit (AssemblyValidation), +3 integration (AssemblyTests: вставка в origin, позиционирование со сдвигом, отклонение не-сборки). Итого 83 unit + 53 integration = 136 зелёных. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
39 lines
2.1 KiB
C#
39 lines
2.1 KiB
C#
namespace Kompas.Mcp.Core.Assemblies;
|
|
|
|
/// <summary>
|
|
/// Чистые валидаторы операций сборки (без COM) — выделены для unit-тестов.
|
|
/// </summary>
|
|
public static class AssemblyValidation
|
|
{
|
|
/// <summary>Допустимые расширения файла-источника компонента: деталь (.m3d) и сборка (.a3d).</summary>
|
|
private static readonly HashSet<string> AllowedExtensions =
|
|
new(StringComparer.OrdinalIgnoreCase) { ".m3d", ".a3d" };
|
|
|
|
/// <summary>
|
|
/// Нормализовать путь к файлу компонента: обрезать пробелы, проверить непустоту и расширение
|
|
/// (.m3d/.a3d, без учёта регистра), вернуть абсолютный путь. Существование файла НЕ проверяет
|
|
/// (это делает сервис на реальной ФС).
|
|
/// </summary>
|
|
public static string NormalizeComponentPath(string? path)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(path))
|
|
throw new ArgumentException("Путь к файлу компонента не задан.", nameof(path));
|
|
|
|
var trimmed = path.Trim();
|
|
var ext = Path.GetExtension(trimmed);
|
|
if (!AllowedExtensions.Contains(ext))
|
|
throw new ArgumentException(
|
|
$"Недопустимое расширение файла компонента '{ext}'. Ожидается .m3d (деталь) или .a3d (сборка).",
|
|
nameof(path));
|
|
|
|
return Path.GetFullPath(trimmed);
|
|
}
|
|
|
|
/// <summary>Проверить, что координаты вставки конечны (отсекает NaN/Infinity).</summary>
|
|
public static void RequireFinitePosition(double x, double y, double z)
|
|
{
|
|
if (!double.IsFinite(x) || !double.IsFinite(y) || !double.IsFinite(z))
|
|
throw new ArgumentException("Координаты вставки компонента должны быть конечными числами (не NaN/Infinity).");
|
|
}
|
|
}
|