Files
kompas3d-mcp/tests/Kompas.Mcp.Tests/Integration/ModelingTests.cs
T
mikhail 01f5f37c67 @
feat(sketch): эскиз на выбранной грани + МЦХ через API5

sketch_create_on_face: OpenSketchOnFaceAsync выбирает плоскую грань по точке
(ksPart.EntityCollection(o3d_face).SelectByPoint) и создаёт на ней эскиз —
ключевой шаг итеративного цикла «построил → выбрал грань → новый эскиз».
Общее ядро создания эскиза вынесено в CreateSketchOn.

QueryService переписан на API5 ksPart.CalcMassInertiaProperties(ST_MIX_MM|ST_MIX_KG):
- API7 IMassInertiaParam7.Calculate() непригоден — флаг Actual «залипает» после
  первого расчёта, повторный запрос отдавал устаревший объём (баг кэша);
- API5-маршрут считает по запросу и согласован с построением через ksPart;
- единицы (мм³/мм²/кг/мм) задаются битовым вектором.

Тест Sketch_on_face_adds_boss_on_top: запрос → штифт R5×H10 на верхней грани
цилиндра → повторный запрос видит прирост ≈785 мм³ (проверяет и грань, и кэш МЦХ).
Презентация: 20 инструментов, 15 тестов; OPEN_QUESTIONS обновлён.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@
2026-05-26 09:52:56 +03:00

113 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Kompas.Mcp.Core.Documents;
using Kompas.Mcp.Core.Modeling;
using Kompas.Mcp.Core.Query;
using Kompas.Mcp.Core.Vision;
namespace Kompas.Mcp.Tests.Integration;
/// <summary>Интеграция: построение 3D (эскиз → выдавливание) и снимок.</summary>
[Trait("Category", "Integration")]
[Collection(KompasCollection.Name)]
public sealed class ModelingTests
{
private readonly DocumentService _docs;
private readonly PartModeler _modeler;
private readonly SnapshotService _snap;
private readonly QueryService _query;
public ModelingTests(KompasFixture fx)
{
_docs = new DocumentService(fx.Session, fx.Dispatcher);
_modeler = new PartModeler(fx.Session, fx.Dispatcher);
_snap = new SnapshotService(fx.Session, fx.Dispatcher);
_query = new QueryService(fx.Session, fx.Dispatcher);
}
[Fact]
public async Task Build_cylinder_then_cut_hole_and_snapshot()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
// Эскиз 1: окружность R20 на XOY → выдавить boss на 40 (цилиндр).
var s1 = await _modeler.OpenSketchAsync(BasePlane.XOY);
await _modeler.AddCircleAsync(s1, 0, 0, 20);
await _modeler.CloseSketchAsync(s1);
var boss = await _modeler.ExtrudeAsync(s1, depth: 40);
Assert.True(boss > 0);
// Эскиз 2: окружность R8 на XOY → вырезать насквозь (отверстие).
var s2 = await _modeler.OpenSketchAsync(BasePlane.XOY);
await _modeler.AddCircleAsync(s2, 0, 0, 8);
await _modeler.CloseSketchAsync(s2);
var cut = await _modeler.ExtrudeAsync(s2, depth: 40, cut: true, throughAll: true);
Assert.True(cut > 0);
await _modeler.RebuildAsync();
var path = TestPaths.NewFile(".png");
var snap = await _snap.CaptureActiveModelAsync(saveToFile: path);
Assert.True(snap.Bytes.Length > 1000, "Снимок цилиндра подозрительно мал.");
Assert.True(File.Exists(path));
}
finally
{
await _docs.CloseAsync(save: false);
}
}
[Fact]
public async Task Sketch_on_face_adds_boss_on_top()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
// Цилиндр R10×H20 на XOY → верхняя грань на Z=20.
var s1 = await _modeler.OpenSketchAsync(BasePlane.XOY);
await _modeler.AddCircleAsync(s1, 0, 0, 10);
await _modeler.CloseSketchAsync(s1);
await _modeler.ExtrudeAsync(s1, depth: 20);
// Запрос ДО достройки — проверяем, что повторный запрос увидит изменения
// (МЦХ не должна «залипнуть» на устаревшем значении).
var before = await _query.GetPartInfoAsync();
// Эскиз на верхней грани (точка (0,0,20)) → штифт R5×H10 наружу.
var s2 = await _modeler.OpenSketchOnFaceAsync(0, 0, 20);
await _modeler.AddCircleAsync(s2, 0, 0, 5);
await _modeler.CloseSketchAsync(s2);
var boss = await _modeler.ExtrudeAsync(s2, depth: 10);
Assert.True(boss > 0);
await _modeler.RebuildAsync();
var after = await _query.GetPartInfoAsync();
// Прирост объёма ≈ объём штифта π·5²·10 ≈ 785.4 мм³.
var deltaExpected = Math.PI * 25 * 10;
Assert.InRange(after.Volume - before.Volume, deltaExpected * 0.9, deltaExpected * 1.1);
}
finally
{
await _docs.CloseAsync(save: false);
}
}
[Fact]
public async Task Reset_invalidates_sketch_ids()
{
await _docs.CreateAsync(KompasDocumentType.Part);
try
{
var s = await _modeler.OpenSketchAsync(BasePlane.XOY);
await _modeler.ResetAsync();
// После сброса реестра старый id недействителен.
await Assert.ThrowsAsync<KeyNotFoundException>(
() => _modeler.AddCircleAsync(s, 0, 0, 5));
}
finally
{
await _docs.CloseAsync(save: false);
}
}
}