thin walls: merge path into external perimeter loop when possible.

This commit is contained in:
supermerill 2020-06-19 15:30:56 +02:00
parent 1b91979567
commit a60631b7aa
7 changed files with 196 additions and 6 deletions

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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;
};

View File

@ -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");

View File

@ -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);

View File

@ -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;
}