Files
mikhail 775128484e feat(drawing): ассоциативная привязка диаметрального/радиального размера к окружности вида
Флаг associate у drawing_add_diametral_dimension/drawing_add_radial_dimension:
- associate=false (по умолчанию) — прежний свободный размер (без изменений);
- associate=true — (xc,yc,radius) как ключ поиска спроецированной окружности
  (IDrawingContainer.Circles), привязка через BaseObject; значение Ø/R читается
  из геометрии и обновляется с моделью.

- CircularObjectMatch.SelectMatchIndex (чистый отбор по центру+радиусу, допуск 1 мм;
  бросает при отсутствии/неоднозначности; концентрические разделяются радиусом)
- RequireViewContainers (вид → ISymbols2DContainer + IDrawingContainer), CollectCircles, FindBaseCircle
- 5 unit + 6 интеграционных тестов (всего 278 зелёных), сборка Release чистая

Спайк подтвердил: BaseObject=circle без задания Xc/Yc/Radius → Valid, NominalValue из
геометрии (Ø=20/R=10 для R10). Объём — только окружности (Circles); дуги/угловой/линейный —
далее. Ревью Codex спека учтено (оба контейнера, guard вокруг блока, доказательство
ассоциативности тестом radius=10.3→Ø20, регресс обоих свободных путей).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 21:47:17 +03:00

54 lines
2.1 KiB
C#

using Kompas.Mcp.Core.Drawings;
namespace Kompas.Mcp.Tests;
[Trait("Category", "Unit")]
public sealed class CircularObjectMatchTests
{
private const double Tol = 1.0;
private static IReadOnlyList<CircleCandidate> Candidates(params (double x, double y, double r)[] items)
=> items.Select(i => new CircleCandidate(i.x, i.y, i.r)).ToList();
[Fact]
public void SelectMatchIndex_returns_unique_match()
{
var c = Candidates((0, 0, 10), (50, 20, 5));
// ключ с допустимым отклонением центра и радиуса
Assert.Equal(0, CircularObjectMatch.SelectMatchIndex(c, 0.3, -0.2, 10.3, Tol));
Assert.Equal(1, CircularObjectMatch.SelectMatchIndex(c, 50, 20, 5, Tol));
}
[Fact]
public void SelectMatchIndex_concentric_disambiguated_by_radius()
{
// концентрические R5 и R10 (цековка): ключ R10 выбирает внешнюю, не неоднозначно
var c = Candidates((0, 0, 5), (0, 0, 10));
Assert.Equal(1, CircularObjectMatch.SelectMatchIndex(c, 0, 0, 10, Tol));
Assert.Equal(0, CircularObjectMatch.SelectMatchIndex(c, 0, 0, 5, Tol));
}
[Fact]
public void SelectMatchIndex_throws_when_none_in_tolerance()
{
var c = Candidates((0, 0, 10));
// центр далеко
Assert.Throws<InvalidOperationException>(() => CircularObjectMatch.SelectMatchIndex(c, 100, 100, 10, Tol));
// радиус далеко
Assert.Throws<InvalidOperationException>(() => CircularObjectMatch.SelectMatchIndex(c, 0, 0, 25, Tol));
}
[Fact]
public void SelectMatchIndex_throws_when_ambiguous()
{
// две почти совпадающие окружности в допуске
var c = Candidates((0, 0, 10), (0.2, 0.2, 10.2));
Assert.Throws<InvalidOperationException>(() => CircularObjectMatch.SelectMatchIndex(c, 0, 0, 10, Tol));
}
[Fact]
public void SelectMatchIndex_throws_on_empty()
=> Assert.Throws<InvalidOperationException>(
() => CircularObjectMatch.SelectMatchIndex(Candidates(), 0, 0, 10, Tol));
}