diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index b83e0dae64..0941c11ef1 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -15,16 +15,20 @@ #include +// for SLIC3R_DEBUG_SLICE_PROCESSING +#include "libslic3r.h" + #if 0 #define DEBUG #define _DEBUG #undef NDEBUG + #define SLIC3R_DEBUG +// #define SLIC3R_TRIANGLEMESH_DEBUG #endif #include -#ifdef SLIC3R_DEBUG -// #define SLIC3R_TRIANGLEMESH_DEBUG +#if defined(SLIC3R_DEBUG) || defined(SLIC3R_DEBUG_SLICE_PROCESSING) #include "SVG.hpp" #endif @@ -758,8 +762,22 @@ void TriangleMeshSlicer::slice(const std::vector &z, std::vectory; il.a_id = a_id; il.b_id = b_id; + assert(il.a != il.b); (*lines)[layer_idx].emplace_back(il); } } else @@ -849,16 +868,6 @@ void TriangleMeshSlicer::slice(const std::vector &z, std::vectorx - a->x; - float v1_y = b->y - a->y; - float v2_x = c->x - a->x; - float v2_y = c->y - a->y; - float dir = (b->x - a->x) * (c->y - a->y) - (b->y - a->y) * (c->x - a->x); - return dir; -} - // Return true, if the facet has been sliced and line_out has been filled. TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( float slice_z, const stl_facet &facet, const int facet_idx, @@ -873,10 +882,10 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( // Reorder vertices so that the first one is the one with lowest Z. // This is needed to get all intersection lines in a consistent order // (external on the right of the line) - int i = (facet.vertex[1].z == min_z) ? 1 : ((facet.vertex[2].z == min_z) ? 2 : 0); - for (int j = i; j - i < 3; ++ j) { // loop through facet edges + const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex; + int i = (facet.vertex[1].z == min_z) ? 1 : ((facet.vertex[2].z == min_z) ? 2 : 0); + for (int j = i; j - i < 3; ++j) { // loop through facet edges int edge_id = this->facets_edges[facet_idx * 3 + (j % 3)]; - const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex; int a_id = vertices[j % 3]; int b_id = vertices[(j+1) % 3]; const stl_vertex *a = &this->v_scaled_shared[a_id]; @@ -888,6 +897,7 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( const stl_vertex &v0 = this->v_scaled_shared[vertices[0]]; const stl_vertex &v1 = this->v_scaled_shared[vertices[1]]; const stl_vertex &v2 = this->v_scaled_shared[vertices[2]]; + const stl_normal &normal = this->mesh->stl.facet_start[facet_idx].normal; // We may ignore this edge for slicing purposes, but we may still use it for object cutting. FacetSliceType result = Slicing; const stl_neighbors &nbr = this->mesh->stl.neighbors_start[facet_idx]; @@ -897,23 +907,23 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( // Mark neighbor edges, which do not have a neighbor. uint32_t edges = 0; uint32_t mask = IntersectionLine::EDGE0; - for (int nbr_idx = 2; nbr_idx != 5; ++ nbr_idx, mask <<= 1) + for (int nbr_idx = 0; nbr_idx != 3; ++ nbr_idx, mask <<= 1) // If the neighbor with an edge starting with a vertex idx (nbr_idx - 2) shares no // opposite face, add it to the edges to process when slicing. - if (nbr.neighbor[nbr_idx % 3] == -1) + if (nbr.neighbor[nbr_idx] == -1) // Mark this edge. edges |= mask; // Use some edges of this triangle for slicing only if at least one of its edge does not have an opposite face. result = (edges == 0) ? Cutting : Slicing; line_out->flags |= edges; - if (this->mesh->stl.facet_start[facet_idx].normal.z < 0) { + if (normal.z < 0) { // If normal points downwards this is a bottom horizontal facet so we reverse its point order. std::swap(a, b); std::swap(a_id, b_id); } } else { // Two vertices are aligned with the cutting plane, the third vertex is below or above the cutting plane. - int nbr_idx = (j + 2) % 3; + int nbr_idx = j % 3; int nbr_face = nbr.neighbor[nbr_idx]; // Is the third vertex below the cutting plane? bool third_below = v0.z < slice_z || v1.z < slice_z || v2.z < slice_z; @@ -923,19 +933,25 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( printf("Face has no neighbor!\n"); #endif } else { + assert(this->mesh->stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 1) % 3] == b_id); + assert(this->mesh->stl.v_indices[nbr_face].vertex[(nbr.which_vertex_not[nbr_idx] + 2) % 3] == a_id); int idx_vertex_opposite = this->mesh->stl.v_indices[nbr_face].vertex[nbr.which_vertex_not[nbr_idx]]; const stl_vertex *c = &this->v_scaled_shared[idx_vertex_opposite]; - if (c->z > slice_z) { - // If an edge resides on a cutting plane, and none of the two triangles are coplanar with the cutting plane, - // igore the lower triangle. - if (third_below) - result = Cutting; - } else if (c->z == slice_z) { - // A vertical face shares edge with a horizontal face. Verify, whether the shared corner is convex or concave. - float dir = cross_product(a, b, c); - if (third_below ? (dir < 0.) : (dir > 0.)) - result = Cutting; - } +// double side = double(normal.x) * (double(c->x) - double(a->x)) + double(normal.y) * (double(c->y) - double(a->y)); +// assert(c->z != slice_z || side != 0.); +// double normal_nbr = (double(c->x) - double(a->x)) * (double(b->y) - double(a->y)) - (double(c->y) - double(a->y)) * (double(b->x) - double(a->x)); + result = + (c->z == slice_z) ? + // A vertical face shares edge with a horizontal face. Verify, whether the shared edge makes a convex or concave corner. + // Unfortunately too often there are flipped normals, which brake our assumption. Let's rather return every edge, + // and leth the code downstream hopefully handle it. + Slicing : + // Failing tests: Ignore concave corners for slicing. + // (((normal_nbr < 0) == third_below) ? Cutting : Slicing) : + // or + // (((this->mesh->stl.facet_start[nbr_face].normal.z < 0) == third_below) ? Cutting : Slicing) : + // For a pair of faces touching exactly at the cutting plane, ignore the face with a higher index. + (facet_idx < nbr_face) ? Slicing : Cutting; } if (third_below) { line_out->edge_type = feTop; @@ -950,6 +966,7 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( line_out->b.y = b->y; line_out->a_id = a_id; line_out->b_id = b_id; + assert(line_out->a != line_out->b); return result; } @@ -970,8 +987,9 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( } else if ((a->z < slice_z && b->z > slice_z) || (b->z < slice_z && a->z > slice_z)) { // A general case. The face edge intersects the cutting plane. Calculate the intersection point. IntersectionPoint &point = points[num_points ++]; - point.x = b->x + (a->x - b->x) * (slice_z - b->z) / (a->z - b->z); - point.y = b->y + (a->y - b->y) * (slice_z - b->z) / (a->z - b->z); + double t = (double(slice_z) - double(b->z)) / (double(a->z) - double(b->z)); + point.x = float(double(b->x) + (double(a->x) - double(b->x)) * t); + point.y = float(double(b->y) + (double(a->y) - double(b->y)) * t); point.edge_id = edge_id; } } @@ -1003,7 +1021,11 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( line_out->edge_a_id = points[1].edge_id; line_out->edge_b_id = points[0].edge_id; // General slicing position, use the segment for both slicing and object cutting. - return Slicing; + // In a degenerate case where a plane cuts the triangle very close to its vertex, it is possible, that + // a zero length edge is created. In that case the zero length edge could be safely ignored + // as the polyline will still be connected, because both the sliced edges of the triangle will be + // sliced the same way at the neighbor triangles. + return (line_out->a == line_out->b) ? NoSlice : Slicing; } return NoSlice; } @@ -1074,6 +1096,11 @@ static inline void remove_tangent_edges(std::vector &lines) void TriangleMeshSlicer::make_loops(std::vector &lines, Polygons* loops) const { +#ifdef _DEBUG + for (const Line &l : lines_src) + assert(l.a != l.b); +#endif /* _DEBUG */ + remove_tangent_edges(lines); struct OpenPolyline { diff --git a/xs/src/libslic3r/Utils.hpp b/xs/src/libslic3r/Utils.hpp index 3492228543..fd63d412a6 100644 --- a/xs/src/libslic3r/Utils.hpp +++ b/xs/src/libslic3r/Utils.hpp @@ -9,6 +9,7 @@ namespace Slic3r { extern void set_logging_level(unsigned int level); extern void trace(unsigned int level, const char *message); +extern void disable_multi_threading(); // Set a path with GUI resource files. void set_var_dir(const std::string &path); diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp index 55164bbdd6..4ca4f69fd8 100644 --- a/xs/src/libslic3r/utils.cpp +++ b/xs/src/libslic3r/utils.cpp @@ -24,6 +24,8 @@ #include #include +#include + namespace Slic3r { static boost::log::trivial::severity_level logSeverity = boost::log::trivial::error; @@ -82,6 +84,14 @@ void trace(unsigned int level, const char *message) (::boost::log::keywords::severity = severity)) << message; } +void disable_multi_threading() +{ + // Disable parallelization so the Shiny profiler works + static tbb::task_scheduler_init *tbb_init = nullptr; + if (tbb_init == nullptr) + tbb_init = new tbb::task_scheduler_init(1); +} + static std::string g_var_dir; void set_var_dir(const std::string &dir) diff --git a/xs/xsp/XS.xsp b/xs/xsp/XS.xsp index e900532aaf..04969a7f92 100644 --- a/xs/xsp/XS.xsp +++ b/xs/xsp/XS.xsp @@ -48,6 +48,11 @@ trace(level, message) CODE: Slic3r::trace(level, message); +void +disable_multi_threading() + CODE: + Slic3r::disable_multi_threading(); + void set_var_dir(dir) char *dir;