diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 3d6b0c3563..ed05e60e2c 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -2501,19 +2501,21 @@ void PrintObject::remove_bridges_from_contacts( if (surface.surface_type == stBottomBridge && surface.bridge_angle != -1) { auto bbox = get_extents(surface.expolygon); auto bbox_size = bbox.size(); - if (bbox_size[0] < max_bridge_length || bbox_size[1] < max_bridge_length) + if (bbox_size[0] < max_bridge_length && bbox_size[1] < max_bridge_length) polygons_append(bridges, surface.expolygon); else { if (break_bridge) { Polygons holes; - int x0 = bbox.min.x(); - int x1 = bbox.max.x(); - int y0 = bbox.min.y(); - int y1 = bbox.max.y(); + coord_t x0 = bbox.min.x(); + coord_t x1 = bbox.max.x(); + coord_t y0 = bbox.min.y(); + coord_t y1 = bbox.max.y(); const int grid_lw = int(w/2); // grid line width -#if 1 - if (fabs(surface.bridge_angle-0) fabs(bridge_direction(1))) + { // cut bridge along x-axis if bridge direction is aligned to x-axis more than to y-axis + // Note: surface.bridge_angle may be pi, so we can't compare it to 0 & pi/2. int step = bbox_size(0) / ceil(bbox_size(0) / max_bridge_length); for (int x = x0 + step; x < x1; x += step) { Polygon poly; @@ -2528,17 +2530,6 @@ void PrintObject::remove_bridges_from_contacts( holes.emplace_back(poly); } } -#else - int stepx = bbox_size(0) / ceil(bbox_size(0) / max_bridge_length); - int stepy = bbox_size(1) / ceil(bbox_size(1) / max_bridge_length); - for (int x = x0 + stepx; x < x1; x += stepx) - for (int y = y0 + stepy; y < y1; y += stepy) { - Polygon poly; - poly.points = {Point(x-grid_lw, y - grid_lw), Point(x+grid_lw, y - grid_lw), Point(x+grid_lw, y + grid_lw), Point(x-grid_lw, y + grid_lw)}; - holes.emplace_back(poly); - } - -#endif auto expoly = diff_ex(surface.expolygon, holes); polygons_append(bridges, expoly); } diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index 3c037ee8eb..261637959d 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -31,9 +31,9 @@ #endif // SUPPORT_USE_AGG_RASTERIZER // #define SLIC3R_DEBUG - +// #define SUPPORT_TREE_DEBUG_TO_SVG // Make assert active if SLIC3R_DEBUG -#ifdef SLIC3R_DEBUG +#if defined(SLIC3R_DEBUG) || defined(SUPPORT_TREE_DEBUG_TO_SVG) #define DEBUG #define _DEBUG #undef NDEBUG @@ -996,16 +996,18 @@ public: if (!support_polygons_simplified.empty()) bbox.merge(get_extents(support_polygons_simplified)); SVG svg(debug_out_path("extract_support_from_grid_trimmed-%s-%d-%d-%lf.svg", step_name, iRun, layer_id, print_z).c_str(), bbox); - svg.draw(union_ex(support_polygons_simplified), "gray", 0.25f); - svg.draw(islands, "red", 0.5f); - svg.draw(union_ex(out), "green", 0.5f); - svg.draw(union_ex(*m_support_polygons), "blue", 0.5f); - svg.draw_outline(islands, "red", "red", scale_(0.05)); - svg.draw_outline(union_ex(out), "green", "green", scale_(0.05)); - svg.draw_outline(union_ex(*m_support_polygons), "blue", "blue", scale_(0.05)); - for (const Point &pt : samples) - svg.draw(pt, "black", coord_t(scale_(0.15))); - svg.Close(); + if (svg.is_opened()) { + svg.draw(union_ex(support_polygons_simplified), "gray", 0.25f); + svg.draw(islands, "red", 0.5f); + svg.draw(union_ex(out), "green", 0.5f); + svg.draw(union_ex(*m_support_polygons), "blue", 0.5f); + svg.draw_outline(islands, "red", "red", scale_(0.05)); + svg.draw_outline(union_ex(out), "green", "green", scale_(0.05)); + svg.draw_outline(union_ex(*m_support_polygons), "blue", "blue", scale_(0.05)); + for (const Point& pt : samples) + svg.draw(pt, "black", coord_t(scale_(0.15))); + svg.Close(); + } #endif /* SLIC3R_DEBUG */ if (m_support_angle != 0.) @@ -1638,7 +1640,7 @@ static inline ExPolygons detect_overhangs( // 1. nothing below // Check whether this is a sharp tail region. // Should use lower_layer_expolys without any offset. Otherwise, it may missing sharp tails near the main body. - if (g_config_support_sharp_tails && overlaps(offset_ex(expoly, 0.5 * fw), lower_layer_expolys)) { + if (g_config_support_sharp_tails && !overlaps(offset_ex(expoly, 0.5 * fw), lower_layer_expolys)) { is_sharp_tail = expoly.area() < area_thresh_well_supported && !offset_ex(expoly,-0.1*fw).empty(); } @@ -2107,6 +2109,9 @@ struct OverhangCluster { int min_layer = 1e7; int max_layer = 0; coordf_t offset_scaled = 0; + bool is_cantilever = false; + bool is_sharp_tail = false; + bool is_small_overhang = false; OverhangCluster(ExPolygon* overhang, int layer_nr, coordf_t offset_scaled) { this->offset_scaled = offset_scaled; @@ -2240,12 +2245,6 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ // 2) lower layer has no sharp tails if (!lower_layer || layer->sharp_tails.empty() == false || lower_layer->sharp_tails.empty() == true) continue; - ExPolygons lower_polys; - for (const ExPolygon& expoly : lower_layer->lslices) { - if (!offset_ex(expoly, -extrusion_width_scaled / 2).empty()) { - lower_polys.emplace_back(expoly); - } - } // BBS detect sharp tail const ExPolygons& lower_layer_sharptails = lower_layer->sharp_tails; @@ -2335,57 +2334,70 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_ } for (OverhangCluster& cluster : clusters) { - // 1. check overhang span size is smaller than 3mm - //auto bbox_size = get_extents(cluster.merged_overhangs_dilated).size(); - //const double dimension_limit = scale_(3.0) + 2 * fw_scaled; - //if (bbox_size.x() > dimension_limit || bbox_size.y() > dimension_limit) - // continue; - - double area = 0.f; - // 2. check overhang cluster size is smaller than 3.0 * fw_scaled - auto erode1 = offset(cluster.merged_overhangs_dilated, -2.5 * fw_scaled); - for (Polygon& poly : erode1) - area += poly.area() * (poly.is_counter_clockwise() ? 1.0 : -1.0); - if (std::abs(area) > SQ(scale_(0.1))) - continue; // 3. check whether the small overhang is sharp tail - bool is_sharp_tail = false; + cluster.is_sharp_tail = false; for (size_t layer_id = cluster.min_layer; layer_id <= cluster.max_layer; layer_id++) { const Layer* layer = object.get_layer(layer_id); if (overlaps(layer->sharp_tails, cluster.merged_overhangs_dilated)) { - is_sharp_tail = true; + cluster.is_sharp_tail = true; break; } } - if (is_sharp_tail) + if (cluster.is_sharp_tail) continue; - // 4. check whether the overhang cluster is cantilever (far awary from main body) - const Layer* layer = object.get_layer(cluster.min_layer); - if (layer->lower_layer == NULL) continue; - Layer* lower_layer = layer->lower_layer; - auto cluster_boundary = intersection(cluster.merged_overhangs_dilated, offset(lower_layer->lslices, scale_(0.5))); - if (cluster_boundary.empty()) continue; - double dist_max = 0; - Points cluster_pts; - for (auto& poly : cluster.merged_overhangs_dilated) - append(cluster_pts, poly.contour.points); - for (auto& pt : cluster_pts) { - double dist_pt = std::numeric_limits::max(); - for (auto& poly : cluster_boundary) { - double d = poly.distance_to(pt); - dist_pt = std::min(dist_pt, d); + if (!cluster.is_sharp_tail) { + // 4. check whether the overhang cluster is cantilever (far awary from main body) + const Layer* layer = object.get_layer(cluster.min_layer); + if (layer->lower_layer == NULL) continue; + Layer* lower_layer = layer->lower_layer; + auto cluster_boundary = intersection(cluster.merged_overhangs_dilated, offset(lower_layer->lslices, scale_(0.5))); + if (cluster_boundary.empty()) continue; + double dist_max = 0; + Points cluster_pts; + for (auto& poly : cluster.merged_overhangs_dilated) + append(cluster_pts, poly.contour.points); + for (auto& pt : cluster_pts) { + double dist_pt = std::numeric_limits::max(); + for (auto& poly : cluster_boundary) { + double d = poly.distance_to(pt); + dist_pt = std::min(dist_pt, d); + } + dist_max = std::max(dist_max, dist_pt); + } + if (dist_max > scale_(3)) { + cluster.is_cantilever = true; + continue; } - dist_max = std::max(dist_max, dist_pt); } - if (dist_max > 5.0 * fw_scaled) - continue; + + if (!cluster.is_sharp_tail && !cluster.is_cantilever) { + // 2. check overhang cluster size is small + cluster.is_small_overhang = false; + auto erode1 = offset_ex(cluster.merged_overhangs_dilated, -2.5 * fw_scaled); + if (area(erode1) < SQ(scale_(0.1))) { + cluster.is_small_overhang = true; + } + } + +#ifdef SUPPORT_TREE_DEBUG_TO_SVG + const Layer* layer1 = object.get_layer(cluster.min_layer); + BoundingBox bbox = get_extents(cluster.merged_overhangs_dilated); + bbox.merge(get_extents(layer1->lslices)); + SVG svg(format("SVG/overhangCluster_%s_%s_tail=%s_cantilever=%s_small=%s.svg", cluster.min_layer, layer1->print_z, cluster.is_sharp_tail, cluster.is_cantilever, cluster.is_small_overhang), bbox); + if (svg.is_opened()) { + svg.draw(layer1->lslices, "red"); + svg.draw(cluster.merged_overhangs_dilated, "blue"); + } +#endif // 5. remove small overhangs - for (auto overhangs : cluster.layer_overhangs) { - for (auto* poly : overhangs.second) - removed_overhang.insert(poly); + if (cluster.is_small_overhang) { + for (auto overhangs : cluster.layer_overhangs) { + for (auto* poly : overhangs.second) + removed_overhang.insert(poly); + } } } diff --git a/src/libslic3r/TreeSupport.cpp b/src/libslic3r/TreeSupport.cpp index 4c37b2c3cd..f6d9d6b563 100644 --- a/src/libslic3r/TreeSupport.cpp +++ b/src/libslic3r/TreeSupport.cpp @@ -763,6 +763,8 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) int max_layer = 0; coordf_t offset = 0; bool is_cantilever = false; + bool is_sharp_tail = false; + bool is_small_overhang = false; OverhangCluster(const ExPolygon* expoly, int layer_nr) { push_back(expoly, layer_nr); } @@ -951,12 +953,6 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) // 2) lower layer has no sharp tails if (!lower_layer || layer->sharp_tails.empty() == false || lower_layer->sharp_tails.empty() == true) continue; - ExPolygons lower_polys; - for (const ExPolygon& expoly : lower_layer->lslices) { - if (!offset_ex(expoly, -extrusion_width_scaled / 2).empty()) { - lower_polys.emplace_back(expoly); - } - } // BBS detect sharp tail const ExPolygons& lower_layer_sharptails = lower_layer->sharp_tails; @@ -1047,9 +1043,21 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers); m_object->project_and_append_custom_facets(false, EnforcerBlockerType::BLOCKER, blockers); - // check whether the overhang cluster is cantilever (far awary from main body) + // check whether the overhang cluster is sharp tail or cantilever max_cantilevel_dist = 0; for (auto& cluster : overhangClusters) { + // 3. check whether the small overhang is sharp tail + cluster.is_sharp_tail = false; + for (size_t layer_id = cluster.min_layer; layer_id <= cluster.max_layer; layer_id++) { + Layer* layer = m_object->get_layer(layer_id); + if (overlaps(layer->sharp_tails, cluster.merged_poly)) { + cluster.is_sharp_tail = true; + break; + } + } + if (cluster.is_sharp_tail) continue; + + // check whether the overhang cluster is cantilever (far awary from main body) Layer* layer = m_object->get_layer(cluster.min_layer); if (layer->lower_layer == NULL) continue; Layer* lower_layer = layer->lower_layer; @@ -1083,46 +1091,29 @@ void TreeSupport::detect_overhangs(bool detect_first_sharp_tail_only) if (blockers.size() < m_object->layer_count()) blockers.resize(m_object->layer_count()); for (auto& cluster : overhangClusters) { - auto erode1 = offset_ex(cluster.merged_poly, -1.5*extrusion_width_scaled); - //DEBUG - bool save_poly = false; - if (save_poly) { - erode1 = offset_ex(cluster.merged_poly, -1*extrusion_width_scaled); - double a = area(erode1); - erode1[0].contour.remove_duplicate_points(); - a = area(erode1); - auto tmp = offset_ex(erode1, extrusion_width_scaled); - SVG svg("SVG/merged_poly_"+std::to_string(cluster.min_layer)+".svg", m_object->bounding_box()); - if (svg.is_opened()) { - svg.draw_outline(cluster.merged_poly, "yellow"); - svg.draw_outline(erode1, "yellow"); - } + // 4. check whether the overhang cluster is cantilever or sharp tail + if (cluster.is_cantilever || cluster.is_sharp_tail) continue; + + if (!cluster.is_sharp_tail && !cluster.is_cantilever) { + // 2. check overhang cluster size is smaller than 3.0 * fw_scaled + auto erode1 = offset_ex(cluster.merged_poly, -1.5 * extrusion_width_scaled); + cluster.is_small_overhang = area(erode1) < SQ(scale_(0.1)); } - // 1. check overhang span size is smaller than 3mm - //auto bbox_size = get_extents(cluster.merged_poly).size(); - //const double dimension_limit = scale_(3.0) + 2 * extrusion_width_scaled; - //if (bbox_size.x() > dimension_limit || bbox_size.y() > dimension_limit) - // continue; +#ifdef SUPPORT_TREE_DEBUG_TO_SVG + const Layer* layer1 = m_object->get_layer(cluster.min_layer); + BoundingBox bbox = cluster.merged_bbox; + bbox.merge(get_extents(layer1->lslices)); + SVG svg(format("SVG/overhangCluster_%s_%s_tail=%s_cantilever=%s_small=%s.svg", cluster.min_layer, layer1->print_z, cluster.is_sharp_tail, cluster.is_cantilever, cluster.is_small_overhang), bbox); + if (svg.is_opened()) { + svg.draw(layer1->lslices, "red"); + svg.draw(cluster.merged_poly, "blue"); + } +#endif - // 2. check overhang cluster size is smaller than 3.0 * fw_scaled - if (area(erode1) > SQ(scale_(0.1))) + if (!cluster.is_small_overhang) continue; - // 3. check whether the small overhang is sharp tail - bool is_sharp_tail = false; - for (size_t layer_id = cluster.min_layer; layer_id <= cluster.max_layer; layer_id++) { - Layer* layer = m_object->get_layer(layer_id); - if(overlaps(layer->sharp_tails, cluster.merged_poly)) { - is_sharp_tail = true; - break; - } - } - if (is_sharp_tail) continue; - - // 4. check whether the overhang cluster is cantilever - if (cluster.is_cantilever) continue; - for (auto it = cluster.layer_overhangs.begin(); it != cluster.layer_overhangs.end(); it++) { int layer_nr = it->first; auto p_overhang = it->second;