feat: уклон граней (draft) через API5 — ksInclineDefinition o3d_incline=42
- ВОПРЕКИ прежнему предположению: уклон ЕСТЬ в API5 (операция Incline, не Draft) → стандартный паттерн PartModeler, регистрируется в _features (массивы/зеркало применимы) - DraftAsync: FaceArray().Add(грани) + SetPlane(нейтральная коорд. плоскость) + angle + direction - ЭМПИРИЧЕСКИ: direction=false=расширение, true=сужение (обратно справке) → маппинг !outward - инструмент draft (faceIndices, neutralPlane, angle 0..90, outward); валидация угла и индексов - интеграционный тест: 4 боковые грани коробки → усечённая пирамида (объём ±10%) - 105 тестов; спек docs/superpowers/specs/2026-05-27-draft-design.md
This commit is contained in:
@@ -480,6 +480,46 @@ public sealed partial class PartModeler
|
||||
return id;
|
||||
}, ct);
|
||||
|
||||
/// <summary>Уклон граней: наклонить грани faceIndices на угол angle° относительно нейтральной
|
||||
/// (опорной) координатной плоскости neutralPlane — сечение тела в этой плоскости остаётся
|
||||
/// неизменным. outward=true — расширение (материал добавляется), false — сужение. Грани должны
|
||||
/// граничить/пересекаться с нейтральной плоскостью. Возвращает id операции.</summary>
|
||||
public Task<int> DraftAsync(IReadOnlyList<int> faceIndices, BasePlane neutralPlane, double angle, bool outward = false, CancellationToken ct = default)
|
||||
=> _dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
if (!double.IsFinite(angle) || angle <= 0 || angle >= 90)
|
||||
throw new ArgumentOutOfRangeException(nameof(angle), "Угол уклона должен быть в (0; 90) градусов.");
|
||||
ArgumentNullException.ThrowIfNull(faceIndices);
|
||||
var indices = faceIndices.Distinct().ToList();
|
||||
if (indices.Count == 0) throw new ArgumentException("Нужна хотя бы одна грань для уклона.", nameof(faceIndices));
|
||||
|
||||
var part = GetTopPart();
|
||||
// Проверяем диапазон ВСЕХ индексов до мутации модели.
|
||||
var faces = indices.Select(i => SelectFaceByIndex(part, i)).ToList();
|
||||
|
||||
var planeEntity = part.GetDefaultEntity((short)BasePlanes.ToObj3dType(neutralPlane)) as ksEntity
|
||||
?? throw new InvalidOperationException("Не удалось получить координатную плоскость.");
|
||||
|
||||
var entity = part.NewEntity((short)Obj3dType.o3d_incline) as ksEntity
|
||||
?? throw new InvalidOperationException("NewEntity(o3d_incline) вернул null.");
|
||||
var def = entity.GetDefinition() as ksInclineDefinition
|
||||
?? throw new InvalidOperationException("GetDefinition() уклона вернул не ksInclineDefinition.");
|
||||
var arr = def.FaceArray() as ksEntityCollection
|
||||
?? throw new InvalidOperationException("FaceArray() уклона вернул не ksEntityCollection.");
|
||||
foreach (var f in faces) arr.Add(f);
|
||||
def.SetPlane(planeEntity);
|
||||
def.angle = angle;
|
||||
def.direction = !outward; // эмпирически: direction=false → расширение, true → сужение
|
||||
|
||||
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(() =>
|
||||
|
||||
@@ -198,6 +198,20 @@ public sealed class FeatureTools(KompasSession session, PartModeler modeler, Hol
|
||||
return $"Отверстие Ø{diameter} ({kind}) создано на грани в точке ({x}, {y}, {z}).";
|
||||
}
|
||||
|
||||
[McpServerTool(Name = "draft")]
|
||||
[Description("Уклон граней: наклонить грани faceIndices (из list_faces) на угол angle (градусы, 0..90) относительно нейтральной (опорной) координатной плоскости neutralPlane (XOY|XOZ|YOZ) — сечение тела в этой плоскости остаётся неизменным, грани уклоняются вокруг линии пересечения с ней. outward=true — расширение (материал добавляется), false — сужение. Грани должны граничить/пересекаться с нейтральной плоскостью. Возвращает id операции.")]
|
||||
public async Task<string> Draft(
|
||||
[Description("Индексы уклоняемых граней из list_faces")] int[] faceIndices,
|
||||
[Description("Нейтральная (опорная) плоскость: XOY|XOZ|YOZ")] string neutralPlane,
|
||||
[Description("Угол уклона, градусы (0..90)")] double angle,
|
||||
[Description("Расширение (true) или сужение (false)")] bool outward = false)
|
||||
{
|
||||
await session.ConnectAsync();
|
||||
var id = await modeler.DraftAsync(faceIndices, BasePlanes.Parse(neutralPlane), angle, outward);
|
||||
var count = faceIndices?.Distinct().Count() ?? 0;
|
||||
return $"Уклон {angle}° создан на {count} гранях (нейтральная плоскость {neutralPlane}), id={id}.";
|
||||
}
|
||||
|
||||
[McpServerTool(Name = "rebuild")]
|
||||
[Description("Перестроить активный документ.")]
|
||||
public async Task<string> Rebuild()
|
||||
|
||||
Reference in New Issue
Block a user