Files
ViewDesignEngine/tests/brep/test_step_import.cpp
T

603 lines
22 KiB
C++
Raw Normal View History

#include <gtest/gtest.h>
#include "vde/brep/step_import.h"
#include "vde/brep/brep.h"
#include "vde/brep/modeling.h"
#include <cmath>
#include <sstream>
using namespace vde::brep;
using namespace vde::core;
// ─────────────────────────────────────────────────────────────
// Helper: build a minimal STEP file as a string
// ─────────────────────────────────────────────────────────────
static std::string step_header() {
return R"(ISO-10303-21;
HEADER;
FILE_DESCRIPTION(('ViewDesignEngine test'),'2;1');
FILE_NAME('test.stp','2025-01-01T00:00:00',('Author'),(''),'','','');
FILE_SCHEMA(('CONFIG_CONTROL_DESIGN','GEOMETRIC_MODEL_SCHEMA'));
ENDSEC;
DATA;
)";
}
static std::string step_footer() {
return R"(ENDSEC;
END-ISO-10303-21;
)";
}
// ─────────────────────────────────────────────────────────────
// Test: Parse a minimal box STEP file
// ─────────────────────────────────────────────────────────────
TEST(StepImport, MinimalBox) {
// A simple box as MANIFOLD_SOLID_BREP with 6 planar faces
// Points are the 8 corners of a 2×2×2 box centered at origin
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',(-1.0,-1.0,-1.0));
#2=CARTESIAN_POINT('',(1.0,-1.0,-1.0));
#3=CARTESIAN_POINT('',(1.0,1.0,-1.0));
#4=CARTESIAN_POINT('',(-1.0,1.0,-1.0));
#5=CARTESIAN_POINT('',(-1.0,-1.0,1.0));
#6=CARTESIAN_POINT('',(1.0,-1.0,1.0));
#7=CARTESIAN_POINT('',(1.0,1.0,1.0));
#8=CARTESIAN_POINT('',(-1.0,1.0,1.0));
#10=DIRECTION('',(0.0,0.0,1.0));
#11=DIRECTION('',(1.0,0.0,0.0));
#12=DIRECTION('',(0.0,1.0,0.0));
#13=DIRECTION('',(0.0,0.0,-1.0));
#14=DIRECTION('',(-1.0,0.0,0.0));
#15=DIRECTION('',(0.0,-1.0,0.0));
#16=DIRECTION('',(1.0,1.0,0.0));
#17=DIRECTION('',(-1.0,1.0,0.0));
#18=DIRECTION('',(-1.0,-1.0,0.0));
#19=DIRECTION('',(1.0,-1.0,0.0));
#20=AXIS2_PLACEMENT_3D('',#1,#10,#11);
#21=AXIS2_PLACEMENT_3D('',#5,#10,#11);
#22=AXIS2_PLACEMENT_3D('',#1,#12,#11);
#23=AXIS2_PLACEMENT_3D('',#4,#12,#11);
#24=AXIS2_PLACEMENT_3D('',#2,#14,#12);
#25=AXIS2_PLACEMENT_3D('',#1,#14,#12);
#30=PLANE('',#20);
#31=PLANE('',#21);
#32=PLANE('',#22);
#33=PLANE('',#23);
#34=PLANE('',#24);
#35=PLANE('',#25);
#40=LINE('',#1,#16);
#41=LINE('',#2,#17);
#42=LINE('',#3,#12);
#43=LINE('',#4,#18);
#44=LINE('',#5,#19);
#45=LINE('',#6,#17);
#46=LINE('',#7,#11);
#47=LINE('',#8,#18);
#48=LINE('',#1,#10);
#49=LINE('',#2,#10);
#50=LINE('',#3,#10);
#51=LINE('',#4,#10);
#52=LINE('',#2,#11);
#53=LINE('',#3,#12);
#54=LINE('',#7,#12);
#55=LINE('',#6,#15);
#56=LINE('',#1,#15);
#57=LINE('',#4,#14);
#58=LINE('',#8,#14);
#59=LINE('',#5,#15);
#60=LINE('',#5,#14);
#70=EDGE_CURVE('',#80,#81,#40,.T.);
#71=EDGE_CURVE('',#81,#82,#41,.T.);
#72=EDGE_CURVE('',#82,#83,#42,.T.);
#73=EDGE_CURVE('',#83,#80,#43,.T.);
#74=EDGE_CURVE('',#84,#85,#44,.T.);
#75=EDGE_CURVE('',#85,#86,#45,.T.);
#76=EDGE_CURVE('',#86,#87,#46,.T.);
#77=EDGE_CURVE('',#87,#84,#47,.T.);
#78=EDGE_CURVE('',#80,#84,#48,.T.);
#79=EDGE_CURVE('',#81,#85,#49,.T.);
#80=VERTEX_POINT('',#1);
#81=VERTEX_POINT('',#2);
#82=VERTEX_POINT('',#3);
#83=VERTEX_POINT('',#4);
#84=VERTEX_POINT('',#5);
#85=VERTEX_POINT('',#6);
#86=VERTEX_POINT('',#7);
#87=VERTEX_POINT('',#8);
#90=EDGE_CURVE('',#82,#86,#50,.T.);
#91=EDGE_CURVE('',#85,#81,#52,.T.);
#92=EDGE_CURVE('',#83,#87,#53,.T.);
#93=EDGE_CURVE('',#86,#87,#54,.T.);
#94=EDGE_CURVE('',#81,#80,#55,.T.);
#95=EDGE_CURVE('',#84,#80,#56,.T.);
#96=EDGE_CURVE('',#82,#83,#57,.T.);
#97=EDGE_CURVE('',#87,#84,#58,.T.);
#98=EDGE_CURVE('',#80,#83,#59,.T.);
#99=EDGE_CURVE('',#84,#85,#60,.T.);
#100=ORIENTED_EDGE('',*,*,#70,.T.);
#101=ORIENTED_EDGE('',*,*,#71,.T.);
#102=ORIENTED_EDGE('',*,*,#72,.T.);
#103=ORIENTED_EDGE('',*,*,#73,.T.);
#104=ORIENTED_EDGE('',*,*,#74,.F.);
#105=ORIENTED_EDGE('',*,*,#75,.F.);
#106=ORIENTED_EDGE('',*,*,#76,.F.);
#107=ORIENTED_EDGE('',*,*,#77,.F.);
#108=ORIENTED_EDGE('',*,*,#78,.T.);
#109=ORIENTED_EDGE('',*,*,#94,.T.);
#110=ORIENTED_EDGE('',*,*,#95,.F.);
#111=ORIENTED_EDGE('',*,*,#98,.T.);
#112=ORIENTED_EDGE('',*,*,#56,.T.);
#113=ORIENTED_EDGE('',*,*,#79,.T.);
#114=ORIENTED_EDGE('',*,*,#91,.T.);
#115=ORIENTED_EDGE('',*,*,#90,.F.);
#116=ORIENTED_EDGE('',*,*,#96,.F.);
#117=ORIENTED_EDGE('',*,*,#92,.T.);
#118=ORIENTED_EDGE('',*,*,#97,.F.);
#119=ORIENTED_EDGE('',*,*,#54,.T.);
#120=ORIENTED_EDGE('',*,*,#93,.F.);
#121=ORIENTED_EDGE('',*,*,#46,.T.);
#122=ORIENTED_EDGE('',*,*,#60,.T.);
#123=ORIENTED_EDGE('',*,*,#99,.F.);
#130=EDGE_LOOP('',(#100,#101,#102,#103));
#131=EDGE_LOOP('',(#104,#105,#106,#107));
#132=EDGE_LOOP('',(#108,#109,#110,#112));
#133=EDGE_LOOP('',(#113,#114,#115,#116));
#134=EDGE_LOOP('',(#117,#118,#119,#120));
#135=EDGE_LOOP('',(#121,#122,#123,#111));
#140=FACE_OUTER_BOUND('',#130,.T.);
#141=FACE_OUTER_BOUND('',#131,.T.);
#142=FACE_OUTER_BOUND('',#132,.T.);
#143=FACE_OUTER_BOUND('',#133,.T.);
#144=FACE_OUTER_BOUND('',#134,.T.);
#145=FACE_OUTER_BOUND('',#135,.T.);
#150=ADVANCED_FACE('',(#140),#30,.T.);
#151=ADVANCED_FACE('',(#141),#31,.T.);
#152=ADVANCED_FACE('',(#142),#32,.T.);
#153=ADVANCED_FACE('',(#143),#33,.T.);
#154=ADVANCED_FACE('',(#144),#34,.T.);
#155=ADVANCED_FACE('',(#145),#35,.T.);
#160=CLOSED_SHELL('',(#150,#151,#152,#153,#154,#155));
#170=MANIFOLD_SOLID_BREP('box',#160);
)" + step_footer();
auto bodies = import_step_from_string(step);
EXPECT_EQ(step_last_error(), StepError::Ok);
ASSERT_GE(bodies.size(), 1u);
const auto& body = bodies[0];
EXPECT_TRUE(body.is_valid());
EXPECT_GE(body.num_faces(), 6u);
EXPECT_GE(body.num_edges(), 12u);
EXPECT_GE(body.num_vertices(), 8u);
EXPECT_EQ(body.num_bodies(), 1u);
}
// ─────────────────────────────────────────────────────────────
// Test: Simple box with CIRCLE edge (cylinder top/bottom face)
// ─────────────────────────────────────────────────────────────
TEST(StepImport, SimpleCylinder) {
// A simple cylinder: bottom circle + top circle + cylindrical side surface
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',(0.0,0.0,-2.0));
#2=CARTESIAN_POINT('',(0.0,0.0,2.0));
#3=CARTESIAN_POINT('',(1.0,0.0,-2.0));
#4=CARTESIAN_POINT('',(1.0,0.0,2.0));
#10=DIRECTION('',(0.0,0.0,1.0));
#11=DIRECTION('',(1.0,0.0,0.0));
#12=DIRECTION('',(0.0,1.0,0.0));
#20=AXIS2_PLACEMENT_3D('',#1,#10,#11);
#21=AXIS2_PLACEMENT_3D('',#2,#10,#11);
#30=PLANE('',#20);
#31=PLANE('',#21);
#40=CIRCLE('',#20,1.0);
#41=CIRCLE('',#21,1.0);
#50=EDGE_CURVE('',#80,#80,#40,.T.);
#51=EDGE_CURVE('',#81,#81,#41,.T.);
#60=LINE('',#3,#10);
#70=EDGE_CURVE('',#80,#81,#60,.T.);
#80=VERTEX_POINT('',#3);
#81=VERTEX_POINT('',#4);
#90=ORIENTED_EDGE('',*,*,#50,.T.);
#91=ORIENTED_EDGE('',*,*,#51,.F.);
#92=ORIENTED_EDGE('',*,*,#70,.T.);
#100=EDGE_LOOP('',(#90));
#101=EDGE_LOOP('',(#91));
#110=FACE_OUTER_BOUND('',#100,.T.);
#111=FACE_OUTER_BOUND('',#101,.T.);
#120=ADVANCED_FACE('',(#110),#30,.T.);
#121=ADVANCED_FACE('',(#111),#31,.T.);
#142=CYLINDRICAL_SURFACE('',#20,1.0);
#143=ADVANCED_FACE('',(#110),#142,.T.);
#150=CLOSED_SHELL('',(#120,#121,#143));
#160=MANIFOLD_SOLID_BREP('cylinder',#150);
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
const auto& body = bodies[0];
EXPECT_TRUE(body.is_valid());
EXPECT_GE(body.num_faces(), 3u);
}
// ─────────────────────────────────────────────────────────────
// Test: Parse STEP with multiple bodies
// ─────────────────────────────────────────────────────────────
TEST(StepImport, MultipleBodies) {
// Two simple models: one circle-face body at origin, one at offset
std::string step = step_header() + R"(
#10=CARTESIAN_POINT('',(0.0,0.0,0.0));
#11=DIRECTION('',(0.0,0.0,1.0));
#12=DIRECTION('',(1.0,0.0,0.0));
#13=AXIS2_PLACEMENT_3D('',#10,#11,#12);
#14=CARTESIAN_POINT('',(5.0,0.0,0.0));
#15=VERTEX_POINT('',#14);
#16=CIRCLE('',#13,5.0);
#17=EDGE_CURVE('',#15,#15,#16,.T.);
#18=ORIENTED_EDGE('',*,*,#17,.T.);
#19=EDGE_LOOP('',(#18));
#20=FACE_OUTER_BOUND('',#19,.T.);
#21=PLANE('',#13);
#22=ADVANCED_FACE('',(#20),#21,.T.);
#23=CLOSED_SHELL('',(#22));
#24=MANIFOLD_SOLID_BREP('body1',#23);
#30=CARTESIAN_POINT('',(20.0,0.0,0.0));
#31=AXIS2_PLACEMENT_3D('',#30,#11,#12);
#32=CARTESIAN_POINT('',(23.0,0.0,0.0));
#33=VERTEX_POINT('',#32);
#34=CIRCLE('',#31,3.0);
#35=EDGE_CURVE('',#33,#33,#34,.T.);
#36=ORIENTED_EDGE('',*,*,#35,.T.);
#37=EDGE_LOOP('',(#36));
#38=FACE_OUTER_BOUND('',#37,.T.);
#39=PLANE('',#31);
#40=ADVANCED_FACE('',(#38),#39,.T.);
#41=CLOSED_SHELL('',(#40));
#42=MANIFOLD_SOLID_BREP('body2',#41);
)" + step_footer();
auto bodies = import_step_from_string(step);
EXPECT_EQ(step_last_error(), StepError::Ok);
ASSERT_GE(bodies.size(), 2u);
EXPECT_TRUE(bodies[0].is_valid());
EXPECT_TRUE(bodies[1].is_valid());
EXPECT_GE(bodies[0].num_faces(), 1u);
EXPECT_GE(bodies[1].num_faces(), 1u);
}
// ─────────────────────────────────────────────────────────────
// Test: Invalid input → graceful error
// ─────────────────────────────────────────────────────────────
TEST(StepImport, EmptyInput) {
auto bodies = import_step_from_string("");
EXPECT_NE(step_last_error(), StepError::Ok);
EXPECT_TRUE(bodies.empty());
}
TEST(StepImport, GarbageInput) {
auto bodies = import_step_from_string("this is not a step file at all");
EXPECT_NE(step_last_error(), StepError::Ok);
EXPECT_TRUE(bodies.empty());
}
TEST(StepImport, MissingEndsec) {
std::string step = step_header() + "#1=CARTESIAN_POINT('',(0,0,0));";
// Missing ENDSEC and footer
auto bodies = import_step_from_string(step);
// May or may not produce bodies depending on where it fails
// But should not crash
EXPECT_NO_THROW(import_step_from_string(step));
}
TEST(StepImport, OnlyHeader) {
std::string step = step_header() + step_footer();
auto bodies = import_step_from_string(step);
// Empty DATA section → no bodies
EXPECT_EQ(bodies.size(), 0u);
}
TEST(StepImport, MissingEntityId) {
std::string step = step_header() + "CARTESIAN_POINT('',(0,0,0));\n" + step_footer();
auto bodies = import_step_from_string(step);
EXPECT_NE(step_last_error(), StepError::Ok);
}
// ─────────────────────────────────────────────────────────────
// Test: Circle and ellipse curves
// ─────────────────────────────────────────────────────────────
TEST(StepImport, CircleCurve) {
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',(0.0,0.0,0.0));
#2=DIRECTION('',(0.0,0.0,1.0));
#3=DIRECTION('',(1.0,0.0,0.0));
#4=AXIS2_PLACEMENT_3D('',#1,#2,#3);
#5=CARTESIAN_POINT('',(5.0,0.0,0.0));
#6=VERTEX_POINT('',#5);
#7=CIRCLE('',#4,5.0);
#8=EDGE_CURVE('',#6,#6,#7,.T.);
#9=ORIENTED_EDGE('',*,*,#8,.T.);
#10=EDGE_LOOP('',(#9));
#11=FACE_OUTER_BOUND('',#10,.T.);
#12=PLANE('',#4);
#13=ADVANCED_FACE('',(#11),#12,.T.);
#14=CLOSED_SHELL('',(#13));
#15=MANIFOLD_SOLID_BREP('circle_test',#14);
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
EXPECT_TRUE(bodies[0].is_valid());
EXPECT_GE(bodies[0].num_vertices(), 1u);
}
TEST(StepImport, EllipseCurve) {
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',(0.0,0.0,0.0));
#2=DIRECTION('',(0.0,0.0,1.0));
#3=DIRECTION('',(1.0,0.0,0.0));
#4=AXIS2_PLACEMENT_3D('',#1,#2,#3);
#5=CARTESIAN_POINT('',(3.0,0.0,0.0));
#6=VERTEX_POINT('',#5);
#7=ELLIPSE('',#4,3.0,1.0);
#8=EDGE_CURVE('',#6,#6,#7,.T.);
#9=ORIENTED_EDGE('',*,*,#8,.T.);
#10=EDGE_LOOP('',(#9));
#11=FACE_OUTER_BOUND('',#10,.T.);
#12=PLANE('',#4);
#13=ADVANCED_FACE('',(#11),#12,.T.);
#14=CLOSED_SHELL('',(#13));
#15=MANIFOLD_SOLID_BREP('ellipse_test',#14);
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
EXPECT_TRUE(bodies[0].is_valid());
}
// ─────────────────────────────────────────────────────────────
// Test: STEP surfaces
// ─────────────────────────────────────────────────────────────
TEST(StepImport, SphericalSurface) {
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',(0.0,0.0,0.0));
#2=CARTESIAN_POINT('',(1.0,0.0,0.0));
#3=DIRECTION('',(0.0,0.0,1.0));
#4=DIRECTION('',(1.0,0.0,0.0));
#5=AXIS2_PLACEMENT_3D('',#1,#3,#4);
#6=VERTEX_POINT('',#2);
#7=SPHERICAL_SURFACE('',#5,5.0);
#8=CIRCLE('',#5,5.0);
#9=EDGE_CURVE('',#6,#6,#8,.T.);
#10=ORIENTED_EDGE('',*,*,#9,.T.);
#11=EDGE_LOOP('',(#10));
#12=FACE_OUTER_BOUND('',#11,.T.);
#13=ADVANCED_FACE('',(#12),#7,.T.);
#14=CLOSED_SHELL('',(#13));
#15=MANIFOLD_SOLID_BREP('sphere',#14);
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
EXPECT_TRUE(bodies[0].is_valid());
EXPECT_GE(bodies[0].num_faces(), 1u);
}
TEST(StepImport, ToroidalSurface) {
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',(0.0,0.0,0.0));
#2=DIRECTION('',(0.0,0.0,1.0));
#3=DIRECTION('',(1.0,0.0,0.0));
#4=AXIS2_PLACEMENT_3D('',#1,#2,#3);
#5=CARTESIAN_POINT('',(8.0,0.0,0.0));
#6=VERTEX_POINT('',#5);
#7=TOROIDAL_SURFACE('',#4,5.0,2.0);
#8=CIRCLE('',#4,5.0);
#9=EDGE_CURVE('',#6,#6,#8,.T.);
#10=ORIENTED_EDGE('',*,*,#9,.T.);
#11=EDGE_LOOP('',(#10));
#12=FACE_OUTER_BOUND('',#11,.T.);
#13=ADVANCED_FACE('',(#12),#7,.T.);
#14=CLOSED_SHELL('',(#13));
#15=MANIFOLD_SOLID_BREP('torus',#14);
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
EXPECT_TRUE(bodies[0].is_valid());
}
// ─────────────────────────────────────────────────────────────
// Test: B_SPLINE_CURVE and B_SPLINE_SURFACE
// ─────────────────────────────────────────────────────────────
TEST(StepImport, BSplineCurve) {
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',(0.0,0.0,0.0));
#2=CARTESIAN_POINT('',(1.0,2.0,0.0));
#3=CARTESIAN_POINT('',(3.0,1.0,0.0));
#4=CARTESIAN_POINT('',(4.0,0.0,0.0));
#10=B_SPLINE_CURVE_WITH_KNOTS('',3,(#1,#2,#3,#4),.UNSPECIFIED.,.F.,.F.,(4,1,1,4),(0.0,0.25,0.75,1.0),.PIECEWISE_BEZIER_KNOTS.);
#11=CARTESIAN_POINT('',(0.0,0.0,0.0));
#12=CARTESIAN_POINT('',(4.0,0.0,0.0));
#20=VERTEX_POINT('',#11);
#21=VERTEX_POINT('',#12);
#30=EDGE_CURVE('',#20,#21,#10,.T.);
#40=LINE('',#11,#12);
#41=EDGE_CURVE('',#21,#20,#40,.T.);
#50=ORIENTED_EDGE('',*,*,#30,.T.);
#51=ORIENTED_EDGE('',*,*,#41,.T.);
#60=EDGE_LOOP('',(#50,#51));
#61=FACE_OUTER_BOUND('',#60,.T.);
#70=DIRECTION('',(0.0,0.0,1.0));
#71=DIRECTION('',(1.0,0.0,0.0));
#72=AXIS2_PLACEMENT_3D('',#11,#70,#71);
#73=PLANE('',#72);
#80=ADVANCED_FACE('',(#61),#73,.T.);
#90=CLOSED_SHELL('',(#80));
#100=MANIFOLD_SOLID_BREP('bspline_curve',#90);
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
EXPECT_TRUE(bodies[0].is_valid());
}
// ─────────────────────────────────────────────────────────────
// Test: Round-trip (create → export is not available, but we
// can test creating a BrepModel programmatically and compare)
// ─────────────────────────────────────────────────────────────
TEST(StepImport, ProgrammaticBrepCanBeUsed) {
auto box = make_box(2.0, 2.0, 2.0);
EXPECT_TRUE(box.is_valid());
// Verify the box can be tessellated
auto mesh = box.to_mesh();
EXPECT_GT(mesh.num_faces(), 0u);
// Verify face and edge queries work after import
auto edges = box.face_edges(0);
EXPECT_FALSE(edges.empty());
auto efs = box.edge_faces(0);
EXPECT_FALSE(efs.empty());
}
// ─────────────────────────────────────────────────────────────
// Test: String escaping in STEP
// ─────────────────────────────────────────────────────────────
TEST(StepImport, StringEscaping) {
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('name with spaces',(1.0,2.0,3.0));
#2=CARTESIAN_POINT('it''s escaped',(4.0,5.0,6.0));
)" + step_footer();
auto bodies = import_step_from_string(step);
// No bodies (no topology) but should not crash
EXPECT_EQ(bodies.size(), 0u);
}
// ─────────────────────────────────────────────────────────────
// Test: Entities with omitted parameters ($)
// ─────────────────────────────────────────────────────────────
TEST(StepImport, OmittedParameters) {
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',(0.0,0.0,0.0));
#2=DIRECTION('',(0.0,0.0,1.0));
#3=AXIS2_PLACEMENT_3D('',#1,#2,$);
#4=CARTESIAN_POINT('',(5.0,0.0,0.0));
#5=VERTEX_POINT('',#4);
#6=CIRCLE('',#3,5.0);
#7=EDGE_CURVE('',#5,#5,#6,.T.);
#8=ORIENTED_EDGE('',*,*,#7,.T.);
#9=EDGE_LOOP('',(#8));
#10=FACE_OUTER_BOUND('',#9,.T.);
#11=PLANE('',#3);
#12=ADVANCED_FACE('',(#10),#11,.T.);
#13=CLOSED_SHELL('',(#12));
#14=MANIFOLD_SOLID_BREP('omitted_test',#13);
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
EXPECT_TRUE(bodies[0].is_valid());
}
// ─────────────────────────────────────────────────────────────
// Test: STEP file with comments
// ─────────────────────────────────────────────────────────────
TEST(StepImport, Comments) {
std::string step = step_header() + R"(
/* This is a comment block */
#1=CARTESIAN_POINT('',(0.0,0.0,0.0)); /* inline comment */
#2=DIRECTION('',(0.0,0.0,1.0));
#3=AXIS2_PLACEMENT_3D('',#1,#2,$);
#4=CARTESIAN_POINT('',(5.0,0.0,0.0));
#5=VERTEX_POINT('',#4);
#6=CIRCLE('',#3,5.0);
#7=EDGE_CURVE('',#5,#5,#6,.T.);
#8=ORIENTED_EDGE('',*,*,#7,.T.);
#9=EDGE_LOOP('',(#8));
#10=FACE_OUTER_BOUND('',#9,.T.);
#11=PLANE('',#3);
#12=ADVANCED_FACE('',(#10),#11,.T.);
#13=CLOSED_SHELL('',(#12));
#14=MANIFOLD_SOLID_BREP('commented',#13);
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
EXPECT_TRUE(bodies[0].is_valid());
}
// ─────────────────────────────────────────────────────────────
// Test: Multi-line entities
// ─────────────────────────────────────────────────────────────
TEST(StepImport, MultiLineEntities) {
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',
(0.0,0.0,0.0));
#2=CARTESIAN_POINT('',(
5.0,0.0,0.0));
#3=DIRECTION('',
(0.0,0.0,1.0));
#4=AXIS2_PLACEMENT_3D('point',
#1,#3,$);
#5=VERTEX_POINT('',#2);
#6=CIRCLE('round',#4,5.0);
#7=EDGE_CURVE('edge',
#5,#5,#6,.T.);
#8=ORIENTED_EDGE('',*,*,#7,.T.);
#9=EDGE_LOOP('',(#8));
#10=FACE_OUTER_BOUND('',#9,.T.);
#11=PLANE('flat',#4);
#12=ADVANCED_FACE('face',(#10),#11,.T.);
#13=CLOSED_SHELL('shell',(#12));
#14=MANIFOLD_SOLID_BREP('solid',#13);
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
EXPECT_TRUE(bodies[0].is_valid());
}
// ─────────────────────────────────────────────────────────────
// Test: SHELL_BASED_SURFACE_MODEL (alternative to MANIFOLD_SOLID_BREP)
// ─────────────────────────────────────────────────────────────
TEST(StepImport, ShellBasedSurfaceModel) {
std::string step = step_header() + R"(
#1=CARTESIAN_POINT('',(0.0,0.0,0.0));
#2=DIRECTION('',(0.0,0.0,1.0));
#3=AXIS2_PLACEMENT_3D('',#1,#2,$);
#4=CARTESIAN_POINT('',(3.0,0.0,0.0));
#5=VERTEX_POINT('',#4);
#6=CIRCLE('',#3,3.0);
#7=EDGE_CURVE('',#5,#5,#6,.T.);
#8=ORIENTED_EDGE('',*,*,#7,.T.);
#9=EDGE_LOOP('',(#8));
#10=FACE_OUTER_BOUND('',#9,.T.);
#11=PLANE('',#3);
#12=ADVANCED_FACE('',(#10),#11,.T.);
#13=CLOSED_SHELL('',(#12));
#14=SHELL_BASED_SURFACE_MODEL('',(#13));
)" + step_footer();
auto bodies = import_step_from_string(step);
ASSERT_GE(bodies.size(), 1u);
EXPECT_TRUE(bodies[0].is_valid());
EXPECT_GE(bodies[0].num_faces(), 1u);
}