@
feat(features): скругление и фаска ребра (fillet_edge / chamfer_edge) PartModeler.FilletEdgeAsync / ChamferEdgeAsync через API5 o3d_fillet/o3d_chamfer: ребро выбирается по точке (общий хелпер SelectEdgeByPoint поверх EntityCollection(o3d_edge).SelectByPoint), добавляется в def.array(), радиус/катет задаются (ksFilletDefinition.radius, ksChamferDefinition.SetChamferParam). Новые MCP-инструменты: fillet_edge, chamfer_edge. Тест Fillet_and_chamfer_edges: цилиндр → скругление верхнего ребра R3 + фаска нижнего 2×2, проверка успеха, уменьшения объёма и снимка (визуально подтверждено). Презентация: 25 инструментов, 17 тестов. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> @
This commit is contained in:
@@ -246,6 +246,64 @@ public sealed class PartModeler : IDisposable
|
||||
return id;
|
||||
}, ct);
|
||||
|
||||
/// <summary>
|
||||
/// Скруглить ребро детали, найденное по точке (мировые координаты, мм), радиусом <paramref name="radius"/>.
|
||||
/// Возвращает id операции.
|
||||
/// </summary>
|
||||
public Task<int> FilletEdgeAsync(double x, double y, double z, double radius, CancellationToken ct = default)
|
||||
=> _dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
if (radius <= 0) throw new ArgumentOutOfRangeException(nameof(radius), "Радиус скругления должен быть > 0.");
|
||||
var part = GetTopPart();
|
||||
var edge = SelectEdgeByPoint(part, x, y, z);
|
||||
|
||||
var entity = part.NewEntity((short)Obj3dType.o3d_fillet) as ksEntity
|
||||
?? throw new InvalidOperationException("NewEntity(o3d_fillet) вернул null.");
|
||||
var def = entity.GetDefinition() as ksFilletDefinition
|
||||
?? throw new InvalidOperationException("GetDefinition() скругления вернул не ksFilletDefinition.");
|
||||
def.radius = radius;
|
||||
def.tangent = false;
|
||||
var arr = def.array() as ksEntityCollection
|
||||
?? throw new InvalidOperationException("array() скругления вернул не ksEntityCollection.");
|
||||
arr.Add(edge);
|
||||
|
||||
if (!entity.Create())
|
||||
throw new InvalidOperationException("Create() скругления вернул FALSE (радиус слишком велик для ребра?).");
|
||||
|
||||
var id = _nextId++;
|
||||
_features[id] = entity;
|
||||
return id;
|
||||
}, ct);
|
||||
|
||||
/// <summary>
|
||||
/// Снять фаску с ребра детали, найденного по точке (мировые координаты, мм), катетом <paramref name="distance"/>.
|
||||
/// Возвращает id операции.
|
||||
/// </summary>
|
||||
public Task<int> ChamferEdgeAsync(double x, double y, double z, double distance, CancellationToken ct = default)
|
||||
=> _dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
if (distance <= 0) throw new ArgumentOutOfRangeException(nameof(distance), "Катет фаски должен быть > 0.");
|
||||
var part = GetTopPart();
|
||||
var edge = SelectEdgeByPoint(part, x, y, z);
|
||||
|
||||
var entity = part.NewEntity((short)Obj3dType.o3d_chamfer) as ksEntity
|
||||
?? throw new InvalidOperationException("NewEntity(o3d_chamfer) вернул null.");
|
||||
var def = entity.GetDefinition() as ksChamferDefinition
|
||||
?? throw new InvalidOperationException("GetDefinition() фаски вернул не ksChamferDefinition.");
|
||||
def.tangent = false;
|
||||
def.SetChamferParam(true, distance, distance);
|
||||
var arr = def.array() as ksEntityCollection
|
||||
?? throw new InvalidOperationException("array() фаски вернул не ksEntityCollection.");
|
||||
arr.Add(edge);
|
||||
|
||||
if (!entity.Create())
|
||||
throw new InvalidOperationException("Create() фаски вернул FALSE (катет слишком велик для ребра?).");
|
||||
|
||||
var id = _nextId++;
|
||||
_features[id] = entity;
|
||||
return id;
|
||||
}, ct);
|
||||
|
||||
/// <summary>Перестроить документ.</summary>
|
||||
public Task RebuildAsync(CancellationToken ct = default)
|
||||
=> _dispatcher.InvokeAsync(() =>
|
||||
@@ -271,6 +329,19 @@ public sealed class PartModeler : IDisposable
|
||||
=> ActiveDoc3D().GetPart((short)Part_Type.pTop_Part) as ksPart
|
||||
?? throw new InvalidOperationException("Не удалось получить вершинный компонент (ksPart).");
|
||||
|
||||
/// <summary>Выбрать ребро детали по точке (мировые координаты). Берёт первое подходящее.</summary>
|
||||
private static ksEntity SelectEdgeByPoint(ksPart part, double x, double y, double z)
|
||||
{
|
||||
var edges = part.EntityCollection((short)Obj3dType.o3d_edge) as ksEntityCollection
|
||||
?? throw new InvalidOperationException("Не удалось получить коллекцию рёбер.");
|
||||
edges.SelectByPoint(x, y, z);
|
||||
if (edges.GetCount() == 0)
|
||||
throw new InvalidOperationException(
|
||||
$"В точке ({x}, {y}, {z}) не найдено ребра. Сделайте снимок и сверьте координаты точки на ребре.");
|
||||
return edges.GetByIndex(0) as ksEntity
|
||||
?? throw new InvalidOperationException("Ребро из коллекции не приводится к ksEntity.");
|
||||
}
|
||||
|
||||
private SketchEntry RequireSketch(int id)
|
||||
=> _sketches.TryGetValue(id, out var s) ? s
|
||||
: throw new KeyNotFoundException($"Эскиз с id={id} не найден.");
|
||||
|
||||
@@ -55,6 +55,24 @@ public sealed class FeatureTools(KompasSession session, PartModeler modeler)
|
||||
return $"Вырез вращением (cut) создан, id={id}.";
|
||||
}
|
||||
|
||||
[McpServerTool(Name = "fillet_edge")]
|
||||
[Description("Скруглить ребро детали, выбранное по точке (мировые координаты x,y,z в мм, точка должна лежать на ребре), радиусом radius (мм). Сделайте model_snapshot, прикиньте точку на ребре. Возвращает id операции.")]
|
||||
public async Task<string> FilletEdge(double x, double y, double z, double radius)
|
||||
{
|
||||
await session.ConnectAsync();
|
||||
var id = await modeler.FilletEdgeAsync(x, y, z, radius);
|
||||
return $"Скругление R{radius} создано на ребре в точке ({x}, {y}, {z}), id={id}.";
|
||||
}
|
||||
|
||||
[McpServerTool(Name = "chamfer_edge")]
|
||||
[Description("Снять фаску с ребра детали, выбранного по точке (мировые координаты x,y,z в мм, точка должна лежать на ребре), катетом distance (мм). Сделайте model_snapshot, прикиньте точку на ребре. Возвращает id операции.")]
|
||||
public async Task<string> ChamferEdge(double x, double y, double z, double distance)
|
||||
{
|
||||
await session.ConnectAsync();
|
||||
var id = await modeler.ChamferEdgeAsync(x, y, z, distance);
|
||||
return $"Фаска {distance}×{distance} создана на ребре в точке ({x}, {y}, {z}), id={id}.";
|
||||
}
|
||||
|
||||
[McpServerTool(Name = "rebuild")]
|
||||
[Description("Перестроить активный документ.")]
|
||||
public async Task<string> Rebuild()
|
||||
|
||||
Reference in New Issue
Block a user