diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 46873ff06c..6dc8478a5a 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2801,8 +2801,9 @@ void PrintObject::project_and_append_custom_facets( const Transform3f& tr1 = mv->get_matrix().cast(); const Transform3f& tr2 = this->trafo().cast(); const Transform3f tr = tr2 * tr1; - const float tr_det_sign = (tr.matrix().determinant() > 0. ? 1.f : -1.f); - + const float tr_det_sign = (tr.matrix().determinant() > 0. ? 1.f : -1.f); + const Vec2f center = unscaled(this->center_offset()); + ConstLayerPtrsAdaptor layers = this->layers(); // The projection will be at most a pentagon. Let's minimize heap // reallocations by saving in in the following struct. @@ -2810,10 +2811,17 @@ void PrintObject::project_and_append_custom_facets( // and they can be moved from to create an ExPolygon later. struct LightPolygon { LightPolygon() { pts.reserve(5); } + LightPolygon(const std::array& tri) { + pts.reserve(3); + pts.emplace_back(scaled(tri.front())); + pts.emplace_back(scaled(tri[1])); + pts.emplace_back(scaled(tri.back())); + } + Points pts; void add(const Vec2f& pt) { - pts.emplace_back(scale_(pt.x()), scale_(pt.y())); + pts.emplace_back(scaled(pt)); assert(pts.size() <= 5); } }; @@ -2831,7 +2839,7 @@ void PrintObject::project_and_append_custom_facets( // Iterate over all triangles. tbb::parallel_for( tbb::blocked_range(0, custom_facets.indices.size()), - [&](const tbb::blocked_range& range) { + [center, &custom_facets, &tr, tr_det_sign, seam, layers, &projections_of_triangles](const tbb::blocked_range& range) { for (size_t idx = range.begin(); idx < range.end(); ++ idx) { std::array facet; @@ -2857,30 +2865,43 @@ void PrintObject::project_and_append_custom_facets( }); std::array trianglef; - for (int i=0; i<3; ++i) { - trianglef[i] = Vec2f(facet[i].x(), facet[i].y()); - trianglef[i] -= Vec2f(unscale(this->center_offset().x()), - unscale(this->center_offset().y())); - } + for (int i=0; i<3; ++i) + trianglef[i] = to_2d(facet[i]) - center; // Find lowest slice not below the triangle. - auto it = std::lower_bound(layers().begin(), layers().end(), facet[0].z()+EPSILON, + auto it = std::lower_bound(layers.begin(), layers.end(), facet[0].z()+EPSILON, [](const Layer* l1, float z) { return l1->slice_z < z; }); // Count how many projections will be generated for this triangle // and allocate respective amount in projections_of_triangles. - projections_of_triangles[idx].first_layer_id = it-layers().begin(); - size_t last_layer_id = projections_of_triangles[idx].first_layer_id; + size_t first_layer_id = projections_of_triangles[idx].first_layer_id = it - layers.begin(); + size_t last_layer_id = first_layer_id; // The cast in the condition below is important. The comparison must // be an exact opposite of the one lower in the code where // the polygons are appended. And that one is on floats. - while (last_layer_id + 1 < layers().size() - && float(layers()[last_layer_id]->slice_z) <= facet[2].z()) + while (last_layer_id + 1 < layers.size() + && float(layers[last_layer_id]->slice_z) <= facet[2].z()) ++last_layer_id; - projections_of_triangles[idx].polygons.resize( - last_layer_id - projections_of_triangles[idx].first_layer_id + 1); + + if (first_layer_id == last_layer_id) { + // The triangle fits just a single slab, just project it. This also avoids division by zero for horizontal triangles. + float dz = facet[2].z() - facet[0].z(); + assert(dz >= 0); + // The face is nearly horizontal and it crosses the slicing plane at first_layer_id - 1. + // Rather add this face to both the planes. + bool add_below = dz < float(2. * EPSILON) && first_layer_id > 0 && layers[first_layer_id - 1]->slice_z > facet[0].z() - EPSILON; + projections_of_triangles[idx].polygons.reserve(add_below ? 2 : 1); + projections_of_triangles[idx].polygons.emplace_back(trianglef); + if (add_below) { + -- projections_of_triangles[idx].first_layer_id; + projections_of_triangles[idx].polygons.emplace_back(trianglef); + } + continue; + } + + projections_of_triangles[idx].polygons.resize(last_layer_id - first_layer_id + 1); // Calculate how to move points on triangle sides per unit z increment. Vec2f ta(trianglef[1] - trianglef[0]); @@ -2896,7 +2917,7 @@ void PrintObject::project_and_append_custom_facets( bool stop = false; // Project a sub-polygon on all slices intersecting the triangle. - while (it != layers().end()) { + while (it != layers.end()) { const float z = float((*it)->slice_z); // Projections of triangle sides intersections with slices. @@ -2914,7 +2935,7 @@ void PrintObject::project_and_append_custom_facets( } // This slice is above the triangle already. - if (z > facet[2].z() || it+1 == layers().end()) { + if (z > facet[2].z() || it+1 == layers.end()) { proj->add(trianglef[2]); stop = true; } @@ -2944,14 +2965,19 @@ void PrintObject::project_and_append_custom_facets( }); // end of parallel_for // Make sure that the output vector can be used. - expolys.resize(layers().size()); + expolys.resize(layers.size()); // Now append the collected polygons to respective layers. for (auto& trg : projections_of_triangles) { int layer_id = int(trg.first_layer_id); - for (const LightPolygon& poly : trg.polygons) { + for (LightPolygon &poly : trg.polygons) { if (layer_id >= int(expolys.size())) break; // part of triangle could be projected above top layer + assert(! poly.pts.empty()); + // The resulting triangles are fed to the Clipper library, which seem to handle flipped triangles well. +// if (cross2(Vec2d((poly.pts[1] - poly.pts[0]).cast()), Vec2d((poly.pts[2] - poly.pts[1]).cast())) < 0) +// std::swap(poly.pts.front(), poly.pts.back()); + expolys[layer_id].emplace_back(std::move(poly.pts)); ++layer_id; } diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index ee8c7f219e..e7685db1f3 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -1408,8 +1408,18 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ const ExPolygons &enforcer = enforcers[layer_id]; if (! enforcer.empty()) { // Enforce supports (as if with 90 degrees of slope) for the regions covered by the enforcer meshes. - Polygons new_contacts = diff(intersection(layerm_polygons, to_polygons(std::move(enforcer))), - offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS)); +#ifdef SLIC3R_DEBUG + ExPolygons enforcers_united = union_ex(to_polygons(enforcer), false); +#endif // SLIC3R_DEBUG + Polygons new_contacts = diff(intersection(layerm_polygons, to_polygons(std::move(enforcer))), + offset(lower_layer_polygons, 0.05f * fw, SUPPORT_SURFACES_OFFSET_PARAMETERS)); +#ifdef SLIC3R_DEBUG + SVG::export_expolygons(debug_out_path("support-top-contacts-enforcers-run%d-layer%d-z%f.svg", iRun, layer_id, layer.print_z), + { { { union_ex(layerm_polygons, false) }, { "layerm_polygons", "gray", 0.2f } }, + { { union_ex(lower_layer_polygons, false) }, { "lower_layer_polygons", "green", 0.5f } }, + { enforcers_united, { "enforcers", "blue", 0.5f } }, + { { union_ex(new_contacts, true) }, { "new_contacts", "red", "black", "", scaled(0.1f), 0.5f } } }); +#endif /* SLIC3R_DEBUG */ if (! new_contacts.empty()) { if (diff_polygons.empty()) diff_polygons = std::move(new_contacts);