feat(core): SketchGeometry (маппинги/валидация) + SketchPoint
ArcDirection, PolygonDescribe, RequirePositive, RequireVertexCount, RequirePoints (null + finite). SketchPoint record с JSON x/y. 10 unit-тестов. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
namespace Kompas.Mcp.Core.Modeling;
|
||||
|
||||
/// <summary>Чистые помощники геометрии эскиза: маппинги контракта в параметры COM и валидация.</summary>
|
||||
public static class SketchGeometry
|
||||
{
|
||||
/// <summary>Направление дуги для ksArcByAngle: против часовой → 1, по часовой → -1.</summary>
|
||||
public static short ArcDirection(bool counterClockwise) => (short)(counterClockwise ? 1 : -1);
|
||||
|
||||
/// <summary>describe для ksRegularPolygon: вписанный (вершины на окружности) → false; описанный → true.</summary>
|
||||
public static bool PolygonDescribe(bool inscribed) => !inscribed;
|
||||
|
||||
/// <summary>Требовать строго положительное значение (радиус, полуось).</summary>
|
||||
public static void RequirePositive(double value, string paramName)
|
||||
{
|
||||
if (!(value > 0))
|
||||
throw new ArgumentOutOfRangeException(paramName, value, "Значение должно быть > 0.");
|
||||
}
|
||||
|
||||
/// <summary>Требовать >= 3 вершин для правильного многоугольника.</summary>
|
||||
public static void RequireVertexCount(int count)
|
||||
{
|
||||
if (count < 3)
|
||||
throw new ArgumentOutOfRangeException(nameof(count), count, "Число вершин должно быть >= 3.");
|
||||
}
|
||||
|
||||
/// <summary>Валидировать список точек: не null, минимум <paramref name="min"/>, все координаты конечны.</summary>
|
||||
public static void RequirePoints(IReadOnlyList<(double x, double y)> points, int min, string paramName)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(points, paramName);
|
||||
if (points.Count < min)
|
||||
throw new ArgumentException($"Нужно минимум {min} точек, передано {points.Count}.", paramName);
|
||||
for (int i = 0; i < points.Count; i++)
|
||||
if (!double.IsFinite(points[i].x) || !double.IsFinite(points[i].y))
|
||||
throw new ArgumentException($"Точка [{i}] имеет неконечную координату.", paramName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.ComponentModel;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Kompas.Mcp.Host.Tools;
|
||||
|
||||
/// <summary>Точка эскиза в его плоскости (мм). Элемент списка для ломаной/сплайна.
|
||||
/// JSON-имена зафиксированы lowercase (x/y), чтобы схема инструмента совпадала с контрактом.</summary>
|
||||
public sealed record SketchPoint(
|
||||
[property: JsonPropertyName("x")][property: Description("Координата X в плоскости эскиза, мм")] double X,
|
||||
[property: JsonPropertyName("y")][property: Description("Координата Y в плоскости эскиза, мм")] double Y);
|
||||
@@ -0,0 +1,54 @@
|
||||
using Kompas.Mcp.Core.Modeling;
|
||||
|
||||
namespace Kompas.Mcp.Tests;
|
||||
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class SketchGeometryTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(true, 1)]
|
||||
[InlineData(false, -1)]
|
||||
public void ArcDirection_maps_orientation(bool ccw, int expected)
|
||||
=> Assert.Equal(expected, (int)SketchGeometry.ArcDirection(ccw));
|
||||
|
||||
[Theory]
|
||||
[InlineData(true, false)] // вписанный → describe=false
|
||||
[InlineData(false, true)] // описанный → describe=true
|
||||
public void PolygonDescribe_inverts_inscribed(bool inscribed, bool expected)
|
||||
=> Assert.Equal(expected, SketchGeometry.PolygonDescribe(inscribed));
|
||||
|
||||
[Fact]
|
||||
public void RequirePositive_throws_on_zero_or_negative()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => SketchGeometry.RequirePositive(0, "radius"));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => SketchGeometry.RequirePositive(-1, "radius"));
|
||||
Assert.Null(Record.Exception(() => SketchGeometry.RequirePositive(0.1, "radius")));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequireVertexCount_throws_below_three()
|
||||
{
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => SketchGeometry.RequireVertexCount(2));
|
||||
Assert.Null(Record.Exception(() => SketchGeometry.RequireVertexCount(3)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RequirePoints_throws_on_null()
|
||||
=> Assert.Throws<ArgumentNullException>(
|
||||
() => SketchGeometry.RequirePoints(null!, 2, "points"));
|
||||
|
||||
[Fact]
|
||||
public void RequirePoints_throws_when_too_few()
|
||||
=> Assert.Throws<ArgumentException>(
|
||||
() => SketchGeometry.RequirePoints(new[] { (0.0, 0.0) }, 2, "points"));
|
||||
|
||||
[Fact]
|
||||
public void RequirePoints_throws_on_non_finite()
|
||||
=> Assert.Throws<ArgumentException>(
|
||||
() => SketchGeometry.RequirePoints(new[] { (0.0, 0.0), (double.NaN, 1.0) }, 2, "points"));
|
||||
|
||||
[Fact]
|
||||
public void RequirePoints_passes_on_valid()
|
||||
=> Assert.Null(Record.Exception(
|
||||
() => SketchGeometry.RequirePoints(new[] { (0.0, 0.0), (1.0, 1.0) }, 2, "points")));
|
||||
}
|
||||
Reference in New Issue
Block a user