diff --git a/src/libslic3r/Brim.cpp b/src/libslic3r/Brim.cpp index 858ca770b..08e0d4151 100644 --- a/src/libslic3r/Brim.cpp +++ b/src/libslic3r/Brim.cpp @@ -126,7 +126,7 @@ static ConstPrintObjectPtrs get_top_level_objects_with_brim(const Print &print, return top_level_objects_with_brim; } -static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_level_objects_with_brim) +static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_level_objects_with_brim, const double scaled_resolution) { Polygons islands; for (const PrintObject *object : top_level_objects_with_brim) { @@ -139,7 +139,7 @@ static Polygons top_level_outer_brim_islands(const ConstPrintObjectPtrs &top_lev for (const ExPolygon &ex_poly : get_print_object_bottom_layer_expolygons(*object)) { Polygons contour_offset = offset(ex_poly.contour, brim_separation, ClipperLib::jtSquare); for (Polygon &poly : contour_offset) - poly.douglas_peucker(SCALED_RESOLUTION); + poly.douglas_peucker(scaled_resolution); polygons_append(islands_object, std::move(contour_offset)); } @@ -359,13 +359,14 @@ static void make_inner_brim(const Print &print, ExtrusionEntityCollection &brim) { assert(print.objects().size() == bottom_layers_expolygons.size()); + const auto scaled_resolution = scaled(print.config().gcode_resolution.value); Flow flow = print.brim_flow(); ExPolygons islands_ex = inner_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing())); Polygons loops; islands_ex = offset_ex(islands_ex, -0.5f * float(flow.scaled_spacing()), ClipperLib::jtSquare); for (size_t i = 0; !islands_ex.empty(); ++i) { for (ExPolygon &poly_ex : islands_ex) - poly_ex.douglas_peucker(SCALED_RESOLUTION); + poly_ex.douglas_peucker(scaled_resolution); polygons_append(loops, to_polygons(islands_ex)); islands_ex = offset_ex(islands_ex, -float(flow.scaled_spacing()), ClipperLib::jtSquare); } @@ -380,10 +381,11 @@ static void make_inner_brim(const Print &print, // Collect islands_area to be merged into the final 1st layer convex hull. ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cancel, Polygons &islands_area) { + const auto scaled_resolution = scaled(print.config().gcode_resolution.value); Flow flow = print.brim_flow(); std::vector bottom_layers_expolygons = get_print_bottom_layers_expolygons(print); ConstPrintObjectPtrs top_level_objects_with_brim = get_top_level_objects_with_brim(print, bottom_layers_expolygons); - Polygons islands = top_level_outer_brim_islands(top_level_objects_with_brim); + Polygons islands = top_level_outer_brim_islands(top_level_objects_with_brim, scaled_resolution); ExPolygons islands_area_ex = top_level_outer_brim_area(print, top_level_objects_with_brim, bottom_layers_expolygons, float(flow.scaled_spacing())); islands_area = to_polygons(islands_area_ex); @@ -393,7 +395,7 @@ ExtrusionEntityCollection make_brim(const Print &print, PrintTryCancel try_cance try_cancel(); islands = expand(islands, float(flow.scaled_spacing()), ClipperLib::jtSquare); for (Polygon &poly : islands) - poly.douglas_peucker(SCALED_RESOLUTION); + poly.douglas_peucker(scaled_resolution); polygons_append(loops, shrink(islands, 0.5f * float(flow.scaled_spacing()))); } loops = union_pt_chained_outside_in(loops); diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 117066690..726ba17a4 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -329,7 +329,8 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ std::vector surface_fills = group_fills(*this); - const Slic3r::BoundingBox bbox = this->object()->bounding_box(); + const Slic3r::BoundingBox bbox = this->object()->bounding_box(); + const auto resolution = this->object()->print()->config().gcode_resolution.value; #ifdef SLIC3R_DEBUG_SLICE_PROCESSING { @@ -371,6 +372,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive: params.dont_adjust = false; // surface_fill.params.dont_adjust; params.anchor_length = surface_fill.params.anchor_length; params.anchor_length_max = surface_fill.params.anchor_length_max; + params.resolution = resolution; for (ExPolygon &expoly : surface_fill.expolygons) { // Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon. diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index eb9c4f1cc..a881ce611 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -44,6 +44,9 @@ struct FillParams float anchor_length { 1000.f }; float anchor_length_max { 1000.f }; + // G-code resolution. + double resolution { 0.0125 }; + // Don't adjust spacing to fill the space evenly. bool dont_adjust { true }; diff --git a/src/libslic3r/Fill/FillPlanePath.cpp b/src/libslic3r/Fill/FillPlanePath.cpp index f1e3884bc..49b02b542 100644 --- a/src/libslic3r/Fill/FillPlanePath.cpp +++ b/src/libslic3r/Fill/FillPlanePath.cpp @@ -31,7 +31,8 @@ void FillPlanePath::_fill_surface_single( coord_t(ceil(coordf_t(bounding_box.min.x()) / distance_between_lines)), coord_t(ceil(coordf_t(bounding_box.min.y()) / distance_between_lines)), coord_t(ceil(coordf_t(bounding_box.max.x()) / distance_between_lines)), - coord_t(ceil(coordf_t(bounding_box.max.y()) / distance_between_lines))); + coord_t(ceil(coordf_t(bounding_box.max.y()) / distance_between_lines)), + params.resolution); if (pts.size() >= 2) { // Convert points to a polyline, upscale. @@ -58,7 +59,7 @@ void FillPlanePath::_fill_surface_single( } // Follow an Archimedean spiral, in polar coordinates: r=a+b\theta -Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) +Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) { // Radius to achieve. coordf_t rmax = std::sqrt(coordf_t(max_x)*coordf_t(max_x)+coordf_t(max_y)*coordf_t(max_y)) * std::sqrt(2.) + 1.5; @@ -72,8 +73,8 @@ Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t m out.emplace_back(0, 0); out.emplace_back(1, 0); while (r < rmax) { - // Discretization angle to achieve a discretization error lower than RESOLUTION. - theta += 2. * acos(1. - RESOLUTION / r); + // Discretization angle to achieve a discretization error lower than resolution. + theta += 2. * acos(1. - resolution / r); r = a + b * theta; out.emplace_back(r * cos(theta), r * sin(theta)); } @@ -125,7 +126,7 @@ static inline Point hilbert_n_to_xy(const size_t n) return Point(x, y); } -Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) +Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */) { // Minimum power of two square to fit the domain. size_t sz = 2; @@ -148,7 +149,7 @@ Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, return line; } -Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) +Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double /* resolution */) { // Radius to achieve. coordf_t rmax = std::sqrt(coordf_t(max_x)*coordf_t(max_x)+coordf_t(max_y)*coordf_t(max_y)) * std::sqrt(2.) + 1.5; diff --git a/src/libslic3r/Fill/FillPlanePath.hpp b/src/libslic3r/Fill/FillPlanePath.hpp index cf19a95f8..075f17433 100644 --- a/src/libslic3r/Fill/FillPlanePath.hpp +++ b/src/libslic3r/Fill/FillPlanePath.hpp @@ -28,7 +28,7 @@ protected: float _layer_angle(size_t idx) const override { return 0.f; } virtual bool _centered() const = 0; - virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) = 0; + virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) = 0; }; class FillArchimedeanChords : public FillPlanePath @@ -39,7 +39,7 @@ public: protected: bool _centered() const override { return true; } - Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) override; + Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) override; }; class FillHilbertCurve : public FillPlanePath @@ -50,7 +50,7 @@ public: protected: bool _centered() const override { return false; } - Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) override; + Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) override; }; class FillOctagramSpiral : public FillPlanePath @@ -61,7 +61,7 @@ public: protected: bool _centered() const override { return true; } - Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) override; + Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y, const double resolution) override; }; } // namespace Slic3r diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index f6105b180..4ce078136 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2414,6 +2414,7 @@ void GCode::apply_print_config(const PrintConfig &print_config) { m_writer.apply_print_config(print_config); m_config.apply(print_config); + m_scaled_resolution = scaled(print_config.gcode_resolution.value); } void GCode::append_full_config(const Print &print, std::string &str) @@ -2565,7 +2566,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) { // description += ExtrusionLoop::role_to_string(loop.loop_role()); // description += ExtrusionEntity::role_to_string(path->role); - path->simplify(SCALED_RESOLUTION); + path->simplify(m_scaled_resolution); gcode += this->_extrude(*path, description, speed); } @@ -2619,7 +2620,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, std::string for (ExtrusionPath path : multipath.paths) { // description += ExtrusionLoop::role_to_string(loop.loop_role()); // description += ExtrusionEntity::role_to_string(path->role); - path.simplify(SCALED_RESOLUTION); + path.simplify(m_scaled_resolution); gcode += this->_extrude(path, description, speed); } if (m_wipe.enable) { @@ -2647,7 +2648,7 @@ std::string GCode::extrude_entity(const ExtrusionEntity &entity, std::string des std::string GCode::extrude_path(ExtrusionPath path, std::string description, double speed) { // description += ExtrusionEntity::role_to_string(path.role()); - path.simplify(SCALED_RESOLUTION); + path.simplify(m_scaled_resolution); std::string gcode = this->_extrude(path, description, speed); if (m_wipe.enable) { m_wipe.path = std::move(path.polyline); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 8dfe0fdce..1b2c560da 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -345,6 +345,8 @@ private: methods. */ Vec2d m_origin; FullPrintConfig m_config; + // scaled G-code resolution + double m_scaled_resolution; GCodeWriter m_writer; PlaceholderParser m_placeholder_parser; // For random number generator etc. diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 55d3c6aa5..51c26209e 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -322,7 +322,7 @@ void PerimeterGenerator::process() for (const Surface &surface : this->slices->surfaces) { // detect how many perimeters must be generated for this island int loop_number = this->config->perimeters + surface.extra_perimeters - 1; // 0-indexed loops - ExPolygons last = union_ex(surface.expolygon.simplify_p(SCALED_RESOLUTION)); + ExPolygons last = union_ex(surface.expolygon.simplify_p(m_scaled_resolution)); ExPolygons gaps; if (loop_number >= 0) { // In case no perimeters are to be generated, loop_number will equal to -1. @@ -533,7 +533,7 @@ void PerimeterGenerator::process() // simplify infill contours according to resolution Polygons pp; for (ExPolygon &ex : last) - ex.simplify_p(SCALED_RESOLUTION, &pp); + ex.simplify_p(m_scaled_resolution, &pp); // collapse too narrow infill areas coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE)); // append infill areas to fill_surfaces diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index f55555068..0b3501d36 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -50,6 +50,7 @@ public: overhang_flow(flow), solid_infill_flow(flow), config(config), object_config(object_config), print_config(print_config), m_spiral_vase(spiral_vase), + m_scaled_resolution(scaled(print_config->gcode_resolution.value)), loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces), m_ext_mm3_per_mm(-1), m_mm3_per_mm(-1), m_mm3_per_mm_overhang(-1) {} @@ -63,6 +64,7 @@ public: private: bool m_spiral_vase; + double m_scaled_resolution; double m_ext_mm3_per_mm; double m_mm3_per_mm; double m_mm3_per_mm_overhang; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 7950d38de..65027a390 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -444,7 +444,7 @@ static std::vector s_Preset_print_options { "ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width", "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "clip_multipart_objects", - "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", + "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits" }; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 086aeb2c4..acb4ee6a6 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -214,7 +214,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n } else if ( opt_key == "first_layer_extrusion_width" || opt_key == "min_layer_height" - || opt_key == "max_layer_height") { + || opt_key == "max_layer_height" + || opt_key == "gcode_resolution") { osteps.emplace_back(posPerimeters); osteps.emplace_back(posInfill); osteps.emplace_back(posSupportMaterial); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 7af71fe30..4ab893bef 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2072,7 +2072,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionInt(0)); def = this->add("resolution", coFloat); - def->label = L("Resolution"); + def->label = L("Slice resolution"); def->tooltip = L("Minimum detail resolution, used to simplify the input file for speeding up " "the slicing job and reducing memory usage. High-resolution models often carry " "more detail than printers can render. Set to zero to disable any simplification " @@ -2082,6 +2082,18 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0)); + def = this->add("gcode_resolution", coFloat); + def->label = L("G-code resolution"); + def->tooltip = L("Maximum deviation of exported G-code paths from their full resolution counterparts. " + "Very high resolution G-code requires huge amount of RAM to slice and preview, " + "also a 3D printer may stutter not being able to process a high resolution G-code in a timely manner. " + "On the other hand, a low resolution G-code will produce a low poly effect and because " + "the G-code reduction is performed at each layer independently, visible artifacts may be produced."); + def->sidetext = L("mm"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0.0125)); + def = this->add("retract_before_travel", coFloats); def->label = L("Minimum travel after retraction"); def->tooltip = L("Retraction is not triggered when travel moves are shorter than this length."); @@ -3940,6 +3952,10 @@ void DynamicPrintConfig::normalize_fdm() this->opt("fill_density", true)->value = 0; } } + + if (auto *opt_gcode_resolution = this->opt("gcode_resolution", false); opt_gcode_resolution) + // Resolution will be above 1um. + opt_gcode_resolution->value = std::max(opt_gcode_resolution->value, 0.001); } void handle_legacy_sla(DynamicPrintConfig &config) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 657f34ad1..8d3ab3720 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -734,6 +734,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionString, printer_model)) ((ConfigOptionString, printer_notes)) ((ConfigOptionFloat, resolution)) + ((ConfigOptionFloat, gcode_resolution)) ((ConfigOptionFloats, retract_before_travel)) ((ConfigOptionBools, retract_layer_change)) ((ConfigOptionFloat, skirt_distance)) diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index a29436189..5e0fb67b3 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -47,9 +47,6 @@ static constexpr double EPSILON = 1e-4; // int32_t fits an interval of (-2147.48mm, +2147.48mm) // with int64_t we don't have to worry anymore about the size of the int. static constexpr double SCALING_FACTOR = 0.000001; -// RESOLUTION, SCALED_RESOLUTION: Used as an error threshold for a Douglas-Peucker polyline simplification algorithm. -static constexpr double RESOLUTION = 0.0125; -#define SCALED_RESOLUTION (RESOLUTION / SCALING_FACTOR) static constexpr double PI = 3.141592653589793238; // When extruding a closed loop, the loop is interrupted and shortened a bit to reduce the seam. static constexpr double LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER = 0.15; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 18bd2eb0d..6ea044f40 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1650,6 +1650,7 @@ void TabPrint::build() optgroup->append_single_option_line("slice_closing_radius"); optgroup->append_single_option_line("slicing_mode"); optgroup->append_single_option_line("resolution"); + optgroup->append_single_option_line("gcode_resolution"); optgroup->append_single_option_line("xy_size_compensation"); optgroup->append_single_option_line("elefant_foot_compensation", "elephant-foot-compensation_114487");