diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 1f3066147..bdc51dea6 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -676,25 +676,61 @@ bool paths_touch(const ExtrusionPath &path_one, const ExtrusionPath &path_two, d ExtrusionPaths reconnect_extrusion_paths(const ExtrusionPaths& paths, double limit_distance) { if (paths.empty()) return paths; - ExtrusionPaths result; - result.push_back(paths.front()); - for (size_t pidx = 1; pidx < paths.size(); pidx++) { - if ((result.back().last_point() - paths[pidx].first_point()).cast().squaredNorm() < limit_distance * limit_distance) { - result.back().polyline.points.insert(result.back().polyline.points.end(), paths[pidx].polyline.points.begin(), - paths[pidx].polyline.points.end()); - } else { - result.push_back(paths[pidx]); + + std::unordered_map connected; + connected.reserve(paths.size()); + for (size_t i = 0; i < paths.size(); i++) { + if (!paths[i].empty()) { + connected.emplace(i, paths[i]); } } + + for (size_t a = 0; a < paths.size(); a++) { + if (connected.find(a) == connected.end()) { + continue; + } + ExtrusionPath &base = connected.at(a); + for (size_t b = a + 1; b < paths.size(); b++) { + if (connected.find(b) == connected.end()) { + continue; + } + ExtrusionPath &next = connected.at(b); + if ((base.last_point() - next.first_point()).cast().squaredNorm() < limit_distance * limit_distance) { + base.polyline.append(std::move(next.polyline)); + connected.erase(b); + } else if ((base.last_point() - next.last_point()).cast().squaredNorm() < limit_distance * limit_distance) { + base.polyline.points.insert(base.polyline.points.end(), next.polyline.points.rbegin(), next.polyline.points.rend()); + connected.erase(b); + } else if ((base.first_point() - next.last_point()).cast().squaredNorm() < limit_distance * limit_distance) { + next.polyline.append(std::move(base.polyline)); + base = std::move(next); + base.reverse(); + connected.erase(b); + } else if ((base.first_point() - next.first_point()).cast().squaredNorm() < limit_distance * limit_distance) { + base.reverse(); + base.polyline.append(std::move(next.polyline)); + base.reverse(); + connected.erase(b); + } + } + } + + ExtrusionPaths result; + for (auto& ext : connected) { + result.push_back(std::move(ext.second)); + } + return result; } -ExtrusionPaths sort_and_connect_extra_perimeters(const std::vector &extra_perims, double touch_distance) +ExtrusionPaths sort_and_connect_extra_perimeters(const std::vector &extra_perims, double extrusion_spacing) { std::vector connected_shells; - for (const ExtrusionPaths& ps : extra_perims) { - connected_shells.push_back(reconnect_extrusion_paths(ps, touch_distance)); + connected_shells.reserve(extra_perims.size()); + for (const ExtrusionPaths &ps : extra_perims) { + connected_shells.push_back(reconnect_extrusion_paths(ps, 1.0 * extrusion_spacing)); } + struct Pidx { size_t shell; @@ -708,8 +744,6 @@ ExtrusionPaths sort_and_connect_extra_perimeters(const std::vector, PidxHash>> dependencies; for (size_t shell = 0; shell < connected_shells.size(); shell++) { dependencies.push_back({}); @@ -719,29 +753,37 @@ ExtrusionPaths sort_and_connect_extra_perimeters(const std::vector current_dependencies{}; if (shell > 0) { for (const auto &prev_path : dependencies[shell - 1]) { - if (paths_touch(get_path(current_path), get_path(prev_path.first), touch_distance)) { + if (paths_touch(get_path(current_path), get_path(prev_path.first), extrusion_spacing * 2.0)) { current_dependencies.insert(prev_path.first); }; } - current_shell[current_path] = current_dependencies; - if (!any_point_found) { - current_point = get_path(current_path).first_point(); - any_point_found = true; - } } + current_shell[current_path] = current_dependencies; } } + Point current_point{}; + for (const ExtrusionPaths &ps : connected_shells) { + for (const ExtrusionPath &p : ps) { + if (!p.empty()) { + current_point = p.first_point(); + goto first_point_found; + } + } + } +first_point_found: + ExtrusionPaths sorted_paths{}; - Pidx npidx = Pidx{size_t(-1), 0}; - Pidx next_pidx = npidx; - bool reverse = false; + Pidx npidx = Pidx{size_t(-1), 0}; + Pidx next_pidx = npidx; + bool reverse = false; while (true) { if (next_pidx == npidx) { // find next pidx to print double dist = std::numeric_limits::max(); for (size_t shell = 0; shell < dependencies.size(); shell++) { for (const auto &p : dependencies[shell]) { - if (!p.second.empty()) continue; + if (!p.second.empty()) + continue; const auto &path = get_path(p.first); double dist_a = (path.first_point() - current_point).cast().squaredNorm(); if (dist_a < dist) { @@ -757,14 +799,21 @@ ExtrusionPaths sort_and_connect_extra_perimeters(const std::vector().squaredNorm(); + if (!p.second.empty()) + continue; + const ExtrusionPath &next_path = get_path(p.first); + double dist_a = (next_path.first_point() - current_point).cast().squaredNorm(); if (dist_a < dist) { dist = dist_a; next_pidx = p.first; @@ -789,17 +839,19 @@ ExtrusionPaths sort_and_connect_extra_perimeters(const std::vector scaled(5.0)){ + if (dist > scaled(5.0)) { next_pidx = npidx; } } } - ExtrusionPaths reconnected = reconnect_extrusion_paths(sorted_paths, touch_distance); + ExtrusionPaths reconnected = reconnect_extrusion_paths(sorted_paths, extrusion_spacing * 2.0); ExtrusionPaths filtered; filtered.reserve(reconnected.size()); for (ExtrusionPath &p : reconnected) { - if (p.length() > touch_distance) { filtered.push_back(p); } + if (p.length() > 3 * extrusion_spacing) { + filtered.push_back(p); + } } return filtered; @@ -936,7 +988,7 @@ std::tuple, Polygons> generate_extra_perimeters_over perimeter_polygon = intersection(offset(perimeter_polygon, -overhang_flow.scaled_spacing()), expanded_overhang_to_cover); if (perimeter_polygon.empty()) { // fill possible gaps of single extrusion width - Polygons shrinked = offset(prev, -0.4 * overhang_flow.scaled_spacing()); + Polygons shrinked = intersection(offset(prev, -0.3 * overhang_flow.scaled_spacing()), expanded_overhang_to_cover); if (!shrinked.empty()) { overhang_region.emplace_back(); extrusion_paths_append(overhang_region.back(), perimeter, ExtrusionRole::OverhangPerimeter, overhang_flow.mm3_per_mm(), @@ -944,15 +996,13 @@ std::tuple, Polygons> generate_extra_perimeters_over } Polylines fills; - ExPolygons gap = shrinked.empty() ? offset_ex(prev, overhang_flow.scaled_spacing() * 0.5) : - offset_ex(prev, -overhang_flow.scaled_spacing() * 0.5); + ExPolygons gap = shrinked.empty() ? offset_ex(prev, overhang_flow.scaled_spacing() * 0.5) : to_expolygons(shrinked); - //gap = expolygons_simplify(gap, overhang_flow.scaled_spacing()); for (const ExPolygon &ep : gap) { - ep.medial_axis(0.3 * overhang_flow.scaled_width(), overhang_flow.scaled_spacing() * 2.0, &fills); + ep.medial_axis(0.75 * overhang_flow.scaled_width(), 3.0 * overhang_flow.scaled_spacing(), &fills); } if (!fills.empty()) { - fills = intersection_pl(fills, inset_overhang_area); + fills = intersection_pl(fills, shrinked_overhang_to_cover); overhang_region.emplace_back(); extrusion_paths_append(overhang_region.back(), fills, ExtrusionRole::OverhangPerimeter, overhang_flow.mm3_per_mm(), overhang_flow.width(), overhang_flow.height()); @@ -981,9 +1031,11 @@ std::tuple, Polygons> generate_extra_perimeters_over } } Polylines perimeter = intersection_pl(to_polylines(perimeter_polygon), shrinked_overhang_to_cover); - overhang_region.emplace_back(); - extrusion_paths_append(overhang_region.back(), perimeter, ExtrusionRole::OverhangPerimeter, overhang_flow.mm3_per_mm(), - overhang_flow.width(), overhang_flow.height()); + if (!perimeter.empty()) { + overhang_region.emplace_back(); + extrusion_paths_append(overhang_region.back(), perimeter, ExtrusionRole::OverhangPerimeter, overhang_flow.mm3_per_mm(), + overhang_flow.width(), overhang_flow.height()); + } perimeter_polygon = expand(perimeter_polygon, 0.5 * overhang_flow.scaled_spacing()); perimeter_polygon = union_(perimeter_polygon, anchoring); @@ -1006,7 +1058,7 @@ std::tuple, Polygons> generate_extra_perimeters_over std::vector result{}; for (const std::vector &paths : extra_perims) { - result.push_back(sort_and_connect_extra_perimeters(paths, 2.0 * overhang_flow.scaled_spacing())); + result.push_back(sort_and_connect_extra_perimeters(paths, overhang_flow.scaled_spacing())); } #ifdef EXTRA_PERIM_DEBUG_FILES diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 295d3fe07..33dce04a2 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -659,7 +659,10 @@ std::tuple build_object_part_from_slice(const size_t &slice_i if (params.brim_type == BrimType::btOuterAndInner || params.brim_type == BrimType::btOuterOnly) { Polygon brim_hole = slice_poly.contour; brim_hole.reverse(); - brim.push_back(ExPolygon{expand(slice_poly.contour, scale_(params.brim_width)).front(), brim_hole}); + Polygons c = expand(slice_poly.contour, scale_(params.brim_width)); // For very small polygons, the expand may result in empty vector, even thought the input is correct. + if (!c.empty()) { + brim.push_back(ExPolygon{c.front(), brim_hole}); + } } if (params.brim_type == BrimType::btOuterAndInner || params.brim_type == BrimType::btInnerOnly) { Polygons brim_contours = slice_poly.holes; @@ -1182,7 +1185,8 @@ std::vector> gather_issues(const SupportPoint std::sort(partial_objects.begin(), partial_objects.end(), [](const PartialObject &left, const PartialObject &right) { return left.volume > right.volume; }); - float max_volume_part = partial_objects.front().volume; + // Object may have zero extrusions and thus no partial objects. (e.g. very tiny object) + float max_volume_part = partial_objects.empty() ? 0.0f : partial_objects.front().volume; for (const PartialObject &p : partial_objects) { if (p.volume > max_volume_part / 200.0f && !p.connected_to_bed) { result.emplace_back(SupportPointCause::UnstableFloatingPart, true);