Skip to content

Commit

Permalink
medial axis: now grows the extrusion to nozzle diameter if it's lower…
Browse files Browse the repository at this point in the history
… than that. Add a parameter to define the min width (default to 33% of nozzle diameter).
  • Loading branch information
supermerill committed Jan 3, 2019
1 parent 72d828c commit a48e190
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/libslic3r/Layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ void Layer::make_perimeters()
&& config.overhangs == other_config.overhangs
&& config.serialize("perimeter_extrusion_width").compare(other_config.serialize("perimeter_extrusion_width")) == 0
&& config.thin_walls == other_config.thin_walls
&& config.thin_walls_min_width == other_config.thin_walls_min_width
&& config.external_perimeters_first == other_config.external_perimeters_first
&& config.perimeter_loop == other_config.perimeter_loop) {
layerms.push_back(other_layerm);
Expand Down
30 changes: 25 additions & 5 deletions src/libslic3r/MedialAxis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ MedialAxis::fusion_corners(ThickPolylines &pp)
//FIXME: also pull (a bit less) points that are near to this one.
// if true, pull it a bit, depends on my size, the dot?, and the coeff at my 0-end (~14% for a square, almost 0 for a gentle curve)
coord_t length_pull = polyline.length();
length_pull *= 0.144 * get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, polyline.length() / 2));
length_pull *= 0.144 * get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, (coord_t)(polyline.length() / 2)));

//compute dir
Vec2d pull_direction(polyline.points[1].x() - polyline.points[0].x(), polyline.points[1].y() - polyline.points[0].y());
Expand Down Expand Up @@ -801,11 +801,11 @@ MedialAxis::main_fusion(ThickPolylines& pp)
//test if we don't merge with something too different and without any relevance.
double coeffSizePolyI = 1;
if (polyline.width.back() == 0) {
coeffSizePolyI = 0.1 + 0.9*get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, polyline.length() / 2));
coeffSizePolyI = 0.1 + 0.9*get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, (coord_t)(polyline.length() / 2)));
}
double coeffSizeOtherJ = 1;
if (other.width.back() == 0) {
coeffSizeOtherJ = 0.1 + 0.9*get_coeff_from_angle_countour(other.points.back(), this->expolygon, min(min_width, polyline.length() / 2));
coeffSizeOtherJ = 0.1 + 0.9*get_coeff_from_angle_countour(other.points.back(), this->expolygon, min(min_width, (coord_t)(polyline.length() / 2)));
}
//std::cout << " try2 : " << i << ":" << j << " : "
// << (abs(polyline.length()*coeffSizePolyI - other.length()*coeffSizeOtherJ) > max_width / 2)
Expand Down Expand Up @@ -904,10 +904,10 @@ MedialAxis::main_fusion(ThickPolylines& pp)
//TODO: try if we can achieve a better result if we use a different algo if the angle is <90°
const double coeff_angle_poly = (coeff_angle_cache.find(polyline.points.back()) != coeff_angle_cache.end())
? coeff_angle_cache[polyline.points.back()]
: (get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, polyline.length() / 2)));
: (get_coeff_from_angle_countour(polyline.points.back(), this->expolygon, min(min_width, (coord_t)(polyline.length() / 2))));
const double coeff_angle_candi = (coeff_angle_cache.find(best_candidate->points.back()) != coeff_angle_cache.end())
? coeff_angle_cache[best_candidate->points.back()]
: (get_coeff_from_angle_countour(best_candidate->points.back(), this->expolygon, min(min_width, best_candidate->length() / 2)));
: (get_coeff_from_angle_countour(best_candidate->points.back(), this->expolygon, min(min_width, (coord_t)(best_candidate->length() / 2))));

//this will encourage to follow the curve, a little, because it's shorter near the center
//without that, it tends to go to the outter rim.
Expand Down Expand Up @@ -1488,11 +1488,31 @@ MedialAxis::build(ThickPolylines* polylines_out)
// svg.draw(pp);
// svg.Close();
//}
if (nozzle_diameter != min_width)
grow_to_nozzle_diameter(pp, diff_ex(this->bounds, this->expolygon));

polylines_out->insert(polylines_out->end(), pp.begin(), pp.end());

}


void
MedialAxis::grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchors) {
//ensure the width is not lower than 0.4.
for (ThickPolyline& polyline : pp) {
for (int i = 0; i < polyline.points.size(); ++i) {
bool is_anchored = false;
for (const ExPolygon &poly : anchors) {
if (poly.contains(polyline.points[i])) {
is_anchored = true;
break;
}
}
if (!is_anchored && polyline.width[i]<nozzle_diameter) polyline.width[i] = nozzle_diameter;
}
}
}

ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) {
// this value determines granularity of adaptive width, as G-code does not allow
// variable extrusion within a single move; this value shall only affect the amount
Expand Down
11 changes: 7 additions & 4 deletions src/libslic3r/MedialAxis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ namespace Slic3r {
ExPolygon expolygon;
const ExPolygon& bounds;
const ExPolygon& surface;
const double max_width;
const double min_width;
const double height;
const coord_t max_width;
const coord_t min_width;
const coord_t height;
coord_t nozzle_diameter;
bool stop_at_min_width = true;
MedialAxis(const ExPolygon &_expolygon, const ExPolygon &_bounds, const double _max_width, const double _min_width, const double _height)
MedialAxis(const ExPolygon &_expolygon, const ExPolygon &_bounds, const coord_t _max_width, const coord_t _min_width, const coord_t _height)
: surface(_expolygon), bounds(_bounds), max_width(_max_width), min_width(_min_width), height(_height) {
nozzle_diameter = _min_width;
};
void build(ThickPolylines* polylines_out);
void build(Polylines* polylines);
Expand Down Expand Up @@ -60,6 +62,7 @@ namespace Slic3r {
void remove_too_thin_points(ThickPolylines& pp);
void remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size);
void ensure_not_overextrude(ThickPolylines& pp);
void grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchors);
};

ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow);
Expand Down
7 changes: 4 additions & 3 deletions src/libslic3r/PerimeterGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ void PerimeterGenerator::process()

// the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width
// (actually, something larger than that still may exist due to mitering or other causes)
coord_t min_width = (coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter / 3);
coord_t min_width = (coord_t)scale_(this->config->thin_walls_min_width.get_abs_value(this->ext_perimeter_flow.nozzle_diameter));

ExPolygons no_thin_zone = offset_ex(next_onion, (float)(ext_perimeter_width / 2), jtSquare);
// medial axis requires non-overlapping geometry
Expand Down Expand Up @@ -297,8 +297,9 @@ void PerimeterGenerator::process()
if (thin[0].area() > min_width*(ext_perimeter_width + ext_perimeter_spacing2)) {
bound.remove_point_too_near(SCALED_RESOLUTION);
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop
thin[0].medial_axis(bound, ext_perimeter_width + ext_perimeter_spacing2, min_width,
&thin_walls, this->layer_height);
Slic3r::MedialAxis ma(thin[0], bound, ext_perimeter_width + ext_perimeter_spacing2, min_width, this->layer_height);
ma.nozzle_diameter = (coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter);
ma.build(&thin_walls);
thin_zones_extruded.emplace_back(thin[0]);
}
break;
Expand Down
11 changes: 10 additions & 1 deletion src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2346,14 +2346,23 @@ void PrintConfigDef::init_fff_params()
def->default_value = new ConfigOptionInts { 200 };

def = this->add("thin_walls", coBool);
def->label = L("Detect thin walls");
def->label = L("");
def->category = L("Layers and Perimeters");
def->tooltip = L("Detect single-width walls (parts where two extrusions don't fit and we need "
"to collapse them into a single trace).");
def->cli = "thin-walls!";
def->mode = comAdvanced;
def->default_value = new ConfigOptionBool(true);

def = this->add("thin_walls_min_width", coFloatOrPercent);
def->label = L("min width");
def->category = L("Layers and Perimeters");
def->tooltip = L("Minimum width for the extrusion to be extruded (widths lower than the nozzle diameter will be over-extruded at the nozzle diameter). Can be percent of the nozzle size.");
def->cli = "thin-walls-min-width=s";
def->mode = comExpert;
def->min = 0;
def->default_value = new ConfigOptionFloatOrPercent(33,true);

def = this->add("threads", coInt);
def->label = L("Threads");
def->tooltip = L("Threads are used to parallelize long-running tasks. Optimal threads number "
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ class PrintRegionConfig : public StaticPrintConfig
ConfigOptionFloatOrPercent solid_infill_speed;
// Detect thin walls.
ConfigOptionBool thin_walls;
ConfigOptionFloatOrPercent thin_walls_min_width;
ConfigOptionFloatOrPercent top_infill_extrusion_width;
ConfigOptionInt top_solid_layers;
ConfigOptionFloatOrPercent top_solid_infill_speed;
Expand Down Expand Up @@ -574,6 +575,7 @@ class PrintRegionConfig : public StaticPrintConfig
OPT_PTR(solid_infill_every_layers);
OPT_PTR(solid_infill_speed);
OPT_PTR(thin_walls);
OPT_PTR(thin_walls_min_width);
OPT_PTR(top_infill_extrusion_width);
OPT_PTR(top_solid_infill_speed);
OPT_PTR(top_solid_layers);
Expand Down
1 change: 1 addition & 0 deletions src/libslic3r/PrintObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|| opt_key == "perimeter_extrusion_width"
|| opt_key == "infill_overlap"
|| opt_key == "thin_walls"
|| opt_key == "thin_walls_min_width"
|| opt_key == "external_perimeters_first"
|| opt_key == "perimeter_loop"
|| opt_key == "perimeter_loop_seam"
Expand Down
1 change: 1 addition & 0 deletions src/slic3r/GUI/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ const std::vector<std::string>& Preset::print_options()
, "infill_not_connected"
, "first_layer_infill_speed"
, "label_printed_objects"
, "thin_walls_min_width"
};
return s_opts;
}
Expand Down
8 changes: 6 additions & 2 deletions src/slic3r/GUI/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,10 @@ void TabPrint::build()
optgroup->append_single_option_line("only_one_perimeter_top");
optgroup->append_single_option_line("ensure_vertical_shell_thickness");
optgroup->append_single_option_line("avoid_crossing_perimeters");
optgroup->append_single_option_line("thin_walls");
line = { _(L("Thin walls")), "" };
line.append_option(optgroup->get_option("thin_walls"));
line.append_option(optgroup->get_option("thin_walls_min_width"));
optgroup->append_line(line);
optgroup->append_single_option_line("overhangs");
line = { _(L("Avoid unsupported perimeters")), "" };
line.append_option(optgroup->get_option("no_perimeter_unsupported"));
Expand Down Expand Up @@ -1322,10 +1325,11 @@ void TabPrint::update()

bool have_perimeters = m_config->opt_int("perimeters") > 0;
for (auto el : { "extra_perimeters", "only_one_perimeter_top", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width",
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", "thin_walls_min_width",
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "perimeter_loop", "perimeter_loop_seam" })
get_field(el)->toggle(have_perimeters);

get_field("thin_walls_min_width")->toggle(m_config->opt_bool("thin_walls"));
get_field("perimeter_loop_seam")->toggle(m_config->opt_bool("perimeter_loop"));

bool have_no_perimeter_unsupported = have_perimeters && m_config->opt_bool("no_perimeter_unsupported");
Expand Down

0 comments on commit a48e190

Please sign in to comment.