using System.ComponentModel; using Kompas.Mcp.Core; using Kompas.Mcp.Core.Modeling; using ModelContextProtocol.Server; namespace Kompas.Mcp.Host.Tools; /// Инструменты построения эскизов в активной детали. [McpServerToolType] public sealed class SketchTools(KompasSession session, PartModeler modeler) { [McpServerTool(Name = "sketch_create")] [Description("Создать эскиз на базовой плоскости (XOY, XOZ или YOZ) активной детали и открыть его на редактирование. Возвращает id эскиза для последующих sketch_add_* и операций.")] public async Task Create([Description("Плоскость: XOY, XOZ или YOZ")] string plane) { await session.ConnectAsync(); var id = await modeler.OpenSketchAsync(BasePlanes.Parse(plane)); return $"Эскиз создан, id={id}. Добавьте геометрию (sketch_add_*) и завершите sketch_close."; } [McpServerTool(Name = "sketch_create_on_face")] [Description("Создать эскиз на плоской грани детали, выбранной по точке (мировые координаты модели x,y,z в мм), и открыть его на редактирование. Используйте для построения «на грани» поверх уже созданной геометрии: сделайте model_snapshot, прикиньте координаты точки на нужной грани, затем вызовите этот инструмент. Возвращает id эскиза.")] public async Task CreateOnFace(double x, double y, double z) { await session.ConnectAsync(); var id = await modeler.OpenSketchOnFaceAsync(x, y, z); return $"Эскиз создан на грани в точке ({x}, {y}, {z}), id={id}. Координаты геометрии — в локальной плоскости эскиза."; } [McpServerTool(Name = "sketch_create_on_offset_plane")] [Description("Создать эскиз на плоскости, смещённой от базовой (XOY|XOZ|YOZ) на offset мм, и открыть на редактирование. Позволяет строить геометрию на произвольной высоте/смещении (например сечения для операции loft). direction — направление смещения от базовой плоскости. Возвращает id эскиза.")] public async Task CreateOnOffsetPlane( [Description("Базовая плоскость: XOY | XOZ | YOZ")] string basePlane, [Description("Смещение от базовой плоскости, мм")] double offset, [Description("Прямое направление смещения")] bool direction = true) { await session.ConnectAsync(); var id = await modeler.OpenSketchOnOffsetPlaneAsync(BasePlanes.Parse(basePlane), offset, direction); return $"Эскиз создан на смещённой плоскости {basePlane}+{offset}, id={id}."; } [McpServerTool(Name = "sketch_add_circle")] [Description("Добавить окружность в открытый эскиз. Координаты — в плоскости эскиза, мм.")] public async Task AddCircle(int sketchId, double centerX, double centerY, double radius) { await session.ConnectAsync(); await modeler.AddCircleAsync(sketchId, centerX, centerY, radius); return "Окружность добавлена."; } [McpServerTool(Name = "sketch_add_line")] [Description("Добавить отрезок в открытый эскиз (две точки, мм).")] public async Task AddLine(int sketchId, double x1, double y1, double x2, double y2) { await session.ConnectAsync(); await modeler.AddLineAsync(sketchId, x1, y1, x2, y2); return "Отрезок добавлен."; } [McpServerTool(Name = "sketch_create_on_face_index")] [Description("Создать эскиз на грани детали, заданной индексом из list_faces, и открыть на редактирование. Надёжнее выбора по точке (не нужно угадывать координаты). Возвращает id эскиза.")] public async Task CreateOnFaceIndex([Description("Индекс грани из list_faces")] int faceIndex) { await session.ConnectAsync(); var id = await modeler.OpenSketchOnFaceIndexAsync(faceIndex); return $"Эскиз создан на грани [{faceIndex}], id={id}."; } [McpServerTool(Name = "sketch_add_axis")] [Description("Добавить осевую линию (ось вращения) в открытый эскиз — нужна для revolve_boss/revolve_cut. Две точки в плоскости эскиза, мм.")] public async Task AddAxis(int sketchId, double x1, double y1, double x2, double y2) { await session.ConnectAsync(); await modeler.AddAxisAsync(sketchId, x1, y1, x2, y2); return "Осевая линия добавлена."; } [McpServerTool(Name = "sketch_add_rectangle")] [Description("Добавить прямоугольник по двум противоположным углам в открытый эскиз (мм).")] public async Task AddRectangle(int sketchId, double x1, double y1, double x2, double y2) { await session.ConnectAsync(); await modeler.AddRectangleAsync(sketchId, x1, y1, x2, y2); return "Прямоугольник добавлен."; } [McpServerTool(Name = "sketch_close")] [Description("Завершить редактирование эскиза (перед операцией выдавливания).")] public async Task Close(int sketchId) { await session.ConnectAsync(); await modeler.CloseSketchAsync(sketchId); return "Эскиз закрыт."; } [McpServerTool(Name = "sketch_add_arc_3points")] [Description("Добавить дугу по трём точкам (начало, промежуточная точка на дуге, конец) в открытый эскиз. Координаты — в плоскости эскиза, мм.")] public async Task AddArc3Points(int sketchId, double x1, double y1, double x2, double y2, double x3, double y3) { await session.ConnectAsync(); await modeler.AddArc3PointsAsync(sketchId, x1, y1, x2, y2, x3, y3); return "Дуга по 3 точкам добавлена."; } [McpServerTool(Name = "sketch_add_arc")] [Description("Добавить дугу по центру, радиусу и углам (в градусах, от оси X) в открытый эскиз. counterClockwise=true — против часовой стрелки, false — по часовой. Координаты центра — в плоскости эскиза, мм.")] public async Task AddArc(int sketchId, double centerX, double centerY, double radius, double startAngle, double endAngle, bool counterClockwise = true) { await session.ConnectAsync(); await modeler.AddArcByAngleAsync(sketchId, centerX, centerY, radius, startAngle, endAngle, counterClockwise); return "Дуга добавлена."; } [McpServerTool(Name = "sketch_add_ellipse")] [Description("Добавить эллипс в открытый эскиз: центр, большая полуось semiMajor, малая полуось semiMinor (мм), угол наклона большой оси к X (градусы, по умолчанию 0).")] public async Task AddEllipse(int sketchId, double centerX, double centerY, double semiMajor, double semiMinor, double angle = 0) { await session.ConnectAsync(); await modeler.AddEllipseAsync(sketchId, centerX, centerY, semiMajor, semiMinor, angle); return "Эллипс добавлен."; } [McpServerTool(Name = "sketch_add_polyline")] [Description("Добавить ломаную — цепочку прямых отрезков по списку точек — в открытый эскиз. closed=true замыкает последнюю точку с первой (тогда нужно минимум 3 точки). Координаты — в плоскости эскиза, мм.")] public async Task AddPolyline(int sketchId, SketchPoint[] points, bool closed = false) { await session.ConnectAsync(); await modeler.AddPolylineAsync(sketchId, Map(points), closed); return $"Ломаная из {points.Length} точек добавлена{(closed ? " (замкнута)" : "")}."; } [McpServerTool(Name = "sketch_add_polygon")] [Description("Добавить правильный многоугольник в открытый эскиз: центр, vertexCount вершин (>=3), radius (мм). inscribed=true — вершины лежат на окружности радиуса (вписанный в окружность); false — стороны касаются окружности (описанный). angle — поворот первой вершины (градусы, по умолчанию 0).")] public async Task AddPolygon(int sketchId, double centerX, double centerY, int vertexCount, double radius, bool inscribed = true, double angle = 0) { await session.ConnectAsync(); await modeler.AddPolygonAsync(sketchId, centerX, centerY, vertexCount, radius, inscribed, angle); return $"Правильный многоугольник ({vertexCount} вершин) добавлен."; } [McpServerTool(Name = "sketch_add_spline")] [Description("Добавить сплайн (кубический NURBS) через список точек в открытый эскиз. closed=true замыкает кривую. Координаты — в плоскости эскиза, мм.")] public async Task AddSpline(int sketchId, SketchPoint[] points, bool closed = false) { await session.ConnectAsync(); await modeler.AddSplineAsync(sketchId, Map(points), closed); return $"Сплайн по {points.Length} точкам добавлен{(closed ? " (замкнут)" : "")}."; } [McpServerTool(Name = "sketch_add_point")] [Description("Добавить точку в открытый эскиз (опорная точка для построений). Координаты — в плоскости эскиза, мм.")] public async Task AddPoint(int sketchId, double x, double y) { await session.ConnectAsync(); await modeler.AddPointAsync(sketchId, x, y); return "Точка добавлена."; } private static IReadOnlyList<(double x, double y)> Map(SketchPoint[] points) { ArgumentNullException.ThrowIfNull(points); return points.Select(p => (p.X, p.Y)).ToList(); } }