mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-16 07:25:55 +08:00
medial axis: now grows the extrusion to nozzle diameter if it's lower than that. Add a parameter to define the min width (default to 33% of nozzle diameter).
This commit is contained in:
parent
72d828cf74
commit
a48e190137
@ -110,6 +110,7 @@ void Layer::make_perimeters()
|
|||||||
&& config.overhangs == other_config.overhangs
|
&& config.overhangs == other_config.overhangs
|
||||||
&& config.serialize("perimeter_extrusion_width").compare(other_config.serialize("perimeter_extrusion_width")) == 0
|
&& config.serialize("perimeter_extrusion_width").compare(other_config.serialize("perimeter_extrusion_width")) == 0
|
||||||
&& config.thin_walls == other_config.thin_walls
|
&& 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.external_perimeters_first == other_config.external_perimeters_first
|
||||||
&& config.perimeter_loop == other_config.perimeter_loop) {
|
&& config.perimeter_loop == other_config.perimeter_loop) {
|
||||||
layerms.push_back(other_layerm);
|
layerms.push_back(other_layerm);
|
||||||
|
@ -578,7 +578,7 @@ MedialAxis::fusion_corners(ThickPolylines &pp)
|
|||||||
//FIXME: also pull (a bit less) points that are near to this one.
|
//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)
|
// 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();
|
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
|
//compute dir
|
||||||
Vec2d pull_direction(polyline.points[1].x() - polyline.points[0].x(), polyline.points[1].y() - polyline.points[0].y());
|
Vec2d pull_direction(polyline.points[1].x() - polyline.points[0].x(), polyline.points[1].y() - polyline.points[0].y());
|
||||||
@ -801,11 +801,11 @@ MedialAxis::main_fusion(ThickPolylines& pp)
|
|||||||
//test if we don't merge with something too different and without any relevance.
|
//test if we don't merge with something too different and without any relevance.
|
||||||
double coeffSizePolyI = 1;
|
double coeffSizePolyI = 1;
|
||||||
if (polyline.width.back() == 0) {
|
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;
|
double coeffSizeOtherJ = 1;
|
||||||
if (other.width.back() == 0) {
|
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 << " : "
|
//std::cout << " try2 : " << i << ":" << j << " : "
|
||||||
// << (abs(polyline.length()*coeffSizePolyI - other.length()*coeffSizeOtherJ) > max_width / 2)
|
// << (abs(polyline.length()*coeffSizePolyI - other.length()*coeffSizeOtherJ) > max_width / 2)
|
||||||
@ -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°
|
//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())
|
const double coeff_angle_poly = (coeff_angle_cache.find(polyline.points.back()) != coeff_angle_cache.end())
|
||||||
? coeff_angle_cache[polyline.points.back()]
|
? 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())
|
const double coeff_angle_candi = (coeff_angle_cache.find(best_candidate->points.back()) != coeff_angle_cache.end())
|
||||||
? coeff_angle_cache[best_candidate->points.back()]
|
? 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
|
//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.
|
//without that, it tends to go to the outter rim.
|
||||||
@ -1488,11 +1488,31 @@ MedialAxis::build(ThickPolylines* polylines_out)
|
|||||||
// svg.draw(pp);
|
// svg.draw(pp);
|
||||||
// svg.Close();
|
// 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());
|
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) {
|
ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) {
|
||||||
// this value determines granularity of adaptive width, as G-code does not allow
|
// 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
|
// variable extrusion within a single move; this value shall only affect the amount
|
||||||
|
@ -21,12 +21,14 @@ namespace Slic3r {
|
|||||||
ExPolygon expolygon;
|
ExPolygon expolygon;
|
||||||
const ExPolygon& bounds;
|
const ExPolygon& bounds;
|
||||||
const ExPolygon& surface;
|
const ExPolygon& surface;
|
||||||
const double max_width;
|
const coord_t max_width;
|
||||||
const double min_width;
|
const coord_t min_width;
|
||||||
const double height;
|
const coord_t height;
|
||||||
|
coord_t nozzle_diameter;
|
||||||
bool stop_at_min_width = true;
|
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) {
|
: 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(ThickPolylines* polylines_out);
|
||||||
void build(Polylines* polylines);
|
void build(Polylines* polylines);
|
||||||
@ -60,6 +62,7 @@ namespace Slic3r {
|
|||||||
void remove_too_thin_points(ThickPolylines& pp);
|
void remove_too_thin_points(ThickPolylines& pp);
|
||||||
void remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size);
|
void remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size);
|
||||||
void ensure_not_overextrude(ThickPolylines& pp);
|
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);
|
ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow);
|
||||||
|
@ -265,7 +265,7 @@ void PerimeterGenerator::process()
|
|||||||
|
|
||||||
// the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width
|
// 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)
|
// (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);
|
ExPolygons no_thin_zone = offset_ex(next_onion, (float)(ext_perimeter_width / 2), jtSquare);
|
||||||
// medial axis requires non-overlapping geometry
|
// medial axis requires non-overlapping geometry
|
||||||
@ -297,8 +297,9 @@ void PerimeterGenerator::process()
|
|||||||
if (thin[0].area() > min_width*(ext_perimeter_width + ext_perimeter_spacing2)) {
|
if (thin[0].area() > min_width*(ext_perimeter_width + ext_perimeter_spacing2)) {
|
||||||
bound.remove_point_too_near(SCALED_RESOLUTION);
|
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
|
// 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,
|
Slic3r::MedialAxis ma(thin[0], bound, ext_perimeter_width + ext_perimeter_spacing2, min_width, this->layer_height);
|
||||||
&thin_walls, 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]);
|
thin_zones_extruded.emplace_back(thin[0]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2346,7 +2346,7 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->default_value = new ConfigOptionInts { 200 };
|
def->default_value = new ConfigOptionInts { 200 };
|
||||||
|
|
||||||
def = this->add("thin_walls", coBool);
|
def = this->add("thin_walls", coBool);
|
||||||
def->label = L("Detect thin walls");
|
def->label = L("");
|
||||||
def->category = L("Layers and Perimeters");
|
def->category = L("Layers and Perimeters");
|
||||||
def->tooltip = L("Detect single-width walls (parts where two extrusions don't fit and we need "
|
def->tooltip = L("Detect single-width walls (parts where two extrusions don't fit and we need "
|
||||||
"to collapse them into a single trace).");
|
"to collapse them into a single trace).");
|
||||||
@ -2354,6 +2354,15 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->mode = comAdvanced;
|
def->mode = comAdvanced;
|
||||||
def->default_value = new ConfigOptionBool(true);
|
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 = this->add("threads", coInt);
|
||||||
def->label = L("Threads");
|
def->label = L("Threads");
|
||||||
def->tooltip = L("Threads are used to parallelize long-running tasks. Optimal threads number "
|
def->tooltip = L("Threads are used to parallelize long-running tasks. Optimal threads number "
|
||||||
|
@ -519,6 +519,7 @@ public:
|
|||||||
ConfigOptionFloatOrPercent solid_infill_speed;
|
ConfigOptionFloatOrPercent solid_infill_speed;
|
||||||
// Detect thin walls.
|
// Detect thin walls.
|
||||||
ConfigOptionBool thin_walls;
|
ConfigOptionBool thin_walls;
|
||||||
|
ConfigOptionFloatOrPercent thin_walls_min_width;
|
||||||
ConfigOptionFloatOrPercent top_infill_extrusion_width;
|
ConfigOptionFloatOrPercent top_infill_extrusion_width;
|
||||||
ConfigOptionInt top_solid_layers;
|
ConfigOptionInt top_solid_layers;
|
||||||
ConfigOptionFloatOrPercent top_solid_infill_speed;
|
ConfigOptionFloatOrPercent top_solid_infill_speed;
|
||||||
@ -574,6 +575,7 @@ protected:
|
|||||||
OPT_PTR(solid_infill_every_layers);
|
OPT_PTR(solid_infill_every_layers);
|
||||||
OPT_PTR(solid_infill_speed);
|
OPT_PTR(solid_infill_speed);
|
||||||
OPT_PTR(thin_walls);
|
OPT_PTR(thin_walls);
|
||||||
|
OPT_PTR(thin_walls_min_width);
|
||||||
OPT_PTR(top_infill_extrusion_width);
|
OPT_PTR(top_infill_extrusion_width);
|
||||||
OPT_PTR(top_solid_infill_speed);
|
OPT_PTR(top_solid_infill_speed);
|
||||||
OPT_PTR(top_solid_layers);
|
OPT_PTR(top_solid_layers);
|
||||||
|
@ -462,6 +462,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
|||||||
|| opt_key == "perimeter_extrusion_width"
|
|| opt_key == "perimeter_extrusion_width"
|
||||||
|| opt_key == "infill_overlap"
|
|| opt_key == "infill_overlap"
|
||||||
|| opt_key == "thin_walls"
|
|| opt_key == "thin_walls"
|
||||||
|
|| opt_key == "thin_walls_min_width"
|
||||||
|| opt_key == "external_perimeters_first"
|
|| opt_key == "external_perimeters_first"
|
||||||
|| opt_key == "perimeter_loop"
|
|| opt_key == "perimeter_loop"
|
||||||
|| opt_key == "perimeter_loop_seam"
|
|| opt_key == "perimeter_loop_seam"
|
||||||
|
@ -353,6 +353,7 @@ const std::vector<std::string>& Preset::print_options()
|
|||||||
, "infill_not_connected"
|
, "infill_not_connected"
|
||||||
, "first_layer_infill_speed"
|
, "first_layer_infill_speed"
|
||||||
, "label_printed_objects"
|
, "label_printed_objects"
|
||||||
|
, "thin_walls_min_width"
|
||||||
};
|
};
|
||||||
return s_opts;
|
return s_opts;
|
||||||
}
|
}
|
||||||
|
@ -923,7 +923,10 @@ void TabPrint::build()
|
|||||||
optgroup->append_single_option_line("only_one_perimeter_top");
|
optgroup->append_single_option_line("only_one_perimeter_top");
|
||||||
optgroup->append_single_option_line("ensure_vertical_shell_thickness");
|
optgroup->append_single_option_line("ensure_vertical_shell_thickness");
|
||||||
optgroup->append_single_option_line("avoid_crossing_perimeters");
|
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");
|
optgroup->append_single_option_line("overhangs");
|
||||||
line = { _(L("Avoid unsupported perimeters")), "" };
|
line = { _(L("Avoid unsupported perimeters")), "" };
|
||||||
line.append_option(optgroup->get_option("no_perimeter_unsupported"));
|
line.append_option(optgroup->get_option("no_perimeter_unsupported"));
|
||||||
@ -1322,10 +1325,11 @@ void TabPrint::update()
|
|||||||
|
|
||||||
bool have_perimeters = m_config->opt_int("perimeters") > 0;
|
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",
|
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" })
|
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "perimeter_loop", "perimeter_loop_seam" })
|
||||||
get_field(el)->toggle(have_perimeters);
|
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"));
|
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");
|
bool have_no_perimeter_unsupported = have_perimeters && m_config->opt_bool("no_perimeter_unsupported");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user