From 8ba954d2aae58d43b7888c393ec52136f87524d0 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 13 Mar 2019 12:01:32 +0100 Subject: [PATCH] new feature: smooth curve * it create more points to smooth rough curves, do hide polygons in the final print. also, create a new tab in the print settings for the ones related to the mesh. --- src/libslic3r/Print.hpp | 3 +- src/libslic3r/PrintConfig.cpp | 37 +++++++++++-- src/libslic3r/PrintConfig.hpp | 4 ++ src/libslic3r/PrintObject.cpp | 99 +++++++++++++++++++++++++++++++++-- src/slic3r/GUI/Preset.cpp | 2 + src/slic3r/GUI/Tab.cpp | 41 +++++++++------ 6 files changed, 161 insertions(+), 25 deletions(-) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index ba6a6c823..52015bd1b 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -172,7 +172,8 @@ private: void generate_support_material(); void _slice(const std::vector &layer_height_profile); - void _offsetHoles(float hole_delta, LayerRegion *layerm); + void _offset_holes(float hole_delta, LayerRegion *layerm); + void _smooth_curves(LayerRegion *layerm); std::string _fix_slicing_errors(); void _simplify_slices(double distance); void _make_perimeters(); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 171489a1f..d0363a445 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -375,7 +375,7 @@ void PrintConfigDef::init_fff_params() def = this->add("elefant_foot_compensation", coFloat); def->label = L("First layer"); def->full_label = L("First layer compensation"); - def->category = L("Advanced"); + def->category = L("Slicing"); def->tooltip = L("The first layer will be grown / shrunk in the XY plane by the configured value " "to compensate for the 1st layer squish aka an Elephant Foot effect. (should be negative = inwards)"); def->sidetext = L("mm"); @@ -2132,6 +2132,35 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->default_value = new ConfigOptionFloatOrPercent(15, false); + def = this->add("curve_smoothing_angle", coFloat); + def->label = L("Min angle"); + def->full_label = L("Curve smoothing minimum angle"); + def->category = L("Slicing"); + def->tooltip = L("Minimum angle at a vertex to enable smoothing" + " (trying to create a curve around the vertex). " + "180 : nothing will be smooth, 0 : all angles will be smoothen."); + def->sidetext = L("°"); + def->cli = "curve-smoothing-angle=f"; + def->min = 0; + def->max = 180; + def->mode = comAdvanced; + def->default_value = new ConfigOptionFloat(0); + + def = this->add("curve_smoothing_precision", coFloat); + def->label = L("Precision"); + def->full_label = L("Curve smoothing precision"); + def->category = L("Slicing"); + def->tooltip = L("These parameter allow the slicer to smooth the angles in each layer. " + "The precision will be at least the new precision of the curve. Set to 0 to deactivate." + "\nNote: as it use the polygon's edges and only work in the 2D planes, " + "you must have a very clean or hand-made 3D model." + "\nIt's really only useful to smoothen functional models or very wide angles."); + def->sidetext = L("mm"); + def->min = 0; + def->cli = "curve-smoothing-precision=f"; + def->mode = comAdvanced; + def->default_value = new ConfigOptionFloat(0); + def = this->add("solid_infill_below_area", coFloat); def->label = L("Solid infill threshold area"); def->category = L("Infill"); @@ -2258,7 +2287,7 @@ void PrintConfigDef::init_fff_params() def = this->add("model_precision", coFloat); def->label = L("Model rounding precision"); def->full_label = L("Model rounding precision"); - def->category = L("Advanced"); + def->category = L("Slicing"); def->tooltip = L("This is the rounding error of the input object." " It's used to align points that should be in the same line." " Put 0 to disable."); @@ -2860,7 +2889,7 @@ void PrintConfigDef::init_fff_params() def = this->add("xy_size_compensation", coFloat); def->label = L("All layers"); def->full_label = L("XY size compensation"); - def->category = L("Advanced"); + def->category = L("Slicing"); def->tooltip = L("The object will be grown/shrunk in the XY plane by the configured value " "(negative = inwards, positive = outwards). This might be useful " "for fine-tuning sizes."); @@ -2872,7 +2901,7 @@ void PrintConfigDef::init_fff_params() def = this->add("hole_size_compensation", coFloat); def->label = L("Holes"); def->full_label = L("XY holes compensation"); - def->category = L("Advanced"); + def->category = L("Slicing"); def->tooltip = L("The convex holes will be grown / shrunk in the XY plane by the configured value" " (negative = inwards, positive = outwards, should be negative as the holes are always a bit smaller irl)." " This might be useful for fine-tuning hole sizes."); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 5394355e5..d856f88aa 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -561,6 +561,8 @@ public: ConfigOptionEnum bottom_fill_pattern; ConfigOptionFloatOrPercent bridged_infill_margin; ConfigOptionFloat bridge_speed; + ConfigOptionFloat curve_smoothing_precision; + ConfigOptionFloat curve_smoothing_angle; ConfigOptionBool ensure_vertical_shell_thickness; ConfigOptionBool enforce_full_fill_volume; ConfigOptionFloatOrPercent external_infill_margin; @@ -620,6 +622,8 @@ protected: OPT_PTR(bottom_fill_pattern); OPT_PTR(bridged_infill_margin); OPT_PTR(bridge_speed); + OPT_PTR(curve_smoothing_precision); + OPT_PTR(curve_smoothing_angle); OPT_PTR(ensure_vertical_shell_thickness); OPT_PTR(enforce_full_fill_volume); OPT_PTR(external_infill_margin); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 6bcb690d7..1302002dc 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1882,7 +1882,8 @@ end: LayerRegion *layerm = layer->m_regions.front(); layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stPosInternal | stDensSparse); } - _offsetHoles(hole_delta, layer->regions().front()); + _offset_holes(hole_delta, layer->regions().front()); + _smooth_curves(layer->regions().front()); } else if (scale || clip || hole_delta != 0.f) { // Multiple regions, growing, shrinking or just clipping one region by the other. // When clipping the regions, priority is given to the first regions. @@ -1899,7 +1900,8 @@ end: // Collect the already processed regions to trim the to be processed regions. polygons_append(processed, slices); layerm->slices.set(std::move(slices), stPosInternal | stDensSparse); - _offsetHoles(hole_delta, layerm); + _offset_holes(hole_delta, layerm); + _smooth_curves(layerm); } } // Merge all regions' slices to get islands, chain them by a shortest path. @@ -1910,9 +1912,8 @@ end: BOOST_LOG_TRIVIAL(debug) << "Slicing objects - make_slices in parallel - end"; } -void PrintObject::_offsetHoles(float hole_delta, LayerRegion *layerm) { +void PrintObject::_offset_holes(float hole_delta, LayerRegion *layerm) { if (hole_delta != 0.f) { - std::cout << "offset_hole z="<layer()->id()<<"\n"; ExPolygons polys = to_expolygons(std::move(layerm->slices.surfaces)); ExPolygons new_polys; for (const ExPolygon &ex_poly : polys) { @@ -1950,6 +1951,96 @@ void PrintObject::_offsetHoles(float hole_delta, LayerRegion *layerm) { } } +/// max angle: you ahve to be lwer than that to divide it. PI => all accepted +/// min angle: don't smooth sharp angles! 0 => all accepted +Polygon _smooth_curve(Polygon &p, double max_angle, double min_angle, coord_t max_dist){ + if (p.size() < 4) return p; + Polygon pout; + //duplicate points to simplify the loop + p.points.insert(p.points.end(), p.points.begin(), p.points.begin() + 3); + for (size_t idx = 1; idx PI) angle1 = 2 * PI - angle1; + double angle2 = p[idx + 1].ccw_angle(p.points[idx], p.points[idx + 2]); + if (angle2 > PI) angle2 = 2 * PI - angle2; + if (angle1 < min_angle && angle2 < min_angle) continue; + if (angle1 > max_angle && angle2 > max_angle) continue; + // add points, but how many? + coordf_t dist = p[idx].distance_to(p[idx + 1]); + int nb_add = dist / max_dist; + if (max_angle < PI) { + int nb_add_per_angle = std::max((PI - angle1) / (PI - max_angle), (PI - angle2) / (PI - max_angle)); + nb_add = std::min(nb_add, nb_add_per_angle); + } + if (nb_add == 0) continue; + + //création des points de controles + Vec2d vec_ab = (p[idx] - p[idx - 1]).cast(); + Vec2d vec_bc = (p[idx + 1] - p[idx]).cast(); + Vec2d vec_cb = (p[idx] - p[idx + 1]).cast(); + Vec2d vec_dc = (p[idx + 1] - p[idx + 2]).cast(); + vec_ab.normalize(); + vec_bc.normalize(); + vec_cb.normalize(); + vec_dc.normalize(); + Vec2d vec_b_tang = vec_ab + vec_bc; + vec_b_tang.normalize(); + //should be 0.55 / 1.414 = ~0.39 to create a true circle from a square (90°) + // it's ~0.36 for exagon (120°) + // it's ~0.34 for octogon (135°) + vec_b_tang *= dist * (0.31 + 0.12 * (1-(angle1 / PI))); + Vec2d vec_c_tang = vec_dc + vec_cb; + vec_c_tang.normalize(); + vec_c_tang *= dist * (0.31 + 0.12 * (1 - (angle1 / PI))); + Point bp = p[idx] + ((angle1 < min_angle) ? vec_bc.cast() : vec_b_tang.cast()); + Point cp = p[idx + 1] + ((angle2 < min_angle) ? vec_cb.cast() : vec_c_tang.cast()); + for (int idx_np = 0; idx_np < nb_add; idx_np++){ + const float percent_np = (idx_np + 1) / (float)(nb_add + 1); + const float inv_percent_np = 1 - percent_np; + pout.points.emplace_back(); + Point &new_p = pout.points.back(); + const float coeff0 = inv_percent_np * inv_percent_np * inv_percent_np; + const float coeff1 = percent_np * inv_percent_np * inv_percent_np; + const float coeff2 = percent_np * percent_np * inv_percent_np; + const float coeff3 = percent_np * percent_np * percent_np; + new_p.x() = (p[idx].x() * coeff0) + + (3 * bp.x() * coeff1) + + (3 * cp.x() * coeff2) + + (p[idx + 1].x() * coeff3); + new_p.y() = (p[idx].y() * coeff0) + + (3 * bp.y() * coeff1) + + (3 * cp.y() * coeff2) + + (p[idx + 1].y() * coeff3); + } + + } + return pout; +} + +void PrintObject::_smooth_curves(LayerRegion *layerm) { + + if (layerm->region()->config().curve_smoothing_precision.value > 0.f) { + ExPolygons new_polys; + for (const Surface &srf : layerm->slices.surfaces) { + const ExPolygon &ex_poly = srf.expolygon; + ExPolygon new_ex_poly(ex_poly); + new_ex_poly.contour = _smooth_curve(new_ex_poly.contour, PI, + layerm->region()->config().curve_smoothing_angle.value*PI / 180.0, + scale_(layerm->region()->config().curve_smoothing_precision.value)); + for (Polygon &phole : new_ex_poly.holes){ + phole.reverse(); // make_counter_clockwise(); + phole = _smooth_curve(phole, PI, + layerm->region()->config().curve_smoothing_angle.value*PI / 180.0, + scale_(layerm->region()->config().curve_smoothing_precision.value)); + phole.reverse(); // make_clockwise(); + } + new_polys.push_back(new_ex_poly); + } + layerm->slices.set(std::move(new_polys), stPosInternal | stDensSparse); + } +} + std::vector PrintObject::_slice_region(size_t region_id, const std::vector &z, bool modifier) { std::vector volumes; diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index ffd15cd98..d72b74715 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -403,6 +403,8 @@ const std::vector& Preset::print_options() , "thin_walls_min_width" , "thin_walls_overlap" , "model_precision" + , "curve_smoothing_precision" + , "curve_smoothing_angle" }; return s_opts; } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index b9a958d53..d45251710 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -945,10 +945,10 @@ void Tab::update_frequently_changed_parameters() void TabPrint::build() { - m_presets = &m_preset_bundle->prints; + m_presets = &m_preset_bundle->prints; + Line line{ "", "" }; load_initial_data(); - - auto page = add_options_page(_(L("Layers and perimeters")), "layers.png"); + auto page = add_options_page(_(L("Layers and perimeters")), "layers.png"); auto optgroup = page->new_optgroup(_(L("Layer height"))); optgroup->append_single_option_line("layer_height"); optgroup->append_single_option_line("first_layer_height"); @@ -958,8 +958,8 @@ void TabPrint::build() optgroup->append_single_option_line("perimeters"); optgroup->append_single_option_line("spiral_vase"); - Line line { "", "" }; - line.full_width = 1; + line = { "", "" }; + line.full_width = 1; line.widget = [this](wxWindow* parent) { return description_line_widget(parent, &m_recommended_thin_wall_thickness_description_line); }; @@ -1147,6 +1147,26 @@ void TabPrint::build() optgroup = page->new_optgroup(_(L("Advanced"))); optgroup->append_single_option_line("interface_shells"); + + page = add_options_page(_(L("Slicing")), "layers.png"); + + optgroup = page->new_optgroup(_(L("Filtering"))); + optgroup->append_single_option_line("slice_closing_radius"); + optgroup->append_single_option_line("resolution"); + optgroup->append_single_option_line("model_precision"); + + optgroup = page->new_optgroup(_(L("Modifying"))); + line = { _(L("Curve smoothing")), "" }; + line.append_option(optgroup->get_option("curve_smoothing_precision")); + line.append_option(optgroup->get_option("curve_smoothing_angle")); + optgroup->append_line(line); + line = { _(L("XY compensation")), "" }; + line.append_option(optgroup->get_option("xy_size_compensation")); + line.append_option(optgroup->get_option("elefant_foot_compensation")); + line.append_option(optgroup->get_option("hole_size_compensation")); + optgroup->append_line(line); + + page = add_options_page(_(L("Advanced")), "wrench.png"); optgroup = page->new_optgroup(_(L("Extrusion width"))); optgroup->append_single_option_line("extrusion_width"); @@ -1165,21 +1185,10 @@ void TabPrint::build() line = { _(L("Bridge flow ratio")), "" }; line.append_option(optgroup->get_option("bridge_flow_ratio")); line.append_option(optgroup->get_option("over_bridge_flow_ratio")); - optgroup->append_line(line); - - optgroup = page->new_optgroup(_(L("Slicing"))); - optgroup->append_single_option_line("slice_closing_radius"); - optgroup->append_single_option_line("resolution"); - line = { _(L("XY compensation")), "" }; - line.append_option(optgroup->get_option("xy_size_compensation")); - line.append_option(optgroup->get_option("elefant_foot_compensation")); - line.append_option(optgroup->get_option("hole_size_compensation")); optgroup->append_line(line); optgroup = page->new_optgroup(_(L("Other"))); optgroup->append_single_option_line("clip_multipart_objects"); - optgroup->append_single_option_line("resolution"); - optgroup->append_single_option_line("model_precision"); page = add_options_page(_(L("Output options")), "page_white_go.png"); optgroup = page->new_optgroup(_(L("Sequential printing")));