diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 28ddb52..42945c0 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -66,7 +66,8 @@ namespace ClipperUtils { // Useful as an optimization for expensive ClipperLib operations, for example when clipping source polygons one by one // with a set of polygons covering the whole layer below. template - inline void clip_clipper_polygon_with_subject_bbox_templ(const PointsType &src, const BoundingBox &bbox, PointsType &out) + //w38 + inline void clip_clipper_polygon_with_subject_bbox_templ(const PointsType &src, const BoundingBox &bbox, PointsType &out,const bool get_entire_polygons=false) { using PointType = typename PointsType::value_type; @@ -121,6 +122,8 @@ namespace ClipperUtils { void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out) { clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out); } + //w38 + void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out, const bool get_entire_polygons) { clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out, get_entire_polygons); } void clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox, ZPoints &out) { clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out); } @@ -149,6 +152,14 @@ namespace ClipperUtils { return out; } + //w38 + [[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, const bool get_entire_polygons) + { + Polygon out; + clip_clipper_polygon_with_subject_bbox(src.points, bbox, out.points, get_entire_polygons); + return out; + } + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox) { Polygons out; @@ -172,7 +183,36 @@ namespace ClipperUtils { out.end()); return out; } -} + + //w38 + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon & src, + const BoundingBox &bbox, + const bool get_entire_polygons) + { + Polygons out; + out.reserve(src.num_contours()); + out.emplace_back(clip_clipper_polygon_with_subject_bbox(src.contour, bbox, get_entire_polygons)); + for (const Polygon &p : src.holes) + out.emplace_back(clip_clipper_polygon_with_subject_bbox(p, bbox, get_entire_polygons)); + out.erase(std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) { return polygon.empty(); }), out.end()); + return out; + } + //w38 + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons & src, + const BoundingBox &bbox, + const bool get_entire_polygons) + { + Polygons out; + out.reserve(number_polygons(src)); + for (const ExPolygon &p : src) { + Polygons temp = clip_clipper_polygons_with_subject_bbox(p, bbox, get_entire_polygons); + out.insert(out.end(), temp.begin(), temp.end()); + } + + out.erase(std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) { return polygon.empty(); }), out.end()); + return out; + } + } static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree) { diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index d42676e..a11df3f 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -326,9 +326,23 @@ namespace ClipperUtils { [[nodiscard]] ZPoints clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox); void clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, Polygon &out); [[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox); + + //w38 + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon & src, + const BoundingBox &bbox, + const bool get_entire_polygons); [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox); [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon &src, const BoundingBox &bbox); -} + + //w38 + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons & src, + const BoundingBox &bbox, + const bool get_entire_polygons); + [[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon & src, + const BoundingBox &bbox, + const bool get_entire_polygons); + void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out, const bool get_entire_polygons); + } // offset Polygons // Wherever applicable, please use the expand() / shrink() variants instead, they convey their purpose better. diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp index 2f01c59..a73ef9d 100644 --- a/src/libslic3r/ExtrusionEntity.cpp +++ b/src/libslic3r/ExtrusionEntity.cpp @@ -115,6 +115,22 @@ Polyline ExtrusionMultiPath::as_polyline() const } return out; } +//w38 +bool ExtrusionLoop::make_clockwise() +{ + bool was_ccw = this->polygon().is_counter_clockwise(); + if (was_ccw) + this->reverse_loop(); + return was_ccw; +} + +bool ExtrusionLoop::make_counter_clockwise() +{ + bool was_cw = this->polygon().is_clockwise(); + if (was_cw) + this->reverse_loop(); + return was_cw; +} double ExtrusionLoop::area() const { diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index 9d08d17..a6a56fb 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -328,6 +328,9 @@ public: double total_volume() const override { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } //w37 bool check_seam_point_angle(double angle_threshold = 0.174, double min_arm_length = 0.025) const; + //w38 + bool make_clockwise(); + bool make_counter_clockwise(); #ifndef NDEBUG bool validate() const { diff --git a/src/libslic3r/ExtrusionRole.hpp b/src/libslic3r/ExtrusionRole.hpp index af1d79b..6528954 100644 --- a/src/libslic3r/ExtrusionRole.hpp +++ b/src/libslic3r/ExtrusionRole.hpp @@ -95,9 +95,13 @@ struct ExtrusionRole : public ExtrusionRoleModifiers // Special flags describing loop enum ExtrusionLoopRole { - elrDefault, - elrContourInternalPerimeter, - elrSkirt, + //w38 + elrDefault = 0x0, + // Loop for the hole, not for the contour + elrHole = 0x1, + // Loop that is the most closest to infill + elrInternal = 0x2, + elrSkirt = 0x4, }; // Be careful when editing this list as many parts of the code depend diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index bb3e3a9..c57ddf5 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2950,18 +2950,29 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC { // Extrude all loops CCW. - bool is_hole = loop_src.is_clockwise(); + //w38 + //bool is_hole = loop_src.is_clockwise(); + ExtrusionLoop new_loop_src = loop_src; + bool is_hole = (new_loop_src.loop_role() & elrHole) == elrHole; + + //w38 + if (m_config.spiral_vase && !is_hole) { + // if spiral vase, we have to ensure that all contour are in the same orientation. + new_loop_src.make_counter_clockwise(); + } Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero(); //w37 if ((!m_config.spiral_vase && comment_is_perimeter(description)) || (this->config().seam_slope_type == SeamScarfType::None) &&comment_is_perimeter(description) ) { assert(m_layer != nullptr); - seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, seam_point); + //w38 + seam_point = m_seam_placer.place_seam(m_layer, new_loop_src, m_config.external_perimeters_first, seam_point); } // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns, // thus empty path segments will not be produced by G-code export. + //w38 GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam( - loop_src, is_hole, m_scaled_resolution, seam_point, scaled(0.0015)); + new_loop_src, is_hole, m_scaled_resolution, seam_point, scaled(0.0015)); // Clip the path to avoid the extruder to get exactly on the first point of the loop; // if polyline was shorter than the clipping distance we'd get a null polyline, so @@ -2975,7 +2986,8 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC assert(validate_smooth_path(smooth_path, ! m_enable_loop_clipping)); // Apply the small perimeter speed. - if (loop_src.paths.front().role().is_perimeter() && loop_src.length() <= SMALL_PERIMETER_LENGTH && speed == -1) + //w38 + if (new_loop_src.paths.front().role().is_perimeter() && new_loop_src.length() <= SMALL_PERIMETER_LENGTH && speed == -1) speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed); // Extrude along the smooth path. @@ -2985,7 +2997,8 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC double ext_length = 0; double inner_length = 0; double start_height = 0; - bool enable_seam_slope = loop_src.check_seam_point_angle(m_config.scarf_angle_threshold.value * M_PI / 180.0); + //w38 + bool enable_seam_slope = new_loop_src.check_seam_point_angle(m_config.scarf_angle_threshold.value * M_PI / 180.0); if (this->config().seam_slope_start_height.percent) start_height = this->config().seam_slope_start_height * this->config().layer_height / 100; else @@ -3077,7 +3090,8 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC // Wipe will hide the seam. m_wipe.set_path(std::move(smooth_path)); - } else if (loop_src.paths.back().role().is_external_perimeter() && m_layer != nullptr && m_config.perimeters.value > 1) { + }//w38 + else if (new_loop_src.paths.back().role().is_external_perimeter() && m_layer != nullptr && m_config.perimeters.value > 1) { // Only wipe inside if the wipe along the perimeter is disabled. // Make a little move inwards before leaving loop. diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index e906ca7..87a295d 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -683,7 +683,10 @@ void Layer::make_perimeters() && config.infill_overlap == other_config.infill_overlap && config.fuzzy_skin == other_config.fuzzy_skin && config.fuzzy_skin_thickness == other_config.fuzzy_skin_thickness - && config.fuzzy_skin_point_dist == other_config.fuzzy_skin_point_dist) + && config.fuzzy_skin_point_dist == other_config.fuzzy_skin_point_dist + //w38 + && config.overhang_reverse == other_config.overhang_reverse + && config.overhang_reverse_threshold == other_config.overhang_reverse_threshold) { layer_region_reset_perimeters(*other_layerm); layer_region_ids.push_back(it - m_regions.begin()); diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 45891db..12f3a66 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -114,6 +114,8 @@ void LayerRegion::make_perimeters( Polygons lower_layer_polygons_cache; //w16 Polygons upper_layer_polygons_cache; + //w38 + params.lower_slices = lower_slices; for (const Surface &surface : slices) { auto perimeters_begin = uint32_t(m_perimeters.size()); diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 42517cd..941dd2e 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -285,12 +285,62 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine &ext_lines, double fuzzy using PerimeterGeneratorLoops = std::vector; -static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator::Parameters ¶ms, const Polygons &lower_slices_polygons_cache, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) +//w38 +template +static bool detect_steep_overhang(const PrintRegionConfig &config, + bool is_contour, + const BoundingBox & extrusion_bboxs, + double extrusion_width, + const _T extrusion, + const ExPolygons * lower_slices, + bool & steep_overhang_contour, + bool & steep_overhang_hole) +{ + double threshold = config.overhang_reverse_threshold.get_abs_value(extrusion_width); + // Special case: reverse on every odd layer + if (threshold < EPSILON) { + if (is_contour) { + steep_overhang_contour = true; + } else { + steep_overhang_hole = true; + } + + return true; + } + + Polygons lower_slcier_chopped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*lower_slices, extrusion_bboxs,true); + + // All we need to check is whether we have lines outside `threshold` + double off = threshold - 0.5 * extrusion_width; + + auto limiton_polygons = offset(lower_slcier_chopped, float(scale_(off))); + + auto remain_polylines = diff_pl(extrusion, limiton_polygons); + if (!remain_polylines.empty()) { + if (is_contour) { + steep_overhang_contour = true; + } else { + steep_overhang_hole = true; + } + + return true; + } + + return false; +} + +//w38 +static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator::Parameters ¶ms, const Polygons &lower_slices_polygons_cache, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls, + bool & steep_overhang_contour, + bool & steep_overhang_hole) { // loops is an arrayref of ::Loop objects // turn each one into an ExtrusionLoop object ExtrusionEntityCollection coll; Polygon fuzzified; + //w38 + bool overhangs_reverse = params.config.overhang_reverse && + params.layer_id % 2 == 1; for (const PerimeterGeneratorLoop &loop : loops) { bool is_external = loop.is_external(); @@ -301,13 +351,24 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator // Note that we set loop role to ContourInternalPerimeter // also when loop is both internal and external (i.e. // there's only one contour loop). - loop_role = elrContourInternalPerimeter; + //w38 + loop_role = elrInternal;//loop_role = elrContourInternalPerimeter; } else { - loop_role = elrDefault; + //w38 + loop_role = loop.is_contour? elrDefault : elrHole;//loop_role = elrDefault; } // detect overhanging/bridging perimeters ExtrusionPaths paths; + //w38 + double extrusion_width; + if (is_external) { + + extrusion_width = params.ext_perimeter_flow.width(); + } else { + extrusion_width = params.perimeter_flow.width(); + } + const Polygon &polygon = loop.fuzzify ? fuzzified : loop.polygon; if (loop.fuzzify) { fuzzified = loop.polygon; @@ -318,6 +379,19 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator params.object_config.support_material_contact_distance.value == 0)) { BoundingBox bbox(polygon.points); bbox.offset(SCALED_EPSILON); + //w38 + if (overhangs_reverse && params.config.fuzzy_skin != FuzzySkinType::None) { + if (loop.is_contour) { + steep_overhang_contour = true; + } else if (params.config.fuzzy_skin != FuzzySkinType::External) { + steep_overhang_hole = true; + } + } + bool found_steep_overhang = (loop.is_contour && steep_overhang_contour) || (!loop.is_contour && steep_overhang_hole); + if (overhangs_reverse && !found_steep_overhang) { + detect_steep_overhang(params.config, loop.is_contour, bbox, extrusion_width, Polygons{polygon}, + params.lower_slices, steep_overhang_contour, steep_overhang_hole); + } Polygons lower_slices_polygons_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(lower_slices_polygons_cache, bbox); // get non-overhang paths by intersecting this loop with the grown lower slices extrusion_paths_append( @@ -381,10 +455,13 @@ static ExtrusionEntityCollection traverse_loops_classic(const PerimeterGenerator } else { const PerimeterGeneratorLoop &loop = loops[idx.first]; assert(thin_walls.empty()); - ExtrusionEntityCollection children = traverse_loops_classic(params, lower_slices_polygons_cache, loop.children, thin_walls); + //w38 + ExtrusionEntityCollection children = traverse_loops_classic(params, lower_slices_polygons_cache, loop.children, thin_walls,steep_overhang_contour, steep_overhang_hole); out.entities.reserve(out.entities.size() + children.entities.size() + 1); ExtrusionLoop *eloop = static_cast(coll.entities[idx.first]); coll.entities[idx.first] = nullptr; + //w38 + //eloop->make_counter_clockwise(); if (loop.is_contour) { if (eloop->is_clockwise()) eloop->reverse_loop(); @@ -505,8 +582,16 @@ struct PerimeterGeneratorArachneExtrusion bool fuzzify = false; }; -static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::Parameters ¶ms, const Polygons &lower_slices_polygons_cache, std::vector &pg_extrusions) +//w38 +static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::Parameters & params, + const Polygons & lower_slices_polygons_cache, + std::vector &pg_extrusions, + bool & steep_overhang_contour, + bool & steep_overhang_hole) { + //w38 + bool overhangs_reverse = params.config.overhang_reverse && + params.layer_id % 2 == 1; ExtrusionEntityCollection extrusion_coll; for (PerimeterGeneratorArachneExtrusion &pg_extrusion : pg_extrusions) { Arachne::ExtrusionLine *extrusion = pg_extrusion.extrusion; @@ -556,6 +641,40 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role_normal, is_external ? params.ext_perimeter_flow : params.perimeter_flow); + //w38 + if (overhangs_reverse && params.config.fuzzy_skin != FuzzySkinType::None) { + if (pg_extrusion.is_contour) { + steep_overhang_contour = true; + } else if (params.config.fuzzy_skin != FuzzySkinType::External) { + steep_overhang_hole = true; + } + } + bool found_steep_overhang = (pg_extrusion.is_contour && steep_overhang_contour) || + (!pg_extrusion.is_contour && steep_overhang_hole); + if (overhangs_reverse && !found_steep_overhang) { + std::map recognization_paths; + for (const ExtrusionPath &path : paths) { + if (recognization_paths.count(path.width())) + recognization_paths[path.width()].emplace_back(std::move(path)); + else + recognization_paths.insert(std::pair(path.width(), {std::move(path)})); + } + for (const auto &it : recognization_paths) { + Polylines be_clipped; + + for (const ExtrusionPath &p : it.second) { + be_clipped.emplace_back(std::move(p.polyline)); + } + + BoundingBox extrusion_bboxs = get_extents(be_clipped); + + if (detect_steep_overhang(params.config, pg_extrusion.is_contour, extrusion_bboxs, it.first, be_clipped, + params.lower_slices, steep_overhang_contour, steep_overhang_hole)) { + break; + } + } + } + // get overhang paths by checking what parts of this loop fall // outside the grown lower slices (thus where the distance between // the loop centerline and original lower slices is >= half nozzle diameter @@ -571,6 +690,9 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::P // Especially for open extrusion, we need to select a starting point that is at the start // or the end of the extrusions to make one continuous line. Also, we prefer a non-overhang // starting point. + //w38 + ExtrusionLoop extrusion_loop(std::move(paths), pg_extrusion.is_contour ? elrDefault : elrHole); + extrusion_loop.make_counter_clockwise(); struct PointInfo { size_t occurrence = 0; @@ -1105,6 +1227,23 @@ void PerimeterGenerator::add_infill_contour_for_arachne(ExPolygons infill_contou } +//w38 +static void reorient_perimeters(ExtrusionEntityCollection &entities, bool steep_overhang_contour, bool steep_overhang_hole) +{ + if (steep_overhang_hole || steep_overhang_contour) { + for (auto entity : entities) { + if (entity->is_loop()) { + ExtrusionLoop *eloop = static_cast(entity); + bool need_reverse = ((eloop->loop_role() & elrHole) == elrHole) ? steep_overhang_hole : steep_overhang_contour; + if (need_reverse) { + eloop->make_clockwise(); + } + } + } + } +} + + // Thanks, Cura developers, for implementing an algorithm for generating perimeters with variable width (Arachne) that is based on the paper // "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling" void PerimeterGenerator::process_arachne( @@ -1308,8 +1447,15 @@ void PerimeterGenerator::process_arachne( } } - if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions); !extrusion_coll.empty()) + //w38 + bool steep_overhang_contour = false; + bool steep_overhang_hole = false; + if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions, + steep_overhang_contour, steep_overhang_hole); + !extrusion_coll.empty()) { + reorient_perimeters(extrusion_coll, steep_overhang_contour, steep_overhang_hole); out_loops.append(extrusion_coll); + } ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour()); //w17 @@ -1645,8 +1791,15 @@ void PerimeterGenerator::process_with_one_wall_arachne( } } - if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions); !extrusion_coll.empty()) + //w38 + bool steep_overhang_contour = false; + bool steep_overhang_hole = false; + if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions, + steep_overhang_contour, steep_overhang_hole); + !extrusion_coll.empty()) { + reorient_perimeters(extrusion_coll, steep_overhang_contour, steep_overhang_hole); out_loops.append(extrusion_coll); + } //w16 @@ -2037,7 +2190,11 @@ void PerimeterGenerator::process_classic( } } // at this point, all loops should be in contours[0] - ExtrusionEntityCollection entities = traverse_loops_classic(params, lower_layer_polygons_cache, contours.front(), thin_walls); + //w38 + bool steep_overhang_contour = false; + bool steep_overhang_hole = false; + ExtrusionEntityCollection entities = traverse_loops_classic(params, lower_layer_polygons_cache, contours.front(), thin_walls,steep_overhang_contour, steep_overhang_hole); + reorient_perimeters(entities, steep_overhang_contour, steep_overhang_hole); // if brim will be printed, reverse the order of perimeters so that // we continue inwards after having finished the brim // TODO: add test for perimeter order diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index db284a5..d326c39 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -39,7 +39,9 @@ struct Parameters { scaled_resolution(scaled(print_config.gcode_resolution.value)), mm3_per_mm(perimeter_flow.mm3_per_mm()), ext_mm3_per_mm(ext_perimeter_flow.mm3_per_mm()), - mm3_per_mm_overhang(overhang_flow.mm3_per_mm()) + mm3_per_mm_overhang(overhang_flow.mm3_per_mm()), + //w38 + lower_slices(lower_slices) { } @@ -53,6 +55,8 @@ struct Parameters { const PrintRegionConfig &config; const PrintObjectConfig &object_config; const PrintConfig &print_config; + //w38 + const ExPolygons * lower_slices; // Derived parameters bool spiral_vase; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 778b7ee..fc9605a 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -498,7 +498,8 @@ static std::vector s_Preset_print_options { //w37 ,"seam_slope_type", "seam_slope_conditional", "scarf_angle_threshold", "seam_slope_start_height", "seam_slope_entire_loop", "seam_slope_min_length", "seam_slope_steps", "seam_slope_inner_walls" -}; + //w38 + ,"overhang_reverse","overhang_reverse_threshold"}; static std::vector s_Preset_filament_options { "filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ff94f6c..8876afd 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2320,6 +2320,28 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(true)); + //w38 + def = this->add("overhang_reverse", coBool); + def->label = L("Reverse on odd"); + def->category = L("Layers and Perimeters"); + def->tooltip = L("Extrude perimeters that have a part over an overhang in the reverse direction on odd layers. This alternating " + "pattern can drastically improve steep overhang."); + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionBool(false)); + + //w38 + def = this->add("overhang_reverse_threshold", coFloatOrPercent); + def->label = L("Reverse threshold"); + def->category = L("Layers and Perimeters"); + def->tooltip = L("Number of mm the overhang need to be for the reversal to be considered useful. Can be a % of the perimeter width." + "\nValue 0 enables reversal on every odd layers regardless."); + def->sidetext = L("mm or %"); + def->ratio_over = "line_width"; + def->min = 0; + def->max_literal = 20; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloatOrPercent(50, true)); + def = this->add("parking_pos_retraction", coFloat); def->label = L("Filament parking position"); def->tooltip = L("Distance of the extruder tip from the position where the filament is parked " diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 9885271..a31908a 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -693,6 +693,10 @@ PRINT_CONFIG_CLASS_DEFINE( //w30 ((ConfigOptionFloat, top_solid_infill_flow_ratio)) ((ConfigOptionFloat, bottom_solid_infill_flow_ratio)) + + //w38 + ((ConfigOptionBool, overhang_reverse)) + ((ConfigOptionFloatOrPercent, overhang_reverse_threshold)) ) PRINT_CONFIG_CLASS_DEFINE( diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index d49adc0..b2a1304 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -391,6 +391,13 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("seam_slope_steps", has_seam_slope); toggle_field("seam_slope_inner_walls", has_seam_slope); toggle_field("seam_slope_min_length", !config->opt_bool("seam_slope_entire_loop")); + + //w38 + bool has_detect_overhang_wall = config->opt_bool("overhangs"); + bool has_overhang_reverse = config->opt_bool("overhang_reverse"); + bool allow_overhang_reverse = has_detect_overhang_wall && !has_spiral_vase; + toggle_field("overhang_reverse", allow_overhang_reverse); + toggle_field("overhang_reverse_threshold", allow_overhang_reverse && has_overhang_reverse); } void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 915d544..8c2a0b5 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1460,6 +1460,10 @@ void TabPrint::build() optgroup->append_single_option_line("thick_bridges", category_path + "thick_bridges"); optgroup->append_single_option_line("overhangs", category_path + "detect-bridging-perimeters"); + //w38 + optgroup->append_single_option_line("overhang_reverse"); + optgroup->append_single_option_line("overhang_reverse_threshold"); + optgroup = page->new_optgroup(L("Advanced")); optgroup->append_single_option_line("seam_position", category_path + "seam-position"); //Y21