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:
2026-05-27 10:23:16 +03:00
parent 4f7e8f3b7e
commit 205a4b02de
4 changed files with 153 additions and 0 deletions
@@ -282,6 +282,38 @@ public sealed class FeatureOpsTests
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task Draft_tapers_box_sides_into_frustum()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
// Коробка 40×40×20 (центр 0,0; низ на Z=0, верх на Z=20).
var s = await _modeler.OpenSketchAsync(BasePlane.XOY);
await _modeler.AddRectangleAsync(s, -20, -20, 20, 20);
await _modeler.CloseSketchAsync(s);
await _modeler.ExtrudeAsync(s, depth: 20);
var before = (await _query.GetPartInfoAsync()).Volume; // 32000
// 4 боковые грани (площадь 40×20=800) под уклон 10° внутрь относительно XOY (низ остаётся 40×40).
var faces = await _query.ListFacesAsync();
var sides = faces.Where(f => f.Type == "plane" && Math.Abs(f.Area - 800) < 1).Select(f => f.Index).ToArray();
Assert.Equal(4, sides.Length);
var id = await _modeler.DraftAsync(sides, BasePlane.XOY, angle: 10, outward: false);
Assert.True(id > 0);
await _modeler.RebuildAsync();
// Сужение к верху → усечённая пирамида. Верх ≈ 40−2·20·tan10° = 32.95; A2≈1085.5.
// V = (20/3)(1600 + 1085.5 + √(1600·1085.5)) ≈ 26689 мм³.
var after = (await _query.GetPartInfoAsync()).Volume;
var expected = (20.0 / 3) * (1600 + 1085.5 + Math.Sqrt(1600 * 1085.5));
Assert.True(after < before, "Сужающий уклон должен уменьшить объём.");
Assert.InRange(after, expected * 0.9, expected * 1.1);
}
finally { await _docs.CloseAsync(save: false); }
}
[Fact]
public async Task Loft_two_squares_makes_solid()
{