mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 05:45:52 +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:width$5:thin_walls_min_width
|
||||
setting:width$5:thin_walls_overlap
|
||||
setting:thin_walls_merge
|
||||
end_line
|
||||
group:Overhangs
|
||||
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())) {
|
||||
coll.append(ExtrusionLoop(paths));
|
||||
} else {
|
||||
//not a loop : avoid to "sort" it.
|
||||
ExtrusionEntityCollection unsortable_coll(paths);
|
||||
unsortable_coll.no_sort = true;
|
||||
coll.append(unsortable_coll);
|
||||
if (role == erThinWall){
|
||||
//thin walls : avoid to cut them, please.
|
||||
ExtrusionEntityCollection unsortable_coll(paths);
|
||||
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();
|
||||
}
|
||||
} 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
|
||||
}
|
||||
|
||||
|
||||
ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
|
||||
const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const
|
||||
{
|
||||
@ -1056,6 +1060,170 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
|
||||
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
|
||||
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
|
||||
|
@ -98,9 +98,15 @@ private:
|
||||
double _mm3_per_mm_overhang;
|
||||
Polygons _lower_slices_p;
|
||||
|
||||
// transform loops into ExtrusionEntityCollection, adding also thin walls into it.
|
||||
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;
|
||||
// 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;
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
@ -3174,6 +3174,15 @@ void PrintConfigDef::init_fff_params()
|
||||
def->min = 0;
|
||||
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->label = L("Thin walls");
|
||||
def->full_label = L("Thin walls speed");
|
||||
|
@ -541,6 +541,7 @@ public:
|
||||
ConfigOptionInt support_material_threshold;
|
||||
ConfigOptionBool support_material_with_sheath;
|
||||
ConfigOptionFloatOrPercent support_material_xy_spacing;
|
||||
ConfigOptionBool thin_walls_merge;
|
||||
ConfigOptionFloat xy_size_compensation;
|
||||
ConfigOptionFloat xy_inner_size_compensation;
|
||||
ConfigOptionBool wipe_into_objects;
|
||||
@ -599,6 +600,7 @@ protected:
|
||||
OPT_PTR(support_material_xy_spacing);
|
||||
OPT_PTR(support_material_threshold);
|
||||
OPT_PTR(support_material_with_sheath);
|
||||
OPT_PTR(thin_walls_merge);
|
||||
OPT_PTR(xy_size_compensation);
|
||||
OPT_PTR(xy_inner_size_compensation);
|
||||
OPT_PTR(wipe_into_objects);
|
||||
|
@ -542,6 +542,7 @@ const std::vector<std::string>& Preset::print_options()
|
||||
"milling_post_process",
|
||||
"milling_extra_size",
|
||||
"milling_speed",
|
||||
"thin_walls_merge",
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user