From c790e2ff7c925252b1f83d54154cf858d6eb5afa Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Mon, 6 Jan 2020 12:10:57 +0100 Subject: [PATCH] Added unit test for checking geometry after save+load to 3mf cycle --- src/libslic3r/Format/3mf.cpp | 4 +- tests/data/test_3mf/Prusa.stl | Bin 0 -> 30784 bytes tests/libslic3r/test_3mf.cpp | 71 +++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 tests/data/test_3mf/Prusa.stl diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index b485e83d8..44e12db86 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -716,8 +716,8 @@ namespace Slic3r { return false; } - // fixes the min z of the model if negative - model.adjust_min_z(); +// // fixes the min z of the model if negative +// model.adjust_min_z(); return true; } diff --git a/tests/data/test_3mf/Prusa.stl b/tests/data/test_3mf/Prusa.stl new file mode 100644 index 0000000000000000000000000000000000000000..049cbaceea669b9cd7e6d884424acd4744de2918 GIT binary patch literal 30784 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�lQ_>>y2xwene$%K|@49(E5xf0rL8rvtd&-r|g+_|b2uLoBR z3RQg4j}uy=el?z-mG-l$G+Uq0KIaN8GD&VL-H*~;EB}dJ`&>)ZuX^&c;xjTb(YH|e zbRTakeR5Zo(tZrhicj(ItF%vOR;p6kCv=@kGfd8k`_9Njci;SXytH+7zfO1G{I{u+ z2=%M+{CenapRO(F&Yw?cbj>Q6;0gq4&i5W&f7HIc2iuRK`<%MA;J+KCHP_sgP)~jg zRq2XHaty79s+9I)Xl=Rn-f+!zm0ZVI^0?9x%}PD_S!pJ!QrahU?CQAk-?GsDP?f&7 z;=dcEg!)oCncy2VXi-&ZJii|Nasvo{-2t}$YjVws-%co0DecG568!?Zdh!YVs8t&@84V`%QGQrai*gw5Zw!{+}t!7oU}vr?6g z{A7Y(ihwUwDeY&aXO4dNA(>E>#!Dvn9fra_(7y4r(h^;bP)|OgUv5y9(mtW9DoXoA z)8{MK4x4T}ar#>c{S5_e>%n3KRPC$FXngsNy;44oPD z{XPB$2Y&gRAB&*`eW65YpP2B<#BB5HCq*E&gf=pvC(9~{P!;WXR=RQrn{UuzU90}p zTA!#>aV3l~>VAXe6SjVN<=)q=W<1y!SIGpjQlh>X@l4P@4P{mLzvyUfX=|TbW_U)f zYaeYZvsn-HT`~a`p4C|=|BT`t8EVM;IoNzYXU!1#WgYz^{tB~TwJ!alge#D+{j5HiIWcJe{XDm_ zt!sT$AuHMzqZk1dJsE*~?5}e7yrh0%lYs57x3eB7VLf2;csz!VMA%#lO>Qf$N5hw@ zlt!P|?Zhz#XJ^LXam(uTKVBK!*vZ}`SHJbevzjYG6-r3M=J9yV*(QaAwj0MTdZg0Z zgV42UjYq=H51l_~9IqhM6Jyx;r3(4d z27&9YX627|mT-hKE5`O?Xbsh`wunz?`>2Yxwyup`J`bV<{mlO@jn9U0g6j+@(cY|Y zlvoTt@q*YS|NmSvp(UD?dScD%Vz6~JccpzoOZZJ{WTAh^~V)QA4i7vzh4i1PeR{%DSQJ0HNaox?(beBy1uufv>!vi_^jWgPA0SjHurA* z?>bvXmX(fne&ZP#D(z>bCHxi+2=(OmU}0ALG9Ep}d$5q;*C using namespace Slic3r; SCENARIO("Reading 3mf file", "[3mf]") { GIVEN("umlauts in the path of the file") { - Slic3r::Model model; + Model model; WHEN("3mf model is read") { std::string path = std::string(TEST_DATA_DIR) + "/test_3mf/Geräte/Büchse.3mf"; DynamicPrintConfig config; - bool ret = Slic3r::load_3mf(path.c_str(), &config, &model, false); + bool ret = load_3mf(path.c_str(), &config, &model, false); THEN("load should succeed") { REQUIRE(ret); } } } } + +SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") { + GIVEN("world vertices coordinates before save") { + // load a model from stl file + Model src_model; + std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.stl"; + load_stl(src_file.c_str(), &src_model); + src_model.add_default_instances(); + + ModelObject* src_object = src_model.objects[0]; + + // apply generic transformation to the 1st volume + Geometry::Transformation src_volume_transform; + src_volume_transform.set_offset(Vec3d(10.0, 20.0, 0.0)); + src_volume_transform.set_rotation(Vec3d(Geometry::deg2rad(25.0), Geometry::deg2rad(35.0), Geometry::deg2rad(45.0))); + src_volume_transform.set_scaling_factor(Vec3d(1.1, 1.2, 1.3)); + src_volume_transform.set_mirror(Vec3d(-1.0, 1.0, -1.0)); + src_object->volumes[0]->set_transformation(src_volume_transform); + + // apply generic transformation to the 1st instance + Geometry::Transformation src_instance_transform; + src_instance_transform.set_offset(Vec3d(5.0, 10.0, 0.0)); + src_instance_transform.set_rotation(Vec3d(Geometry::deg2rad(12.0), Geometry::deg2rad(13.0), Geometry::deg2rad(14.0))); + src_instance_transform.set_scaling_factor(Vec3d(0.9, 0.8, 0.7)); + src_instance_transform.set_mirror(Vec3d(1.0, -1.0, -1.0)); + src_object->instances[0]->set_transformation(src_instance_transform); + + WHEN("model is saved+loaded to/from 3mf file") { + // save the model to 3mf file + std::string test_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.3mf"; + store_3mf(test_file.c_str(), &src_model, nullptr); + + // load back the model from the 3mf file + Model dst_model; + DynamicPrintConfig dst_config; + load_3mf(test_file.c_str(), &dst_config, &dst_model, false); + boost::filesystem::remove(test_file); + + // compare meshes + TriangleMesh src_mesh = src_model.mesh(); + src_mesh.repair(); + + TriangleMesh dst_mesh = dst_model.mesh(); + dst_mesh.repair(); + + bool res = src_mesh.its.vertices.size() == dst_mesh.its.vertices.size(); + if (res) + { + for (size_t i = 0; i < dst_mesh.its.vertices.size(); ++i) + { + res &= dst_mesh.its.vertices[i].isApprox(src_mesh.its.vertices[i]); + if (!res) + { + Vec3f diff = dst_mesh.its.vertices[i] - src_mesh.its.vertices[i]; + std::cout << i << ": diff " << to_string((Vec3d)diff.cast()) << "\n"; + } + } + } + THEN("world vertices coordinates after load match") { + REQUIRE(res); + } + } + } +}