diff --git a/src/test/libslic3r/test_trianglemesh.cpp b/src/test/libslic3r/test_trianglemesh.cpp index 52d19cc83..72d0d0b55 100644 --- a/src/test/libslic3r/test_trianglemesh.cpp +++ b/src/test/libslic3r/test_trianglemesh.cpp @@ -10,43 +10,41 @@ SCENARIO( "TriangleMesh: Basic mesh statistics") { const Pointf3s vertices { Pointf3(20,20,0), Pointf3(20,0,0), Pointf3(0,0,0), Pointf3(0,20,0), Pointf3(20,20,20), Pointf3(0,20,20), Pointf3(0,0,20), Pointf3(20,0,20) }; const Point3s facets { Point3(0,1,2), Point3(0,2,3), Point3(4,5,6), Point3(4,6,7), Point3(0,4,7), Point3(0,7,1), Point3(1,7,6), Point3(1,6,2), Point3(2,6,5), Point3(2,5,3), Point3(4,0,3), Point3(4,3,5) }; - auto* cube {new TriangleMesh(vertices, facets)}; - cube->repair(); + auto cube {TriangleMesh(vertices, facets)}; + cube.repair(); THEN( "Volume is appropriate for 20mm square cube.") { - REQUIRE(abs(cube->volume() - 20.0*20.0*20.0) < 1e-2); + REQUIRE(abs(cube.volume() - 20.0*20.0*20.0) < 1e-2); } THEN( "Vertices array matches input.") { - for (auto i = 0U; i < cube->vertices().size(); i++) { - REQUIRE(cube->vertices().at(i) == vertices.at(i)); + for (auto i = 0U; i < cube.vertices().size(); i++) { + REQUIRE(cube.vertices().at(i) == vertices.at(i)); } for (auto i = 0U; i < vertices.size(); i++) { - REQUIRE(vertices.at(i) == cube->vertices().at(i)); + REQUIRE(vertices.at(i) == cube.vertices().at(i)); } } THEN( "Vertex count matches vertex array size.") { - REQUIRE(cube->facets_count() == facets.size()); + REQUIRE(cube.facets_count() == facets.size()); } THEN( "Facet array matches input.") { - for (auto i = 0U; i < cube->facets().size(); i++) { - REQUIRE(cube->facets().at(i) == facets.at(i)); + for (auto i = 0U; i < cube.facets().size(); i++) { + REQUIRE(cube.facets().at(i) == facets.at(i)); } for (auto i = 0U; i < facets.size(); i++) { - REQUIRE(facets.at(i) == cube->facets().at(i)); + REQUIRE(facets.at(i) == cube.facets().at(i)); } } THEN( "Facet count matches facet array size.") { - REQUIRE(cube->facets_count() == facets.size()); + REQUIRE(cube.facets_count() == facets.size()); } THEN( "Number of normals is equal to the number of facets.") { - REQUIRE(cube->normals().size() == facets.size()); + REQUIRE(cube.normals().size() == facets.size()); } - - delete cube; } } @@ -54,43 +52,48 @@ SCENARIO( "TriangleMesh: Transformation functions affect mesh as expected.") { GIVEN( "A 20mm cube with one corner on the origin") { const Pointf3s vertices { Pointf3(20,20,0), Pointf3(20,0,0), Pointf3(0,0,0), Pointf3(0,20,0), Pointf3(20,20,20), Pointf3(0,20,20), Pointf3(0,0,20), Pointf3(20,0,20) }; const std::vector facets { Point3(0,1,2), Point3(0,2,3), Point3(4,5,6), Point3(4,6,7), Point3(0,4,7), Point3(0,7,1), Point3(1,7,6), Point3(1,6,2), Point3(2,6,5), Point3(2,5,3), Point3(4,0,3), Point3(4,3,5) }; - auto* cube {new TriangleMesh(vertices, facets)}; - cube->repair(); - WHEN( "The cube is scaled 200\%") { + auto cube {TriangleMesh(vertices, facets)}; + cube.repair(); + + WHEN( "The cube is scaled 200\% uniformly") { + cube.scale(2.0); THEN( "The volume is equivalent to 40x40x40 (all dimensions increased by 200\%") { - REQUIRE(false); // TODO + REQUIRE(abs(cube.volume() - 40.0*40.0*40.0) < 1e-2); } } - WHEN( "The cube is scaled 200\% in the X direction") { + WHEN( "The resulting cube is scaled 200\% in the X direction") { + cube.scale(Vectorf3(2.0, 1, 1)); THEN( "The volume is doubled.") { - REQUIRE(false); // TODO + REQUIRE(abs(cube.volume() - 2*20.0*20.0*20.0) < 1e-2); } THEN( "The X coordinate size is 200\%.") { - REQUIRE(false); // TODO + REQUIRE(cube.vertices().at(0).x == 40.0); } } - WHEN( "The cube is scaled 50\% in the X direction") { - THEN( "The volume is doubled.") { - REQUIRE(false); // TODO + + WHEN( "The cube is scaled 25\% in the X direction") { + cube.scale(Vectorf3(0.25, 1, 1)); + THEN( "The volume is 25\% of the previous volume.") { + REQUIRE(abs(cube.volume() - 0.25*20.0*20.0*20.0) < 1e-2); } - THEN( "The X coordinate size is 50\%.") { - REQUIRE(false); // TODO + THEN( "The X coordinate size is 25\% from previous.") { + REQUIRE(cube.vertices().at(0).x == 5.0); } } WHEN( "The scaled cube is rotated 45 degrees.") { - THEN( "The X component of the size is sqrt(2)*40") { - REQUIRE(false); // TODO + cube.rotate(45.0, Slic3r::Point(20,20)); + THEN( "The X component of the size is sqrt(2)*20") { + REQUIRE(abs(cube.size().x - sqrt(2.0)*20) < 1e-2); } } } - } -SCENARIO( "TriangleMesh: split function functionality.") { +SCENARIO( "TriangleMesh: split functionality.", "[!mayfail]") { REQUIRE(false); // TODO } -SCENARIO( "make_xxx functions produce meshes.") { +SCENARIO( "make_xxx functions produce meshes.", "[!mayfail]") { REQUIRE(false); // TODO } diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index e4be594a0..cae3e40c1 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -1,5 +1,6 @@ #include "TriangleMesh.hpp" #include "ClipperUtils.hpp" +#include "Log.hpp" #include "Geometry.hpp" #include #include @@ -93,6 +94,59 @@ TriangleMesh::TriangleMesh(const TriangleMesh &other) } } +Pointf3s TriangleMesh::vertices() +{ + Pointf3s tmp {}; + if (this->repaired) { + if (this->stl.v_shared == nullptr) + stl_generate_shared_vertices(&stl); // build the list of vertices + for (auto i = 0; i < this->stl.stats.shared_vertices; i++) { + const auto& v {this->stl.v_shared[i]}; + tmp.emplace_back(Pointf3(v.x, v.y, v.z)); + } + } else { + Slic3r::Log::warn("TriangleMesh", "vertices() requires repair()"); + } + return std::move(tmp); +} + +Point3s TriangleMesh::facets() +{ + Point3s tmp {}; + if (this->repaired) { + if (this->stl.v_shared == nullptr) + stl_generate_shared_vertices(&stl); // build the list of vertices + for (auto i = 0; i < stl.stats.number_of_facets; i++) { + const auto& v {stl.v_indices[i]}; + tmp.emplace_back(Point3(v.vertex[0], v.vertex[1], v.vertex[2])); + } + } else { + Slic3r::Log::warn("TriangleMesh", "facets() requires repair()"); + } + return std::move(tmp); +} + +Pointf3s TriangleMesh::normals() const +{ + Pointf3s tmp {}; + if (this->repaired) { + for (auto i = 0; i < stl.stats.number_of_facets; i++) { + const auto& n {stl.facet_start[i].normal}; + tmp.emplace_back(Pointf3(n.x, n.y, n.z)); + } + } else { + Slic3r::Log::warn("TriangleMesh", "normals() requires repair()"); + } + return std::move(tmp); +} + +Pointf3 TriangleMesh::size() const +{ + const auto& sz {stl.stats.size}; + return std::move(Pointf3(sz.x, sz.y, sz.z)); +} + + TriangleMesh& TriangleMesh::operator= (TriangleMesh other) { this->swap(other); @@ -356,9 +410,13 @@ void TriangleMesh::center_around_origin() void TriangleMesh::rotate(double angle, Point* center) { - this->translate(-center->x, -center->y, 0); + this->rotate(angle, *center); +} +void TriangleMesh::rotate(double angle, const Point& center) +{ + this->translate(-center.x, -center.y, 0); stl_rotate_z(&(this->stl), (float)angle); - this->translate(+center->x, +center->y, 0); + this->translate(+center.x, +center.y, 0); } TriangleMeshPtrs @@ -1393,6 +1451,7 @@ TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower) co stl_get_size(&(lower->stl)); } + template TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) : mesh(_mesh), v_scaled_shared(NULL) { diff --git a/xs/src/libslic3r/TriangleMesh.hpp b/xs/src/libslic3r/TriangleMesh.hpp index 5b2431599..b930888e0 100644 --- a/xs/src/libslic3r/TriangleMesh.hpp +++ b/xs/src/libslic3r/TriangleMesh.hpp @@ -47,7 +47,11 @@ class TriangleMesh void mirror_z(); void align_to_origin(); void center_around_origin(); + + /// Rotate angle around a specified point. + void rotate(double angle, const Point& center); void rotate(double angle, Point* center); + TriangleMeshPtrs split() const; TriangleMeshPtrs cut_by_grid(const Pointf &grid) const; void merge(const TriangleMesh &mesh); @@ -60,6 +64,18 @@ class TriangleMesh void extrude_tin(float offset); void require_shared_vertices(); void reverse_normals(); + + /// Return a copy of the vertex array defining this mesh. + Pointf3s vertices(); + + /// Return a copy of the facet array defining this mesh. + Point3s facets(); + + /// Return a copy of the normals array defining this mesh. + Pointf3s normals() const; + + /// Return the size of the mesh in coordinates. + Pointf3 size() const; /// Generate a mesh representing a cube with dimensions (x, y, z), with one corner at (0,0,0). static TriangleMesh make_cube(double x, double y, double z);