d3dd78ec0b
- направление сверления — по факту убыли объёма (Update=TRUE даже при сверлении в воздух на сквозном отверстии); TryDirection + CurrentVolume (API5 МЦХ) — P2-баг, вскрыт тестом - валидация double.IsFinite для координат/диаметра/глубины (Infinity проходил мимо >0) — P2 - откат точки-сироты и объекта отверстия при неуспехе (IFeature7.Delete) + RebuildDocument — P2 - тест Hole_through_bottom_face_uses_direction_fallback (нижняя грань) — P3 - 104 теста зелёных
100 lines
4.7 KiB
C#
100 lines
4.7 KiB
C#
using Kompas.Mcp.Core.Documents;
|
|
using Kompas.Mcp.Core.Modeling;
|
|
using Kompas.Mcp.Core.Query;
|
|
|
|
namespace Kompas.Mcp.Tests.Integration;
|
|
|
|
/// <summary>Интеграция: операция «Отверстие» (API7 IHoles3D/IHole3D).</summary>
|
|
[Trait("Category", "Integration")]
|
|
[Collection(KompasCollection.Name)]
|
|
public sealed class HoleTests
|
|
{
|
|
private readonly DocumentService _docs;
|
|
private readonly PartModeler _modeler;
|
|
private readonly HoleService _holes;
|
|
private readonly QueryService _query;
|
|
|
|
public HoleTests(KompasFixture fx)
|
|
{
|
|
_docs = new DocumentService(fx.Session, fx.Dispatcher);
|
|
_modeler = new PartModeler(fx.Session, fx.Dispatcher);
|
|
_holes = new HoleService(fx.Session, fx.Dispatcher);
|
|
_query = new QueryService(fx.Session, fx.Dispatcher);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Hole_through_top_face_removes_cylinder_volume()
|
|
{
|
|
await _docs.CreateAsync(KompasDocumentType.Part);
|
|
try
|
|
{
|
|
// Коробка 40×40×20 (центр в начале координат), верхняя грань на 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
|
|
|
|
// Сквозное отверстие Ø10 по центру верхней грани (0,0,20).
|
|
await _holes.HoleAsync(0, 0, 20, diameter: 10, depth: 0, throughAll: true);
|
|
var after = (await _query.GetPartInfoAsync()).Volume;
|
|
|
|
// Удалён цилиндр π·25·20 ≈ 1570.8 мм³.
|
|
var removed = Math.PI * 25 * 20;
|
|
Assert.True(after < before, "После отверстия объём должен уменьшиться.");
|
|
Assert.InRange(before - after, removed * 0.95, removed * 1.05);
|
|
}
|
|
finally { await _docs.CloseAsync(save: false); }
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Hole_blind_in_top_face_removes_partial_cylinder()
|
|
{
|
|
await _docs.CreateAsync(KompasDocumentType.Part);
|
|
try
|
|
{
|
|
// Коробка 40×40×20, верхняя грань на 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
|
|
|
|
// Глухое отверстие Ø8 глубиной 10 по центру верхней грани.
|
|
await _holes.HoleAsync(0, 0, 20, diameter: 8, depth: 10, throughAll: false);
|
|
var after = (await _query.GetPartInfoAsync()).Volume;
|
|
|
|
// Удалён цилиндр π·16·10 ≈ 502.7 мм³ (без учёта плоского торца — EndFaceType=Flat).
|
|
var removed = Math.PI * 16 * 10;
|
|
Assert.True(after < before, "После глухого отверстия объём должен уменьшиться.");
|
|
Assert.InRange(before - after, removed * 0.9, removed * 1.1);
|
|
}
|
|
finally { await _docs.CloseAsync(save: false); }
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Hole_through_bottom_face_uses_direction_fallback()
|
|
{
|
|
await _docs.CreateAsync(KompasDocumentType.Part);
|
|
try
|
|
{
|
|
// Коробка 40×40×20, нижняя грань на Z=0 (нормаль смотрит наружу, −Z).
|
|
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
|
|
|
|
// Сверлим со стороны НИЖНЕЙ грани (0,0,0): корректное направление в тело — внутрь (+Z),
|
|
// т.е. противоположно нормали → проверяет авто-подбор направления (fallback).
|
|
await _holes.HoleAsync(0, 0, 0, diameter: 10, depth: 0, throughAll: true);
|
|
var after = (await _query.GetPartInfoAsync()).Volume;
|
|
|
|
var removed = Math.PI * 25 * 20;
|
|
Assert.True(after < before, "Отверстие с нижней грани должно построиться (fallback направления).");
|
|
Assert.InRange(before - after, removed * 0.95, removed * 1.05);
|
|
}
|
|
finally { await _docs.CloseAsync(save: false); }
|
|
}
|
|
}
|