Fix for clipper fix 37838be

It can create 0-length segments. These have to be pruned.
supermerill/SuperSlicer#1641
supermerill/SuperSlicer#1781
This commit is contained in:
supermerill 2021-11-02 20:06:17 +01:00
parent 1822af7854
commit 8cc345ad27
2 changed files with 33 additions and 19 deletions

View File

@ -598,16 +598,18 @@ ClipperLib::PolyTree _clipper_do_pl(const ClipperLib::ClipType clipType, const P
// read input // read input
ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject); ClipperLib::Paths input_subject = Slic3rMultiPoints_to_ClipperPaths(subject);
ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip); ClipperLib::Paths input_clip = Slic3rMultiPoints_to_ClipperPaths(clip);
//scale to have some more precision to do some Y-bugfix
scaleClipperPolygons(input_subject);
scaleClipperPolygons(input_clip);
//perform y safing : if a line is on the same Y, clipper may not pick the good point. //perform y safing : if a line is on the same Y, clipper may not pick the good point.
std::set<coord_t> bad_y; //note: if not enough, next time, add some of the X coordinate (modulo it so it's contained in the scaling part)
for (ClipperLib::Paths* input : {&input_subject, &input_clip} ) for (ClipperLib::Paths* input : { &input_subject, &input_clip })
for (ClipperLib::Path& path : *input) { for (ClipperLib::Path& path : *input) {
coord_t lasty = 0; coord_t lasty = 0;
for (ClipperLib::IntPoint& pt : path) { for (ClipperLib::IntPoint& pt : path) {
if (lasty == pt.Y) { if (lasty == pt.Y) {
pt.Y+=5; //min is 3 on a certain exemple. Using 5 to have some security pt.Y += 50;// well below CLIPPER_OFFSET_POWER_OF_2
bad_y.insert(pt.Y);
} }
lasty = pt.Y; lasty = pt.Y;
} }
@ -629,19 +631,31 @@ ClipperLib::PolyTree _clipper_do_pl(const ClipperLib::ClipType clipType, const P
clipper.Execute(clipType, retval, fillType, fillType); clipper.Execute(clipType, retval, fillType, fillType);
//restore good y //restore good y
if (!bad_y.empty()) { std::vector<ClipperLib::PolyNode*> to_check;
std::vector<ClipperLib::PolyNode*> to_check; to_check.push_back(&retval);
to_check.push_back(&retval); while (!to_check.empty()) {
while (!to_check.empty()) { ClipperLib::PolyNode* node = to_check.back();
ClipperLib::PolyNode* node = to_check.back(); to_check.pop_back();
to_check.pop_back(); for (ClipperLib::IntPoint& pit : node->Contour) {
for (ClipperLib::IntPoint& pt : node->Contour) { pit.X += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
if (bad_y.find(pt.Y) != bad_y.end()) { pit.Y += CLIPPER_OFFSET_SCALE_ROUNDING_DELTA;
pt.Y-=5; pit.X >>= CLIPPER_OFFSET_POWER_OF_2;
} pit.Y >>= CLIPPER_OFFSET_POWER_OF_2;
}
to_check.insert(to_check.end(), node->Childs.begin(), node->Childs.end());
} }
//note: moving in Y may create 0-length segment, so it needs an extra post-processing step to remove these duplicate points.
for (size_t idx = 1; idx < node->Contour.size(); ++idx) {
ClipperLib::IntPoint& pit = node->Contour[idx];
ClipperLib::IntPoint& previous = node->Contour[idx - 1];
// unscaling remove too small differences. The equality is enough.
if (pit.X == previous.X && pit.Y == previous.Y) {
node->Contour.erase(node->Contour.begin() + idx);
--idx;
}
}
//be sure you don't save 1-point paths
if (node->Contour.size() == 1)
node->Contour.clear();
to_check.insert(to_check.end(), node->Childs.begin(), node->Childs.end());
} }
return retval; return retval;

View File

@ -135,12 +135,12 @@ void PerimeterGenerator::process()
} }
} }
if (overhangs_width_speed > 0) { if (overhangs_width_speed > 0 && this->config->overhangs_width_speed.value < this->config->overhangs_width.value) {
this->_lower_slices_bridge_speed_small = offset((simplified.empty() ? *this->lower_slices : simplified), (coordf_t)overhangs_width_speed_90 - (coordf_t)(ext_perimeter_width / 2)); this->_lower_slices_bridge_speed_small = offset((simplified.empty() ? *this->lower_slices : simplified), (coordf_t)overhangs_width_speed_90 - (coordf_t)(ext_perimeter_width / 2));
this->_lower_slices_bridge_speed_big = offset((simplified.empty() ? *this->lower_slices : simplified), (coordf_t)overhangs_width_speed_110 - (coordf_t)(ext_perimeter_width / 2)); this->_lower_slices_bridge_speed_big = offset((simplified.empty() ? *this->lower_slices : simplified), (coordf_t)overhangs_width_speed_110 - (coordf_t)(ext_perimeter_width / 2));
} }
if (overhangs_width_flow > 0) { if (overhangs_width_flow > 0) {
if (overhangs_width_speed_110 == overhangs_width_flow_90) if (overhangs_width_speed_110 == overhangs_width_flow_90 && this->config->overhangs_width_speed.value < this->config->overhangs_width.value)
this->_lower_slices_bridge_flow_small = this->_lower_slices_bridge_speed_big; this->_lower_slices_bridge_flow_small = this->_lower_slices_bridge_speed_big;
else else
this->_lower_slices_bridge_flow_small = offset((simplified.empty() ? *this->lower_slices : simplified), (coordf_t)overhangs_width_flow_90 - (coordf_t)(ext_perimeter_width / 2)); this->_lower_slices_bridge_flow_small = offset((simplified.empty() ? *this->lower_slices : simplified), (coordf_t)overhangs_width_flow_90 - (coordf_t)(ext_perimeter_width / 2));
@ -1201,7 +1201,7 @@ ExtrusionPaths PerimeterGenerator::create_overhangs(const Polyline& loop_polygon
Polylines big_flow; Polylines big_flow;
Polylines* previous = &ok_polylines; Polylines* previous = &ok_polylines;
if (this->config->overhangs_width_speed.value > 0) { if (this->config->overhangs_width_speed.value > 0 && this->config->overhangs_width_speed.value < this->config->overhangs_width.value) {
if (!this->_lower_slices_bridge_speed_small.empty()) { if (!this->_lower_slices_bridge_speed_small.empty()) {
small_speed = diff_pl(*previous, this->_lower_slices_bridge_speed_small); small_speed = diff_pl(*previous, this->_lower_slices_bridge_speed_small);
if (!small_speed.empty()) { if (!small_speed.empty()) {