28d2ae3868
Новый слой «модель как данные» (приоритетный над model_snapshot): - describe_model — структурный «паспорт» детали одним вызовом (габарит, МЦХ, тела, сводка топологии, дерево построения с параметрами, переменные) - list_features / list_bodies / list_variables - describe_face / describe_edge (drill-down по индексу) - measure (расстояние/угол между гранями/рёбрами/вершинами) - model_snapshot понижен до fallback для визуально-пространственных вопросов Реализация: ModelInspectionService (COM) + чистый InspectionText (рендер, группировка, детект «импорт без истории») + record-модели; InspectionTools. Дерево читается через ksPart.GetFeature()->SubFeatureCollection; точный тип и параметры операций берутся из GetObject()->GetDefinition() (ksFeature.type отдаёт лишь coarse o3d_entity). Снимок дерева также включает слои conversion (STEP), editing (move_face/solid) и validation, развивавшиеся параллельно. Полный прогон: 61 тест зелёный, 43 MCP-инструмента. Документация (README, ARCHITECTURE, OPEN_QUESTIONS, CLAUDE.md, presentation.html) синхронизирована. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
70 lines
4.4 KiB
C#
70 lines
4.4 KiB
C#
using System.ComponentModel;
|
||
using Kompas.Mcp.Core;
|
||
using Kompas.Mcp.Core.Query;
|
||
using ModelContextProtocol.Server;
|
||
|
||
namespace Kompas.Mcp.Host.Tools;
|
||
|
||
/// <summary>Инструменты запросов к модели.</summary>
|
||
[McpServerToolType]
|
||
public sealed class QueryTools(KompasSession session, QueryService query)
|
||
{
|
||
[McpServerTool(Name = "get_part_info")]
|
||
[Description("Массово-центровочные характеристики активной детали: объём (мм³), масса (кг), площадь (мм²) и центр масс. Полезно для числовой проверки построения.")]
|
||
public async Task<string> GetPartInfo()
|
||
{
|
||
await session.ConnectAsync();
|
||
var i = await query.GetPartInfoAsync();
|
||
return $"Объём: {i.Volume:F2} мм³; масса: {i.Mass:F4} кг; площадь: {i.Area:F2} мм²; " +
|
||
$"центр масс: ({i.CenterX:F2}, {i.CenterY:F2}, {i.CenterZ:F2}).";
|
||
}
|
||
|
||
[McpServerTool(Name = "list_components")]
|
||
[Description("Перечислить компоненты верхнего уровня активной сборки: индекс, имя, обозначение, признак детали и габарит (мм). Индекс/имя — для последующего извлечения или осмотра детали.")]
|
||
public async Task<string> ListComponents()
|
||
{
|
||
await session.ConnectAsync();
|
||
var comps = await query.ListComponentsAsync();
|
||
if (comps.Count == 0) return "Компонентов нет (активный документ не сборка или пуст).";
|
||
var lines = comps.Select(c =>
|
||
{
|
||
var mark = string.IsNullOrWhiteSpace(c.Marking) ? "" : $", обозн. \"{c.Marking}\"";
|
||
return $" [{c.Index}] {(c.IsDetail ? "деталь" : "узел ")} \"{c.Name}\", " +
|
||
$"габ {c.SizeX:F1}×{c.SizeY:F1}×{c.SizeZ:F1} мм{mark}";
|
||
});
|
||
return $"Компонентов: {comps.Count}\n" + string.Join("\n", lines);
|
||
}
|
||
|
||
[McpServerTool(Name = "list_faces")]
|
||
[Description("Перечислить грани активной детали: индекс, тип поверхности (plane/cylinder/cone/sphere/torus/nurbs) и площадь (мм²). Индекс используйте в sketch_create_on_face_index. Удобно для надёжного выбора грани без угадывания координат.")]
|
||
public async Task<string> ListFaces()
|
||
{
|
||
await session.ConnectAsync();
|
||
var faces = await query.ListFacesAsync();
|
||
if (faces.Count == 0) return "Граней нет (модель пуста?).";
|
||
var lines = faces.Select(f => $" [{f.Index}] {f.Type}, площадь {f.Area:F2} мм²");
|
||
return $"Граней: {faces.Count}\n" + string.Join("\n", lines);
|
||
}
|
||
|
||
[McpServerTool(Name = "list_edges")]
|
||
[Description("Перечислить рёбра активной детали: индекс, тип кривой (line/circle/arc/ellipse/nurbs) и длину (мм). Индекс используйте в fillet_edge_index / chamfer_edge_index для надёжного выбора ребра без угадывания координат.")]
|
||
public async Task<string> ListEdges()
|
||
{
|
||
await session.ConnectAsync();
|
||
var edges = await query.ListEdgesAsync();
|
||
if (edges.Count == 0) return "Рёбер нет (модель пуста?).";
|
||
var lines = edges.Select(e => $" [{e.Index}] {e.Type}, длина {e.Length:F2} мм");
|
||
return $"Рёбер: {edges.Count}\n" + string.Join("\n", lines);
|
||
}
|
||
|
||
[McpServerTool(Name = "get_bounding_box")]
|
||
[Description("Габариты активной детали: координаты габаритного параллелепипеда (мм) и его размеры. Помогает оценить протяжённость модели и подобрать точки для выбора граней/рёбер.")]
|
||
public async Task<string> GetBoundingBox()
|
||
{
|
||
await session.ConnectAsync();
|
||
var b = await query.GetBoundingBoxAsync();
|
||
return $"Габарит: X [{b.MinX:F2}; {b.MaxX:F2}], Y [{b.MinY:F2}; {b.MaxY:F2}], Z [{b.MinZ:F2}; {b.MaxZ:F2}]; " +
|
||
$"размеры (Д×Ш×В): {b.SizeX:F2} × {b.SizeY:F2} × {b.SizeZ:F2} мм.";
|
||
}
|
||
}
|