mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-15 23:05:53 +08:00
thin walls: merge path into external perimeter loop when possible.
This commit is contained in:
parent
1b91979567
commit
a60631b7aa
@ -34,6 +34,7 @@ group:Quality
|
|||||||
setting:thin_walls
|
setting:thin_walls
|
||||||
setting:width$5:thin_walls_min_width
|
setting:width$5:thin_walls_min_width
|
||||||
setting:width$5:thin_walls_overlap
|
setting:width$5:thin_walls_overlap
|
||||||
|
setting:thin_walls_merge
|
||||||
end_line
|
end_line
|
||||||
group:Overhangs
|
group:Overhangs
|
||||||
line:On perimeters
|
line:On perimeters
|
||||||
|
@ -1901,10 +1901,13 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
|
|||||||
if (paths.front().first_point().coincides_with(paths.back().last_point())) {
|
if (paths.front().first_point().coincides_with(paths.back().last_point())) {
|
||||||
coll.append(ExtrusionLoop(paths));
|
coll.append(ExtrusionLoop(paths));
|
||||||
} else {
|
} else {
|
||||||
//not a loop : avoid to "sort" it.
|
if (role == erThinWall){
|
||||||
ExtrusionEntityCollection unsortable_coll(paths);
|
//thin walls : avoid to cut them, please.
|
||||||
unsortable_coll.no_sort = true;
|
ExtrusionEntityCollection unsortable_coll(paths);
|
||||||
coll.append(unsortable_coll);
|
unsortable_coll.no_sort = true;
|
||||||
|
coll.append(unsortable_coll);
|
||||||
|
}else //gap fill : cut them as much as you want
|
||||||
|
coll.append(paths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -717,7 +717,12 @@ void PerimeterGenerator::process()
|
|||||||
thin_walls.clear();
|
thin_walls.clear();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entities = this->_traverse_loops(contours.front(), thin_walls);
|
if (this->object_config->thin_walls_merge) {
|
||||||
|
entities = this->_traverse_loops(contours.front(), ThickPolylines{});
|
||||||
|
_merge_thin_walls(entities, thin_walls);
|
||||||
|
} else {
|
||||||
|
entities = this->_traverse_loops(contours.front(), thin_walls);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -917,7 +922,6 @@ void PerimeterGenerator::process()
|
|||||||
} // for each island
|
} // for each island
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
|
ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
|
||||||
const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const
|
const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const
|
||||||
{
|
{
|
||||||
@ -1056,6 +1060,170 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
|
|||||||
return coll_out;
|
return coll_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions, ThickPolylines &thin_walls) const {
|
||||||
|
class ChangeFlow : public ExtrusionVisitor {
|
||||||
|
public:
|
||||||
|
float percent_extrusion;
|
||||||
|
std::vector<ExtrusionPath> paths;
|
||||||
|
virtual void use(ExtrusionPath &path) override {
|
||||||
|
path.mm3_per_mm *= percent_extrusion;
|
||||||
|
path.width *= percent_extrusion;
|
||||||
|
paths.emplace_back(std::move(path));
|
||||||
|
}
|
||||||
|
virtual void use(ExtrusionPath3D &path3D) override { /*shouldn't happen*/ }
|
||||||
|
virtual void use(ExtrusionMultiPath &multipath) override { /*shouldn't happen*/ }
|
||||||
|
virtual void use(ExtrusionMultiPath3D &multipath) { /*shouldn't happen*/ }
|
||||||
|
virtual void use(ExtrusionLoop &loop) override {
|
||||||
|
for (ExtrusionPath &path : loop.paths)
|
||||||
|
this->use(path);
|
||||||
|
}
|
||||||
|
virtual void use(ExtrusionEntityCollection &collection) override {
|
||||||
|
for (ExtrusionEntity *entity : collection.entities)
|
||||||
|
entity->visit(*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct BestPoint {
|
||||||
|
//Point p;
|
||||||
|
ExtrusionPath *path;
|
||||||
|
size_t idx_path;
|
||||||
|
ExtrusionLoop *loop;
|
||||||
|
size_t idx_line;
|
||||||
|
Line line;
|
||||||
|
double dist;
|
||||||
|
bool from_start;
|
||||||
|
};
|
||||||
|
//use a visitor to found the best point.
|
||||||
|
class SearchBestPoint : public ExtrusionVisitor {
|
||||||
|
public:
|
||||||
|
ThickPolyline* thin_wall;
|
||||||
|
BestPoint search_result;
|
||||||
|
size_t idx_path;
|
||||||
|
ExtrusionLoop *current_loop = nullptr;
|
||||||
|
virtual void use(ExtrusionPath &path) override {
|
||||||
|
//don't consider other thin walls.
|
||||||
|
if (path.role() == erThinWall) return;
|
||||||
|
//for each segment
|
||||||
|
Lines lines = path.polyline.lines();
|
||||||
|
for (size_t idx_line = 0; idx_line < lines.size(); idx_line++) {
|
||||||
|
//look for nearest point
|
||||||
|
double dist = lines[idx_line].distance_to_squared(thin_wall->points.front());
|
||||||
|
if (dist < search_result.dist) {
|
||||||
|
search_result.path = &path;
|
||||||
|
search_result.idx_path = idx_path;
|
||||||
|
search_result.idx_line = idx_line;
|
||||||
|
search_result.line = lines[idx_line];
|
||||||
|
search_result.dist = dist;
|
||||||
|
search_result.from_start = true;
|
||||||
|
search_result.loop = current_loop;
|
||||||
|
}
|
||||||
|
dist = lines[idx_line].distance_to_squared(thin_wall->points.back());
|
||||||
|
if (dist < search_result.dist) {
|
||||||
|
search_result.path = &path;
|
||||||
|
search_result.idx_path = idx_path;
|
||||||
|
search_result.idx_line = idx_line;
|
||||||
|
search_result.line = lines[idx_line];
|
||||||
|
search_result.dist = dist;
|
||||||
|
search_result.from_start = false;
|
||||||
|
search_result.loop = current_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void use(ExtrusionPath3D &path3D) override { /*shouldn't happen*/ }
|
||||||
|
virtual void use(ExtrusionMultiPath &multipath) override { /*shouldn't happen*/ }
|
||||||
|
virtual void use(ExtrusionMultiPath3D &multipath) { /*shouldn't happen*/ }
|
||||||
|
virtual void use(ExtrusionLoop &loop) override {
|
||||||
|
ExtrusionLoop * last_loop = current_loop;
|
||||||
|
current_loop = &loop;
|
||||||
|
//for each extrusion path
|
||||||
|
idx_path = 0;
|
||||||
|
for (ExtrusionPath &path : loop.paths) {
|
||||||
|
this->use(path);
|
||||||
|
idx_path++;
|
||||||
|
}
|
||||||
|
current_loop = last_loop;
|
||||||
|
}
|
||||||
|
virtual void use(ExtrusionEntityCollection &collection) override {
|
||||||
|
collection.no_sort = false;
|
||||||
|
//for each loop? (or other collections)
|
||||||
|
for (ExtrusionEntity *entity : collection.entities)
|
||||||
|
entity->visit(*this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//max dist to branch: ~half external periemeter width
|
||||||
|
coord_t max_width = this->ext_perimeter_flow.scaled_width();
|
||||||
|
SearchBestPoint searcher;
|
||||||
|
ThickPolylines not_added;
|
||||||
|
//search the best extusion/point to branch into
|
||||||
|
//for each thin wall
|
||||||
|
int idx = 0;
|
||||||
|
for (ThickPolyline &tw : thin_walls) {
|
||||||
|
searcher.thin_wall = &tw;
|
||||||
|
searcher.search_result.dist = max_width;
|
||||||
|
searcher.search_result.dist *= searcher.search_result.dist;
|
||||||
|
searcher.search_result.path = nullptr;
|
||||||
|
searcher.use(extrusions);
|
||||||
|
idx++;
|
||||||
|
//now insert thin wall if it has a point
|
||||||
|
//it found a segment
|
||||||
|
if (searcher.search_result.path != nullptr) {
|
||||||
|
if (!searcher.search_result.from_start)
|
||||||
|
tw.reverse();
|
||||||
|
//get the point
|
||||||
|
Point point = tw.points.front().projection_onto(searcher.search_result.line);
|
||||||
|
//we have to create 3 paths: 1: thinwall extusion, 2: thinwall return, 3: end of the path
|
||||||
|
//create new path : end of the path
|
||||||
|
Polyline poly_after;
|
||||||
|
poly_after.points.push_back(point);
|
||||||
|
poly_after.points.insert(poly_after.points.end(),
|
||||||
|
searcher.search_result.path->polyline.points.begin() + searcher.search_result.idx_line + 1,
|
||||||
|
searcher.search_result.path->polyline.points.end());
|
||||||
|
searcher.search_result.path->polyline.points.erase(
|
||||||
|
searcher.search_result.path->polyline.points.begin() + searcher.search_result.idx_line + 1,
|
||||||
|
searcher.search_result.path->polyline.points.end());
|
||||||
|
searcher.search_result.loop->paths[searcher.search_result.idx_path].polyline.points.push_back(point);
|
||||||
|
searcher.search_result.loop->paths.insert(searcher.search_result.loop->paths.begin() + 1 + searcher.search_result.idx_path,
|
||||||
|
ExtrusionPath(poly_after, *searcher.search_result.path));
|
||||||
|
//create thin wall path exttrusion
|
||||||
|
ExtrusionEntityCollection tws = thin_variable_width({ tw }, erThinWall, this->ext_perimeter_flow);
|
||||||
|
ChangeFlow change_flow;
|
||||||
|
if (tws.entities.size() == 1 && tws.entities[0]->is_loop()) {
|
||||||
|
//loop, just add it
|
||||||
|
change_flow.percent_extrusion = 1;
|
||||||
|
change_flow.use(tws);
|
||||||
|
//add move back
|
||||||
|
|
||||||
|
searcher.search_result.loop->paths.insert(searcher.search_result.loop->paths.begin() + 1 + searcher.search_result.idx_path,
|
||||||
|
change_flow.paths.begin(), change_flow.paths.end());
|
||||||
|
//add move to
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//first add the return path
|
||||||
|
ExtrusionEntityCollection tws_second = tws;
|
||||||
|
tws_second.reverse();
|
||||||
|
change_flow.percent_extrusion = 0.1;
|
||||||
|
change_flow.use(tws_second);
|
||||||
|
for (ExtrusionPath &path : change_flow.paths)
|
||||||
|
path.reverse();
|
||||||
|
//std::reverse(change_flow.paths.begin(), change_flow.paths.end());
|
||||||
|
searcher.search_result.loop->paths.insert(searcher.search_result.loop->paths.begin() + 1 + searcher.search_result.idx_path,
|
||||||
|
change_flow.paths.begin(), change_flow.paths.end());
|
||||||
|
//add the real extrusion path
|
||||||
|
change_flow.percent_extrusion = 0.9;
|
||||||
|
change_flow.paths = std::vector<ExtrusionPath>();
|
||||||
|
change_flow.use(tws);
|
||||||
|
searcher.search_result.loop->paths.insert(searcher.search_result.loop->paths.begin() + 1 + searcher.search_result.idx_path,
|
||||||
|
change_flow.paths.begin(), change_flow.paths.end());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
not_added.push_back(tw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//now add thinwalls that have no anchor (make them reversable)
|
||||||
|
ExtrusionEntityCollection tws = thin_variable_width(not_added, erThinWall, this->ext_perimeter_flow);
|
||||||
|
extrusions.append(tws.entities);
|
||||||
|
}
|
||||||
|
|
||||||
PerimeterIntersectionPoint
|
PerimeterIntersectionPoint
|
||||||
PerimeterGenerator::_get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) const {
|
PerimeterGenerator::_get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) const {
|
||||||
//find best points of intersections
|
//find best points of intersections
|
||||||
|
@ -98,9 +98,15 @@ private:
|
|||||||
double _mm3_per_mm_overhang;
|
double _mm3_per_mm_overhang;
|
||||||
Polygons _lower_slices_p;
|
Polygons _lower_slices_p;
|
||||||
|
|
||||||
|
// transform loops into ExtrusionEntityCollection, adding also thin walls into it.
|
||||||
ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const;
|
ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const;
|
||||||
|
// try to merge thin walls to a current periemter exrusion or just add it to the end of the list.
|
||||||
|
void _merge_thin_walls(ExtrusionEntityCollection &extrusions, ThickPolylines &thin_walls) const;
|
||||||
|
// like _traverse_loops but with merging all periemter into one continuous loop
|
||||||
ExtrusionLoop _traverse_and_join_loops(const PerimeterGeneratorLoop &loop, const PerimeterGeneratorLoops &childs, const Point entryPoint) const;
|
ExtrusionLoop _traverse_and_join_loops(const PerimeterGeneratorLoop &loop, const PerimeterGeneratorLoops &childs, const Point entryPoint) const;
|
||||||
|
// sub-function of _traverse_and_join_loops, transform a single loop as a cut extrusion to be merged with an other one.
|
||||||
ExtrusionLoop _extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, const Point entryPoint, const Line &direction = Line(Point(0,0),Point(0,0))) const;
|
ExtrusionLoop _extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, const Point entryPoint, const Line &direction = Line(Point(0,0),Point(0,0))) const;
|
||||||
|
// sub-function of _traverse_and_join_loops, find the good splot to cut a loop to be able to join it with an other one
|
||||||
PerimeterIntersectionPoint _get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) const;
|
PerimeterIntersectionPoint _get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3174,6 +3174,15 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->set_default_value(new ConfigOptionFloatOrPercent(50, true));
|
def->set_default_value(new ConfigOptionFloatOrPercent(50, true));
|
||||||
|
|
||||||
|
def = this->add("thin_walls_merge", coBool);
|
||||||
|
def->label = L("merging with perimeters");
|
||||||
|
def->full_label = L("Thin wall merge");
|
||||||
|
def->category = OptionCategory::perimeter;
|
||||||
|
def->tooltip = L("Allow the external periemter to merge the thin wals int he path. !!! IF you disable this setting, please explain me why (via help->report issue)"
|
||||||
|
" because I'm going to DELETE this setting next release, as i don't see why someone may want to disable it.");
|
||||||
|
def->mode = comExpert;
|
||||||
|
def->set_default_value(new ConfigOptionBool(true));
|
||||||
|
|
||||||
def = this->add("thin_walls_speed", coFloat);
|
def = this->add("thin_walls_speed", coFloat);
|
||||||
def->label = L("Thin walls");
|
def->label = L("Thin walls");
|
||||||
def->full_label = L("Thin walls speed");
|
def->full_label = L("Thin walls speed");
|
||||||
|
@ -541,6 +541,7 @@ public:
|
|||||||
ConfigOptionInt support_material_threshold;
|
ConfigOptionInt support_material_threshold;
|
||||||
ConfigOptionBool support_material_with_sheath;
|
ConfigOptionBool support_material_with_sheath;
|
||||||
ConfigOptionFloatOrPercent support_material_xy_spacing;
|
ConfigOptionFloatOrPercent support_material_xy_spacing;
|
||||||
|
ConfigOptionBool thin_walls_merge;
|
||||||
ConfigOptionFloat xy_size_compensation;
|
ConfigOptionFloat xy_size_compensation;
|
||||||
ConfigOptionFloat xy_inner_size_compensation;
|
ConfigOptionFloat xy_inner_size_compensation;
|
||||||
ConfigOptionBool wipe_into_objects;
|
ConfigOptionBool wipe_into_objects;
|
||||||
@ -599,6 +600,7 @@ protected:
|
|||||||
OPT_PTR(support_material_xy_spacing);
|
OPT_PTR(support_material_xy_spacing);
|
||||||
OPT_PTR(support_material_threshold);
|
OPT_PTR(support_material_threshold);
|
||||||
OPT_PTR(support_material_with_sheath);
|
OPT_PTR(support_material_with_sheath);
|
||||||
|
OPT_PTR(thin_walls_merge);
|
||||||
OPT_PTR(xy_size_compensation);
|
OPT_PTR(xy_size_compensation);
|
||||||
OPT_PTR(xy_inner_size_compensation);
|
OPT_PTR(xy_inner_size_compensation);
|
||||||
OPT_PTR(wipe_into_objects);
|
OPT_PTR(wipe_into_objects);
|
||||||
|
@ -542,6 +542,7 @@ const std::vector<std::string>& Preset::print_options()
|
|||||||
"milling_post_process",
|
"milling_post_process",
|
||||||
"milling_extra_size",
|
"milling_extra_size",
|
||||||
"milling_speed",
|
"milling_speed",
|
||||||
|
"thin_walls_merge",
|
||||||
};
|
};
|
||||||
return s_opts;
|
return s_opts;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user