Files
kompas3d-mcp/src/Kompas.Mcp.Core/Drawings/CircularObjectMatch.cs
T
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

45 lines
2.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace Kompas.Mcp.Core.Drawings;
/// <summary>Геометрия окружности-кандидата вида (центр + радиус, локальная СК вида, мм).</summary>
public sealed record CircleCandidate(double Xc, double Yc, double Radius);
/// <summary>
/// Чистый отбор окружности проекционного вида по ключу (центр + радиус) для ассоциативной привязки
/// размера. Выделен из COM-перечисления ради unit-тестов.
/// </summary>
public static class CircularObjectMatch
{
/// <summary>
/// Индекс единственной окружности из <paramref name="candidates"/>, чей центр и радиус совпадают с
/// ключом (<paramref name="keyX"/>,<paramref name="keyY"/>,<paramref name="keyR"/>) в пределах
/// <paramref name="tol"/> (мм): <c>dist(центр,ключ) ≤ tol</c> И <c>|R keyR| ≤ tol</c>.
/// </summary>
/// <exception cref="InvalidOperationException">Нет подходящих (0) или неоднозначно (&gt;1).</exception>
public static int SelectMatchIndex(IReadOnlyList<CircleCandidate> candidates,
double keyX, double keyY, double keyR, double tol)
{
ArgumentNullException.ThrowIfNull(candidates);
var matches = new List<int>();
for (var i = 0; i < candidates.Count; i++)
{
var c = candidates[i];
var dx = c.Xc - keyX;
var dy = c.Yc - keyY;
if (Math.Sqrt(dx * dx + dy * dy) <= tol && Math.Abs(c.Radius - keyR) <= tol)
matches.Add(i);
}
return matches.Count switch
{
1 => matches[0],
0 => throw new InvalidOperationException(
$"Окружность не найдена рядом с ({keyX},{keyY}) R≈{keyR} (допуск {tol} мм). " +
"Проверьте координаты/радиус и наличие окружности на этом виде."),
_ => throw new InvalidOperationException(
$"Неоднозначный выбор окружности у ({keyX},{keyY}) R≈{keyR}: подходит {matches.Count}. " +
"Уточните координаты/радиус."),
};
}
}