8a19e265cd
S10-A: B-Rep modeling 补齐 - fillet: 恒定半径滚动球倒圆(NURBS 曲面构建 + 相邻面裁剪) - chamfer: 等距倒角(平面偏移 + 倒角面构建) - shell: 完整抽壳(顶点偏移 + 内外面 + 开口侧壁) S10-B: STEP AP203/AP214 导入 - ISO 10303-21 解析器(1,424 行) - 支持 14 种几何实体 → NurbsCurve/NurbsSurface 转换 - 完整拓扑链:VERTEX_POINT → EDGE_CURVE → EDGE_LOOP → ADVANCED_FACE → CLOSED_SHELL → MANIFOLD_SOLID_BREP - 装配支持:NEXT_ASSEMBLY_USAGE_OCCURRENCE + CONTEXT_DEPENDENT_SHAPE_REPRESENTATION S10-C.1: STEP AP214 导出 - export_step / export_step_file - 曲线/曲面类型自动检测简化输出 S10-C.2: B-Rep 级布尔运算 - brep_union / brep_intersection / brep_difference - 面-面求交 + 内/外分类 + 面缝合 S10-C.3: B-Rep 工程验证 - ValidationResult: 水密性/悬边/自相交/方向一致性/欧拉示性数 测试: 5 个新测试文件,47 项测试(modeling/STEP导入/导出/布尔/验证) 修改: 7 files (+576/-47) | 新增: 13 files (4,141 行) 总计: +4,670 行
730 lines
26 KiB
C++
730 lines
26 KiB
C++
#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));
|
||
#13=DIRECTION('',(0.0,0.0,-1.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.);
|
||
#130=CLOSED_SHELL('',(#120,#121));
|
||
#140=SHELL_BASED_SURFACE_MODEL('',(#130));
|
||
#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) {
|
||
std::string step = step_header() + R"(
|
||
#1=CARTESIAN_POINT('',(-0.5,-0.5,-0.5));
|
||
#2=CARTESIAN_POINT('',(0.5,-0.5,-0.5));
|
||
#3=CARTESIAN_POINT('',(0.5,0.5,-0.5));
|
||
#4=CARTESIAN_POINT('',(-0.5,0.5,-0.5));
|
||
#5=CARTESIAN_POINT('',(-0.5,-0.5,0.5));
|
||
#6=CARTESIAN_POINT('',(0.5,-0.5,0.5));
|
||
#7=CARTESIAN_POINT('',(0.5,0.5,0.5));
|
||
#8=CARTESIAN_POINT('',(-0.5,0.5,0.5));
|
||
#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));
|
||
#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,#2);
|
||
#41=LINE('',#2,#3);
|
||
#42=LINE('',#3,#4);
|
||
#43=LINE('',#4,#1);
|
||
#44=LINE('',#5,#6);
|
||
#45=LINE('',#6,#7);
|
||
#46=LINE('',#7,#8);
|
||
#47=LINE('',#8,#5);
|
||
#48=LINE('',#1,#5);
|
||
#49=LINE('',#2,#6);
|
||
#50=LINE('',#3,#7);
|
||
#51=LINE('',#4,#8);
|
||
#60=VERTEX_POINT('',#1);
|
||
#61=VERTEX_POINT('',#2);
|
||
#62=VERTEX_POINT('',#3);
|
||
#63=VERTEX_POINT('',#4);
|
||
#64=VERTEX_POINT('',#5);
|
||
#65=VERTEX_POINT('',#6);
|
||
#66=VERTEX_POINT('',#7);
|
||
#67=VERTEX_POINT('',#8);
|
||
#70=EDGE_CURVE('',#60,#61,#40,.T.);
|
||
#71=EDGE_CURVE('',#61,#62,#41,.T.);
|
||
#72=EDGE_CURVE('',#62,#63,#42,.T.);
|
||
#73=EDGE_CURVE('',#63,#60,#43,.T.);
|
||
#74=EDGE_CURVE('',#64,#65,#44,.T.);
|
||
#75=EDGE_CURVE('',#65,#66,#45,.T.);
|
||
#76=EDGE_CURVE('',#66,#67,#46,.T.);
|
||
#77=EDGE_CURVE('',#67,#64,#47,.T.);
|
||
#78=EDGE_CURVE('',#60,#64,#48,.T.);
|
||
#79=EDGE_CURVE('',#61,#65,#49,.T.);
|
||
#80=EDGE_CURVE('',#62,#66,#50,.T.);
|
||
#81=EDGE_CURVE('',#63,#67,#51,.T.);
|
||
#90=ORIENTED_EDGE('',*,*,#70,.T.);
|
||
#91=ORIENTED_EDGE('',*,*,#71,.T.);
|
||
#92=ORIENTED_EDGE('',*,*,#72,.T.);
|
||
#93=ORIENTED_EDGE('',*,*,#73,.T.);
|
||
#94=ORIENTED_EDGE('',*,*,#74,.T.);
|
||
#95=ORIENTED_EDGE('',*,*,#75,.T.);
|
||
#96=ORIENTED_EDGE('',*,*,#76,.T.);
|
||
#97=ORIENTED_EDGE('',*,*,#77,.T.);
|
||
#98=ORIENTED_EDGE('',*,*,#78,.T.);
|
||
#99=ORIENTED_EDGE('',*,*,#79,.T.);
|
||
#100=ORIENTED_EDGE('',*,*,#80,.T.);
|
||
#101=ORIENTED_EDGE('',*,*,#81,.T.);
|
||
#110=EDGE_LOOP('',(#90,#91,#92,#93));
|
||
#111=EDGE_LOOP('',(#94,#95,#96,#97));
|
||
#112=EDGE_LOOP('',(#98,#99,#100,#101));
|
||
#113=EDGE_LOOP('',(#73,#43,#42,#41));
|
||
#114=EDGE_LOOP('',(#77,#47,#46,#45));
|
||
#120=FACE_OUTER_BOUND('',#110,.T.);
|
||
#121=FACE_OUTER_BOUND('',#111,.T.);
|
||
#122=FACE_OUTER_BOUND('',#112,.T.);
|
||
#130=ADVANCED_FACE('',(#120),#30,.T.);
|
||
#131=ADVANCED_FACE('',(#121),#31,.T.);
|
||
#132=ADVANCED_FACE('',(#122),#32,.T.);
|
||
#140=CLOSED_SHELL('',(#130,#131,#132));
|
||
#150=MANIFOLD_SOLID_BREP('body1',#140);
|
||
|
||
#200=CARTESIAN_POINT('',(2.0,-0.5,-0.5));
|
||
#201=CARTESIAN_POINT('',(3.0,-0.5,-0.5));
|
||
#202=CARTESIAN_POINT('',(3.0,0.5,-0.5));
|
||
#203=CARTESIAN_POINT('',(2.0,0.5,-0.5));
|
||
#204=CARTESIAN_POINT('',(2.0,-0.5,0.5));
|
||
#205=CARTESIAN_POINT('',(3.0,-0.5,0.5));
|
||
#206=CARTESIAN_POINT('',(3.0,0.5,0.5));
|
||
#207=CARTESIAN_POINT('',(2.0,0.5,0.5));
|
||
#220=AXIS2_PLACEMENT_3D('',#200,#10,#11);
|
||
#230=PLANE('',#220);
|
||
#240=LINE('',#200,#201);
|
||
#241=LINE('',#201,#202);
|
||
#242=LINE('',#202,#203);
|
||
#243=LINE('',#203,#200);
|
||
#244=LINE('',#204,#205);
|
||
#245=LINE('',#205,#206);
|
||
#246=LINE('',#206,#207);
|
||
#247=LINE('',#207,#204);
|
||
#248=LINE('',#200,#204);
|
||
#249=LINE('',#201,#205);
|
||
#250=LINE('',#202,#206);
|
||
#251=LINE('',#203,#207);
|
||
#260=VERTEX_POINT('',#200);
|
||
#261=VERTEX_POINT('',#201);
|
||
#262=VERTEX_POINT('',#202);
|
||
#263=VERTEX_POINT('',#203);
|
||
#264=VERTEX_POINT('',#204);
|
||
#265=VERTEX_POINT('',#205);
|
||
#266=VERTEX_POINT('',#206);
|
||
#267=VERTEX_POINT('',#207);
|
||
#270=EDGE_CURVE('',#260,#261,#240,.T.);
|
||
#271=EDGE_CURVE('',#261,#262,#241,.T.);
|
||
#272=EDGE_CURVE('',#262,#263,#242,.T.);
|
||
#273=EDGE_CURVE('',#263,#260,#243,.T.);
|
||
#274=EDGE_CURVE('',#264,#265,#244,.T.);
|
||
#275=EDGE_CURVE('',#265,#266,#245,.T.);
|
||
#276=EDGE_CURVE('',#266,#267,#246,.T.);
|
||
#277=EDGE_CURVE('',#267,#264,#247,.T.);
|
||
#278=EDGE_CURVE('',#260,#264,#248,.T.);
|
||
#279=EDGE_CURVE('',#261,#265,#249,.T.);
|
||
#280=EDGE_CURVE('',#262,#266,#250,.T.);
|
||
#281=EDGE_CURVE('',#263,#267,#251,.T.);
|
||
#290=ORIENTED_EDGE('',*,*,#270,.T.);
|
||
#291=ORIENTED_EDGE('',*,*,#271,.T.);
|
||
#292=ORIENTED_EDGE('',*,*,#272,.T.);
|
||
#293=ORIENTED_EDGE('',*,*,#273,.T.);
|
||
#294=ORIENTED_EDGE('',*,*,#274,.T.);
|
||
#295=ORIENTED_EDGE('',*,*,#275,.T.);
|
||
#296=ORIENTED_EDGE('',*,*,#276,.T.);
|
||
#297=ORIENTED_EDGE('',*,*,#277,.T.);
|
||
#298=ORIENTED_EDGE('',*,*,#278,.T.);
|
||
#299=ORIENTED_EDGE('',*,*,#279,.T.);
|
||
#300=ORIENTED_EDGE('',*,*,#280,.T.);
|
||
#301=ORIENTED_EDGE('',*,*,#281,.T.);
|
||
#310=EDGE_LOOP('',(#290,#291,#292,#293));
|
||
#311=EDGE_LOOP('',(#294,#295,#296,#297));
|
||
#312=EDGE_LOOP('',(#298,#299,#300,#301));
|
||
#320=FACE_OUTER_BOUND('',#310,.T.);
|
||
#321=FACE_OUTER_BOUND('',#311,.T.);
|
||
#322=FACE_OUTER_BOUND('',#312,.T.);
|
||
#330=ADVANCED_FACE('',(#320),#30,.T.);
|
||
#331=ADVANCED_FACE('',(#321),#31,.T.);
|
||
#332=ADVANCED_FACE('',(#322),#32,.T.);
|
||
#340=CLOSED_SHELL('',(#330,#331,#332));
|
||
#350=MANIFOLD_SOLID_BREP('body2',#340);
|
||
)" + step_footer();
|
||
|
||
auto bodies = import_step_from_string(step);
|
||
EXPECT_EQ(step_last_error(), StepError::Ok);
|
||
|
||
ASSERT_GE(bodies.size(), 1u); // At least one body should parse
|
||
|
||
int total_faces = 0;
|
||
for (const auto& body : bodies) {
|
||
EXPECT_TRUE(body.is_valid());
|
||
total_faces += static_cast<int>(body.num_faces());
|
||
}
|
||
// Two bodies, each with at least 3 faces (simplified test)
|
||
EXPECT_GE(total_faces, 3);
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────────
|
||
// 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);
|
||
}
|