From 8790b07773a126c17b8dd115baae07ee1985d6f5 Mon Sep 17 00:00:00 2001 From: Kris Austin Date: Thu, 8 Oct 2026 16:10:37 -0500 Subject: [PATCH] fix: missing chamfers on STEP import since the OCCT 8.0.1 update (#16290) --- ...epMesh-seam-pcurve-at-edge-parameter.patch | 28 +++ deps/OCCT/OCCT.cmake | 7 + tests/data/cone_tilted_seam_pcurve.step | 166 ++++++++++++++++++ tests/libslic3r/test_step.cpp | 18 ++ 4 files changed, 219 insertions(+) create mode 100644 deps/OCCT/0001-BRepMesh-seam-pcurve-at-edge-parameter.patch create mode 100644 tests/data/cone_tilted_seam_pcurve.step diff --git a/deps/OCCT/0001-BRepMesh-seam-pcurve-at-edge-parameter.patch b/deps/OCCT/0001-BRepMesh-seam-pcurve-at-edge-parameter.patch new file mode 100644 index 0000000000..84c599a5f3 --- /dev/null +++ b/deps/OCCT/0001-BRepMesh-seam-pcurve-at-edge-parameter.patch @@ -0,0 +1,28 @@ +diff --git a/src/ModelingAlgorithms/TKMesh/BRepMesh/BRepMesh_ModelPreProcessor.cxx b/src/ModelingAlgorithms/TKMesh/BRepMesh/BRepMesh_ModelPreProcessor.cxx +index 6f63781..9b1c08e 100644 +--- a/src/ModelingAlgorithms/TKMesh/BRepMesh/BRepMesh_ModelPreProcessor.cxx ++++ b/src/ModelingAlgorithms/TKMesh/BRepMesh/BRepMesh_ModelPreProcessor.cxx +@@ -210,10 +210,10 @@ private: + + // Define two pcurves of the seam-edge. + occ::handle aPC1, aPC2; +- double af, al; ++ double af, al, af1, al1; + + aE.Orientation(TopAbs_FORWARD); +- aPC1 = BRep_Tool::CurveOnSurface(aE, aF, af, al); ++ aPC1 = BRep_Tool::CurveOnSurface(aE, aF, af1, al1); + + aE.Orientation(TopAbs_REVERSED); + aPC2 = BRep_Tool::CurveOnSurface(aE, aF, af, al); +@@ -224,7 +224,9 @@ private: + } + + // Select the correct pcurve of the seam-edge. +- const gp_Pnt2d& aFPntOfPC1 = aPC1->Value(aPC1->FirstParameter()); ++ // Use the edge's first parameter. A Geom2d_Line's FirstParameter() is -Precision::Infinite(), ++ // where a direction of (2e-16, -1) from rounding error gives an X far outside the U range. ++ const gp_Pnt2d aFPntOfPC1 = aPC1->Value(af1); + + if (std::abs(aLPntOfIPC1.X() - aFPntOfPC1.X()) > Precision::Confusion()) + { diff --git a/deps/OCCT/OCCT.cmake b/deps/OCCT/OCCT.cmake index 4cab60ec6a..0466d8e868 100644 --- a/deps/OCCT/OCCT.cmake +++ b/deps/OCCT/OCCT.cmake @@ -25,9 +25,16 @@ endif() # shipped bytes. Windows ships only the DLLs libslic3r links, so the tab adds the TKFillet, # TKOffset and TKBool DLLs. See docs/HLSD/design-tab.md. +if (IN_GIT_REPO) + set(OCCT_DIRECTORY_FLAG --directory ${BINARY_DIR_REL}/dep_OCCT-prefix/src/dep_OCCT) +endif () + orcaslicer_add_cmake_project(OCCT URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V8_0_1.zip URL_HASH SHA256=7c033d917ee8f040c0512d289dcc5f02c148889d5bac17c3e25639accb44f0da + # Makes BRepMesh triangulate cone faces whose seam pcurve is slightly tilted + # (Open-Cascade-SAS/OCCT#572); remove the patch once an OCCT release includes the fix. + PATCH_COMMAND git apply ${OCCT_DIRECTORY_FLAG} --verbose --ignore-space-change --whitespace=fix ${CMAKE_CURRENT_LIST_DIR}/0001-BRepMesh-seam-pcurve-at-edge-parameter.patch #DEPENDS dep_Boost DEPENDS ${FREETYPE_PKG} CMAKE_ARGS diff --git a/tests/data/cone_tilted_seam_pcurve.step b/tests/data/cone_tilted_seam_pcurve.step new file mode 100644 index 0000000000..172012114b --- /dev/null +++ b/tests/data/cone_tilted_seam_pcurve.step @@ -0,0 +1,166 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('Open CASCADE Model'),'2;1'); +FILE_NAME('Open CASCADE Shape Model','2026-10-08T09:57:33',('Author'),( + 'Open CASCADE'),'Open CASCADE STEP processor 8.0','Open CASCADE 8.0' + ,'Unknown'); +FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }')); +ENDSEC; +DATA; +#1 = APPLICATION_PROTOCOL_DEFINITION('international standard', + 'automotive_design',2000,#2); +#2 = APPLICATION_CONTEXT( + 'core data for automotive mechanical design processes'); +#3 = SHAPE_DEFINITION_REPRESENTATION(#4,#10); +#4 = PRODUCT_DEFINITION_SHAPE('','',#5); +#5 = PRODUCT_DEFINITION('design','',#6,#9); +#6 = PRODUCT_DEFINITION_FORMATION('','',#7); +#7 = PRODUCT('Open CASCADE STEP translator 8.0 1', + 'Open CASCADE STEP translator 8.0 1','',(#8)); +#8 = PRODUCT_CONTEXT('',#2,'mechanical'); +#9 = PRODUCT_DEFINITION_CONTEXT('part definition',#2,'design'); +#10 = ADVANCED_BREP_SHAPE_REPRESENTATION('',(#11,#15),#121); +#11 = AXIS2_PLACEMENT_3D('',#12,#13,#14); +#12 = CARTESIAN_POINT('',(0.,0.,0.)); +#13 = DIRECTION('',(0.,0.,1.)); +#14 = DIRECTION('',(1.,0.,-0.)); +#15 = MANIFOLD_SOLID_BREP('',#16); +#16 = CLOSED_SHELL('',(#17,#113,#117)); +#17 = ADVANCED_FACE('',(#18),#31,.T.); +#18 = FACE_BOUND('',#19,.T.); +#19 = EDGE_LOOP('',(#20,#58,#81,#112)); +#20 = ORIENTED_EDGE('',*,*,#21,.F.); +#21 = EDGE_CURVE('',#22,#22,#24,.T.); +#22 = VERTEX_POINT('',#23); +#23 = CARTESIAN_POINT('',(-36.4,0.,25.)); +#24 = SURFACE_CURVE('',#25,(#30,#42),.PCURVE_S1.); +#25 = CIRCLE('',#26,36.4); +#26 = AXIS2_PLACEMENT_3D('',#27,#28,#29); +#27 = CARTESIAN_POINT('',(0.,0.,25.)); +#28 = DIRECTION('',(0.,0.,1.)); +#29 = DIRECTION('',(1.,0.,-0.)); +#30 = PCURVE('',#31,#36); +#31 = CONICAL_SURFACE('',#32,36.4,0.785398163397); +#32 = AXIS2_PLACEMENT_3D('',#33,#34,#35); +#33 = CARTESIAN_POINT('',(0.,0.,25.)); +#34 = DIRECTION('',(0.,0.,1.)); +#35 = DIRECTION('',(1.,0.,-0.)); +#36 = DEFINITIONAL_REPRESENTATION('',(#37),#41); +#37 = LINE('',#38,#39); +#38 = CARTESIAN_POINT('',(-6.28318530718,3.552713678801E-15)); +#39 = VECTOR('',#40,1.); +#40 = DIRECTION('',(1.,0.)); +#41 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#42 = PCURVE('',#43,#48); +#43 = PLANE('',#44); +#44 = AXIS2_PLACEMENT_3D('',#45,#46,#47); +#45 = CARTESIAN_POINT('',(0.,0.,25.)); +#46 = DIRECTION('',(-0.,-0.,-1.)); +#47 = DIRECTION('',(-1.,0.,0.)); +#48 = DEFINITIONAL_REPRESENTATION('',(#49),#57); +#49 = ( BOUNDED_CURVE() B_SPLINE_CURVE(2,(#50,#51,#52,#53,#54,#55,#56), +.UNSPECIFIED.,.T.,.F.) B_SPLINE_CURVE_WITH_KNOTS((1,2,2,2,2,1),( + -2.094395102393,0.,2.094395102393,4.188790204786,6.28318530718, +8.377580409573),.UNSPECIFIED.) CURVE() GEOMETRIC_REPRESENTATION_ITEM() +RATIONAL_B_SPLINE_CURVE((1.,0.5,1.,0.5,1.,0.5,1.)) REPRESENTATION_ITEM( + '') ); +#50 = CARTESIAN_POINT('',(-36.4,0.)); +#51 = CARTESIAN_POINT('',(-36.4,63.046649395507)); +#52 = CARTESIAN_POINT('',(18.2,31.523324697754)); +#53 = CARTESIAN_POINT('',(72.8,8.915428697793E-15)); +#54 = CARTESIAN_POINT('',(18.2,-31.52332469775)); +#55 = CARTESIAN_POINT('',(-36.4,-63.0466493955)); +#56 = CARTESIAN_POINT('',(-36.4,0.)); +#57 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#58 = ORIENTED_EDGE('',*,*,#59,.T.); +#59 = EDGE_CURVE('',#22,#60,#62,.T.); +#60 = VERTEX_POINT('',#61); +#61 = CARTESIAN_POINT('',(-11.4,0.,3.552713678801E-15)); +#62 = SEAM_CURVE('',#63,(#67,#74),.PCURVE_S1.); +#63 = LINE('',#64,#65); +#64 = CARTESIAN_POINT('',(-36.4,0.,25.)); +#65 = VECTOR('',#66,1.); +#66 = DIRECTION('',(0.707106781187,8.659560562349E-17,-0.707106781187)); +#67 = PCURVE('',#31,#68); +#68 = DEFINITIONAL_REPRESENTATION('',(#69),#73); +#69 = LINE('',#70,#71); +#70 = CARTESIAN_POINT('',(-3.14159265359,3.552713678801E-15)); +#71 = VECTOR('',#72,1.); +#72 = DIRECTION('',(2.13162820728E-16,-1.)); +#73 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#74 = PCURVE('',#31,#75); +#75 = DEFINITIONAL_REPRESENTATION('',(#76),#80); +#76 = LINE('',#77,#78); +#77 = CARTESIAN_POINT('',(3.14159265359,3.552713678801E-15)); +#78 = VECTOR('',#79,1.); +#79 = DIRECTION('',(2.13162820728E-16,-1.)); +#80 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#81 = ORIENTED_EDGE('',*,*,#82,.F.); +#82 = EDGE_CURVE('',#60,#60,#83,.T.); +#83 = SURFACE_CURVE('',#84,(#89,#96),.PCURVE_S1.); +#84 = CIRCLE('',#85,11.4); +#85 = AXIS2_PLACEMENT_3D('',#86,#87,#88); +#86 = CARTESIAN_POINT('',(0.,0.,3.552713678801E-15)); +#87 = DIRECTION('',(0.,0.,-1.)); +#88 = DIRECTION('',(1.,0.,0.)); +#89 = PCURVE('',#31,#90); +#90 = DEFINITIONAL_REPRESENTATION('',(#91),#95); +#91 = LINE('',#92,#93); +#92 = CARTESIAN_POINT('',(6.28318530718,-25.)); +#93 = VECTOR('',#94,1.); +#94 = DIRECTION('',(-1.,0.)); +#95 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#96 = PCURVE('',#97,#102); +#97 = PLANE('',#98); +#98 = AXIS2_PLACEMENT_3D('',#99,#100,#101); +#99 = CARTESIAN_POINT('',(0.,0.,3.552713678801E-15)); +#100 = DIRECTION('',(0.,0.,1.)); +#101 = DIRECTION('',(1.,0.,-0.)); +#102 = DEFINITIONAL_REPRESENTATION('',(#103),#111); +#103 = ( BOUNDED_CURVE() B_SPLINE_CURVE(2,(#104,#105,#106,#107,#108,#109 +,#110),.UNSPECIFIED.,.T.,.F.) B_SPLINE_CURVE_WITH_KNOTS((1,2,2,2,2,1),( + -2.094395102393,0.,2.094395102393,4.188790204786,6.28318530718, +8.377580409573),.UNSPECIFIED.) CURVE() GEOMETRIC_REPRESENTATION_ITEM() +RATIONAL_B_SPLINE_CURVE((1.,0.5,1.,0.5,1.,0.5,1.)) REPRESENTATION_ITEM( + '') ); +#104 = CARTESIAN_POINT('',(11.4,0.)); +#105 = CARTESIAN_POINT('',(11.4,-19.74537920628)); +#106 = CARTESIAN_POINT('',(-5.7,-9.872689603143)); +#107 = CARTESIAN_POINT('',(-22.8,-2.792194702056E-15)); +#108 = CARTESIAN_POINT('',(-5.7,9.872689603143)); +#109 = CARTESIAN_POINT('',(11.4,19.745379206285)); +#110 = CARTESIAN_POINT('',(11.4,0.)); +#111 = ( GEOMETRIC_REPRESENTATION_CONTEXT(2) +PARAMETRIC_REPRESENTATION_CONTEXT() REPRESENTATION_CONTEXT('2D SPACE','' + ) ); +#112 = ORIENTED_EDGE('',*,*,#59,.F.); +#113 = ADVANCED_FACE('',(#114),#43,.F.); +#114 = FACE_BOUND('',#115,.F.); +#115 = EDGE_LOOP('',(#116)); +#116 = ORIENTED_EDGE('',*,*,#21,.F.); +#117 = ADVANCED_FACE('',(#118),#97,.F.); +#118 = FACE_BOUND('',#119,.F.); +#119 = EDGE_LOOP('',(#120)); +#120 = ORIENTED_EDGE('',*,*,#82,.F.); +#121 = ( GEOMETRIC_REPRESENTATION_CONTEXT(3) +GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#125)) GLOBAL_UNIT_ASSIGNED_CONTEXT +((#122,#123,#124)) REPRESENTATION_CONTEXT('Context #1', + '3D Context with UNIT and UNCERTAINTY') ); +#122 = ( LENGTH_UNIT() NAMED_UNIT(*) SI_UNIT(.MILLI.,.METRE.) ); +#123 = ( NAMED_UNIT(*) PLANE_ANGLE_UNIT() SI_UNIT($,.RADIAN.) ); +#124 = ( NAMED_UNIT(*) SI_UNIT($,.STERADIAN.) SOLID_ANGLE_UNIT() ); +#125 = UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(1.E-07),#122, + 'distance_accuracy_value','confusion accuracy'); +#126 = PRODUCT_RELATED_PRODUCT_CATEGORY('part',$,(#7)); +ENDSEC; +END-ISO-10303-21; diff --git a/tests/libslic3r/test_step.cpp b/tests/libslic3r/test_step.cpp index 0bb83f5809..5d843499fa 100644 --- a/tests/libslic3r/test_step.cpp +++ b/tests/libslic3r/test_step.cpp @@ -8,6 +8,7 @@ #include #include "libslic3r/Model.hpp" #include "libslic3r/Format/STEP.hpp" +#include "libslic3r/TriangleMesh.hpp" #include "test_utils.hpp" using namespace Slic3r; @@ -73,6 +74,23 @@ TEST_CASE("A security classification assignment does not crash import", "[Step]" CHECK(model.objects.front()->volumes.front()->mesh().facets_count() == 4); // a tetrahedron } +// The fixture is a truncated cone whose seam pcurves have the direction (2.1e-16, -1). +TEST_CASE("A cone with a slightly tilted seam imports as a closed mesh", "[Step]") +{ + const std::string path = std::string(TEST_DATA_DIR) + PATH_SEPARATOR "cone_tilted_seam_pcurve.step"; + + Model model; + bool cancel = false; + Step step(path); + + REQUIRE(step.load() == Step::Step_Status::LOAD_SUCCESS); + REQUIRE(step.mesh(&model, cancel, false) == Step::Step_Status::MESH_SUCCESS); + + REQUIRE(model.objects.size() == 1); + REQUIRE(model.objects.front()->volumes.size() == 1); + CHECK(its_num_open_edges(model.objects.front()->volumes.front()->mesh().its) == 0); +} + TEST_CASE("isUtf8 recognises two, three and four byte sequences", "[Step]") { CHECK(StepPreProcessor::isUtf8("\xC3\xA9")); // U+00E9