Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsupermerill <merill@fr.fr>2019-02-18 13:08:54 +0300
committersupermerill <merill@fr.fr>2019-02-21 21:32:52 +0300
commit591b1162233758d0f63128014f8fa2a013cbe7cf (patch)
tree569fcca98fbe7b485e284b778a730b0fa12b983a
parent91c7a3b3dfc501f0467575b863544974ee9ccdcb (diff)
thin walls:
* bugfix medial axis concatenate_polylines_with_crossing : now connected the good end with the other. * bugfix thin wall (medial axis): use correct temp variables. * fix variable_width: now the algo for width calculation is also used to set where it should create a new path.
-rw-r--r--src/libslic3r/MedialAxis.cpp277
1 files changed, 158 insertions, 119 deletions
diff --git a/src/libslic3r/MedialAxis.cpp b/src/libslic3r/MedialAxis.cpp
index 3ad6bd5e1..eb498e59c 100644
--- a/src/libslic3r/MedialAxis.cpp
+++ b/src/libslic3r/MedialAxis.cpp
@@ -44,7 +44,6 @@ MedialAxis::polyline_from_voronoi(const Lines& voronoi_edges, ThickPolylines* po
}
*/
- typedef const VD::vertex_type vert_t;
typedef const VD::edge_type edge_t;
// collect valid edges (i.e. prune those not belonging to MAT)
@@ -605,7 +604,6 @@ MedialAxis::fusion_corners(ThickPolylines &pp)
}
}
-
void
MedialAxis::extends_line_both_side(ThickPolylines& pp) {
const ExPolygons anchors = offset2_ex(diff_ex(this->bounds, this->expolygon), (float)-SCALED_RESOLUTION, (float)SCALED_RESOLUTION);
@@ -850,39 +848,51 @@ MedialAxis::main_fusion(ThickPolylines& pp)
break;
}
}
+ double dot_poly_branch_test = 0.707;
+ double dot_candidate_branch_test = 0.707;
if (!find_main_branch && biggest_main_branch_length == 0) {
// nothing -> it's impossible!
- dot_poly_branch = 0.707;
- dot_candidate_branch = 0.707;
+ dot_poly_branch_test = 0.707;
+ dot_candidate_branch_test = 0.707;
//std::cout << "no main branch... impossible!!\n";
} else if (!find_main_branch && (
(pp[biggest_main_branch_id].length() < polyline.length() && (polyline.width.back() != 0 || pp[biggest_main_branch_id].width.back() ==0))
|| (pp[biggest_main_branch_id].length() < other.length() && (other.width.back() != 0 || pp[biggest_main_branch_id].width.back() == 0)))) {
//the main branch should have no endpoint or be bigger!
//here, it have an endpoint, and is not the biggest -> bad!
+ //std::cout << "he main branch should have no endpoint or be bigger! here, it have an endpoint, and is not the biggest -> bad!\n";
continue;
} else {
//compute the dot (biggest_main_branch_id)
- dot_poly_branch = -dot(Line(polyline.points[0], polyline.points[1]), Line(pp[biggest_main_branch_id].points[0], pp[biggest_main_branch_id].points[1]));
- dot_candidate_branch = -dot(Line(other.points[0], other.points[1]), Line(pp[biggest_main_branch_id].points[0], pp[biggest_main_branch_id].points[1]));
- if (dot_poly_branch < 0) dot_poly_branch = 0;
- if (dot_candidate_branch < 0) dot_candidate_branch = 0;
+ dot_poly_branch_test = -dot(Line(polyline.points[0], polyline.points[1]), Line(pp[biggest_main_branch_id].points[0], pp[biggest_main_branch_id].points[1]));
+ dot_candidate_branch_test = -dot(Line(other.points[0], other.points[1]), Line(pp[biggest_main_branch_id].points[0], pp[biggest_main_branch_id].points[1]));
+ if (dot_poly_branch_test < 0) dot_poly_branch_test = 0;
+ if (dot_candidate_branch_test < 0) dot_candidate_branch_test = 0;
if (pp[biggest_main_branch_id].width.back()>0)
test_dot += 2 * (float)dot_poly_branch;
}
//test if it's useful to merge or not
//ie, don't merge 'T' but ok for 'Y', merge only lines of not disproportionate different length (ratio max: 4) (or they are both with 0-width end)
- if (dot_poly_branch < 0.1 || dot_candidate_branch < 0.1 ||
+ if (dot_poly_branch_test < 0.1 || dot_candidate_branch_test < 0.1 ||
(
((polyline.length()>other.length() ? polyline.length() / other.length() : other.length() / polyline.length()) > 4)
&& !(polyline.width.back() == 0 && other.width.back()==0)
- ) ){
+ )) {
+ //std::cout << "not useful to merge\n";
continue;
}
if (test_dot > best_dot) {
best_candidate = &other;
best_idx = j;
best_dot = test_dot;
+ dot_poly_branch = dot_poly_branch_test;
+ dot_candidate_branch = dot_candidate_branch_test;
+ //{
+ // std::cout << "going to merge: b1=" << i << ", b2=" << best_idx << ", main=" << biggest_main_branch_id << "\n";
+ // std::cout << "b1=" << polyline.points.front().x() << " : " << polyline.points.front().y() << " => " << polyline.points.back().x() << " : " << polyline.points.back().y() << "\n";
+ // std::cout << "b2=" << other.points.front().x() << " : " << other.points.front().y() << " => " << other.points.back().x() << " : " << other.points.back().y() << "\n";
+ // std::cout << "main=" << pp[biggest_main_branch_id].points.front().x() << " : " << pp[biggest_main_branch_id].points.front().y() << " => " << pp[biggest_main_branch_id].points.back().x() << " : " << pp[biggest_main_branch_id].points.back().y() << "\n";
+ //}
}
}
if (best_candidate != nullptr) {
@@ -1017,7 +1027,7 @@ MedialAxis::main_fusion(ThickPolylines& pp)
pp.erase(pp.begin() + best_idx);
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_2.0_aft_fus_" << id << "_" << idf << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1096,7 +1106,6 @@ void
MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
{
-
// concatenate, but even where multiple thickpolyline join, to create nice long strait polylines
/* If we removed any short polylines we now try to connect consecutive polylines
in order to allow loop detection. Note that this algorithm is greedier than
@@ -1121,21 +1130,24 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
if (j == i) continue;
ThickPolyline& other = pp[j];
if (other.endpoints.first && other.endpoints.second) continue;
-
+ bool me_reverse = false;
+ bool other_reverse = false;
if (polyline.last_point().coincides_with(other.last_point())) {
- other.reverse();
+ other_reverse = true;
} else if (polyline.first_point().coincides_with(other.last_point())) {
- polyline.reverse();
- other.reverse();
+ me_reverse = true;
+ other_reverse = true;
} else if (polyline.first_point().coincides_with(other.first_point())) {
- polyline.reverse();
+ me_reverse = true;
} else if (!polyline.last_point().coincides_with(other.first_point())) {
continue;
}
- Vec2d v_poly(polyline.lines().back().vector().x(), polyline.lines().back().vector().y());
+ Vec2d v_poly(me_reverse ? polyline.lines().front().vector().x() : polyline.lines().back().vector().x(),
+ me_reverse ? polyline.lines().front().vector().y() : polyline.lines().back().vector().y());
v_poly *= (1 / std::sqrt(v_poly.x()*v_poly.x() + v_poly.y()*v_poly.y()));
- Vec2d v_other(other.lines().front().vector().x(), other.lines().front().vector().y());
+ Vec2d v_other(other_reverse ? other.lines().back().vector().x() : other.lines().front().vector().x(),
+ other_reverse ? other.lines().back().vector().y() : other.lines().front().vector().y());
v_other *= (1 / std::sqrt(v_other.x()*v_other.x() + v_other.y()*v_other.y()));
float other_dot = (float)( v_poly.x()*v_other.x() + v_poly.y()*v_other.y() );
if (other_dot > best_dot) {
@@ -1145,8 +1157,18 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
}
}
if (best_candidate != nullptr && best_candidate->size() > 1) {
- //intersections may create ever-ertusion because the included circle can be a bit larger. We have to make it short again.
- if (polyline.width.back() > polyline.width[polyline.width.size() - 2] && polyline.width.back() > best_candidate->width[1]) {
+ if (polyline.last_point().coincides_with(best_candidate->last_point())) {
+ best_candidate->reverse();
+ } else if (polyline.first_point().coincides_with(best_candidate->last_point())) {
+ polyline.reverse();
+ best_candidate->reverse();
+ } else if (polyline.first_point().coincides_with(best_candidate->first_point())) {
+ polyline.reverse();
+ }
+ //intersections may create over-extrusion because the included circle can be a bit larger. We have to make it short again if needed.
+ if (polyline.points.size() > 1 && best_candidate->points.size() > 1
+ && polyline.width.back() > polyline.width[polyline.width.size() - 2]
+ && polyline.width.back() > best_candidate->width[1]) {
polyline.width.back() = std::min(polyline.width[polyline.width.size() - 2], best_candidate->width[1]);
}
polyline.points.insert(polyline.points.end(), best_candidate->points.begin() + 1, best_candidate->points.end());
@@ -1327,12 +1349,83 @@ MedialAxis::simplify_polygon_frontier()
return simplified_poly;
}
+/// Grow the extrusion to at least nozzle_diameter*1.05 (lowest safe extrusion width)
+/// Do not grow points inside the anchor.
+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 * 1.05)
+ polyline.width[i] = nozzle_diameter * 1.05;
+ }
+ }
+}
+
+void
+MedialAxis::taper_ends(ThickPolylines& pp) {
+ // minimum size of the taper: be sure to extrude at least the "round edges" of the extrusion (0-spacing extrusion).
+ const coord_t min_size = std::max(this->nozzle_diameter * 0.1, this->height * (1. - 0.25 * PI));
+ const coordf_t length = std::min(this->anchor_size, (this->nozzle_diameter - min_size) / 2);
+ if (length <= SCALED_RESOLUTION) return;
+ //ensure the width is not lower than 0.4.
+ for (ThickPolyline& polyline : pp) {
+ if (polyline.length() < length * 2.2) continue;
+ if (polyline.endpoints.first) {
+ polyline.width[0] = min_size;
+ coord_t current_dist = min_size;
+ coord_t last_dist = min_size;
+ for (size_t i = 1; i<polyline.width.size(); ++i) {
+ current_dist += (coord_t)polyline.points[i - 1].distance_to(polyline.points[i]);
+ if (current_dist > length) {
+ //create a new point if not near enough
+ if (current_dist > polyline.width[i] + SCALED_RESOLUTION) {
+ coordf_t percent_dist = (polyline.width[i] - polyline.width[i - 1]) / (current_dist - last_dist);
+ polyline.points.insert(polyline.points.begin() + i, polyline.points[i - 1].interpolate(percent_dist, polyline.points[i]));
+ polyline.width.insert(polyline.width.begin() + i, polyline.width[i]);
+ }
+ break;
+ }
+ polyline.width[i] = std::max((coordf_t)min_size, min_size + (polyline.width[i] - min_size) * current_dist / length);
+ last_dist = current_dist;
+ }
+ }
+ if (polyline.endpoints.second) {
+ const size_t back_idx = polyline.width.size() - 1;
+ polyline.width[back_idx] = min_size;
+ coord_t current_dist = min_size;
+ coord_t last_dist = min_size;
+ for (size_t i = 1; i<polyline.width.size(); ++i) {
+ current_dist += (coord_t)polyline.points[back_idx - i + 1].distance_to(polyline.points[back_idx - i]);
+ if (current_dist > length) {
+ //create new point if not near enough
+ if (current_dist > polyline.width[back_idx - i] + SCALED_RESOLUTION) {
+ coordf_t percent_dist = (polyline.width[back_idx - i] - polyline.width[back_idx - i + 1]) / (current_dist - last_dist);
+ polyline.points.insert(polyline.points.begin() + back_idx - i + 1, polyline.points[back_idx - i + 1].interpolate(percent_dist, polyline.points[back_idx - i]));
+ polyline.width.insert(polyline.width.begin() + back_idx - i + 1, polyline.width[back_idx - i]);
+ }
+ break;
+ }
+ polyline.width[back_idx - i] = std::max((coordf_t)min_size, min_size + (polyline.width[back_idx - i] - min_size) * current_dist / length);
+ last_dist = current_dist;
+ }
+ }
+ }
+}
+
void
MedialAxis::build(ThickPolylines* polylines_out) {
this->id++;
- //std::cout << layerid << "\n";
+ //std::cout << this->id << "\n";
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_0_enter_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(this->surface);
@@ -1340,7 +1433,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
//}
this->expolygon = simplify_polygon_frontier();
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_0.5_simplified_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1360,7 +1453,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
//std::cout << "concatThickPolylines\n";
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_1_voronoi_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1378,7 +1471,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
fusion_curve(pp);
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_2_curve_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1395,7 +1488,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
//
main_fusion(pp);
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_3_fusion_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1407,6 +1500,8 @@ MedialAxis::build(ThickPolylines* polylines_out) {
//fusion right-angle corners.
fusion_corners(pp);
+ // Loop through all returned polylines in order to extend their endpoints to the
+ // expolygon boundaries (if done here, it may be cut later if not thick enough)
if (stop_at_min_width) {
extends_line_both_side(pp);
}
@@ -1414,7 +1509,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
//reduce extrusion when it's too thin to be printable
remove_too_thin_extrusion(pp);
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_4_thinok_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1425,7 +1520,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
remove_too_thin_points(pp);
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_5.0_thuinner_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1440,7 +1535,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
extends_line_both_side(pp);
}
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_5_expand_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1450,7 +1545,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
//}
concatenate_polylines_with_crossing(pp);
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_6_concat_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1461,7 +1556,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
remove_too_short_polylines(pp, (coord_t)max_w * 2);
//{
- // stringstream stri;
+ // std::stringstream stri;
// stri << "medial_axis_8_tooshort_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
@@ -1473,8 +1568,8 @@ MedialAxis::build(ThickPolylines* polylines_out) {
//TODO: reduce the flow at the intersection ( + ) points ?
ensure_not_overextrude(pp);
//{
- // stringstream stri;
- // stri << "medial_axis_9_endn_" << id << ".svg";
+ // std::stringstream stri;
+ // stri << "medial_axis_9.1_end_" << id << ".svg";
// SVG svg(stri.str());
// svg.draw(bounds);
// svg.draw(this->expolygon);
@@ -1485,83 +1580,22 @@ MedialAxis::build(ThickPolylines* polylines_out) {
grow_to_nozzle_diameter(pp, diff_ex(this->bounds, this->expolygon));
taper_ends(pp);
}
+ //{
+ // std::stringstream stri;
+ // stri << "medial_axis_9.9_endnwithtaper_" << id << ".svg";
+ // SVG svg(stri.str());
+ // svg.draw(bounds);
+ // svg.draw(this->expolygon);
+ // svg.draw(pp);
+ // svg.Close();
+ //}
polylines_out->insert(polylines_out->end(), pp.begin(), pp.end());
}
-
-/// Grow the extrusion to at least nozzle_diameter*1.05 (lowest safe extrusion width)
-/// Do not grow points inside the anchor.
-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 * 1.05)
- polyline.width[i] = nozzle_diameter * 1.05;
- }
- }
-}
-
-void
-MedialAxis::taper_ends(ThickPolylines& pp) {
- const coord_t min_size = std::max(this->nozzle_diameter * 0.1, this->height * (1. - 0.25 * PI));
- const coordf_t length = std::min(this->anchor_size, (this->nozzle_diameter - min_size) / 2);
- if (length <= SCALED_RESOLUTION) return;
- //ensure the width is not lower than 0.4.
- for (ThickPolyline& polyline : pp) {
- if (polyline.length() < length * 2.2) continue;
- if (polyline.endpoints.first) {
- polyline.width[0] = min_size;
- coord_t current_dist = min_size;
- coord_t last_dist = min_size;
- for (size_t i = 1; i<polyline.width.size(); ++i) {
- current_dist += (coord_t) polyline.points[i - 1].distance_to(polyline.points[i]);
- if (current_dist > length) {
- //create new point if not near enough
- if (current_dist > polyline.width[i] + SCALED_RESOLUTION) {
- coordf_t percent_dist = (polyline.width[i] - polyline.width[i - 1]) / (current_dist - last_dist);
- polyline.points.insert(polyline.points.begin() + i, polyline.points[i - 1].interpolate(percent_dist, polyline.points[i]));
- polyline.width.insert(polyline.width.begin() + i, polyline.width[i]);
- }
- break;
- }
- polyline.width[i] = std::max((coordf_t)min_size, min_size + (polyline.width[i] - min_size) * current_dist / length);
- last_dist = current_dist;
- }
- }
- if (polyline.endpoints.second) {
- const size_t back_idx = polyline.width.size() - 1;
- polyline.width[back_idx] = min_size;
- coord_t current_dist = min_size;
- coord_t last_dist = min_size;
- for (size_t i = 1; i<polyline.width.size(); ++i) {
- current_dist += (coord_t)polyline.points[back_idx - i + 1].distance_to(polyline.points[back_idx - i]);
- if (current_dist > length) {
- //create new point if not near enough
- if (current_dist > polyline.width[back_idx - i] + SCALED_RESOLUTION) {
- coordf_t percent_dist = (polyline.width[back_idx - i] - polyline.width[back_idx - i + 1]) / (current_dist - last_dist);
- polyline.points.insert(polyline.points.begin() + back_idx - i + 1, polyline.points[back_idx - i + 1].interpolate(percent_dist, polyline.points[back_idx - i]));
- polyline.width.insert(polyline.width.begin() + back_idx - i + 1, polyline.width[back_idx - i]);
- }
- break;
- }
- polyline.width[back_idx - i] = std::max((coordf_t)min_size, min_size + (polyline.width[back_idx - i] - min_size) * current_dist / length);
- last_dist = current_dist;
- }
- }
- }
-}
-
-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
// variable extrusion within a single move; this value shall only affect the amount
// of segments, and any pruning shall be performed before we apply this tolerance
@@ -1621,27 +1655,32 @@ ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, E
--i;
continue;
}
+ //gapfill : we want to be able to fill the voids (touching the perimeters), so the spacing is what we want.
+ //thinwall: we want the extrusion to not go out of the polygon, so the width is what we want.
+ // but we can't extrude with a negative spacing, so we have to gradually fall back to spacing if the width is too small.
+
+ // default: extrude a thin wall that doesn't go outside of the specified width.
+ coordf_t wanted_width = unscale<coordf_t>(line.a_width);
+ if (role == erGapFill) {
+ // Convert from spacing to extrusion width based on the extrusion model
+ // of a square extrusion ended with semi circles.
+ wanted_width = unscale<coordf_t>(line.a_width) + flow.height * (1. - 0.25 * PI);
+ } else if (unscale<coordf_t>(line.a_width) < 2 * flow.height * (1. - 0.25 * PI)) {
+ //width (too) small, be sure to not extrude with negative spacing.
+ //we began to fall back to spacing gradually even before the spacing go into the negative
+ // to make extrusion1 < extrusion2 if width1 < width2 even if width2 is too small.
+ wanted_width = unscale<coordf_t>(line.a_width)*0.35 + 1.3 * flow.height * (1. - 0.25 * PI);
+ }
if (path.polyline.points.empty()) {
+ flow.width = wanted_width;
path.polyline.append(line.a);
path.polyline.append(line.b);
- if (role == erGapFill) {
- // Convert from spacing to extrusion width based on the extrusion model
- // of a square extrusion ended with semi circles.
- flow.width = unscale<coordf_t>(line.a_width) + flow.height * (1. - 0.25 * PI);
- } else if (unscale<coordf_t>(line.a_width) < 2 * flow.height * (1. - 0.25 * PI)) {
- flow.width = unscale<coordf_t>(line.a_width)*0.35 + 1.3 * flow.height * (1. - 0.25 * PI);
- } else {
- flow.width = unscale<coordf_t>(line.a_width);
- }
-#ifdef SLIC3R_DEBUG
- printf(" filling %f gap\n", flow.width);
-#endif
path.mm3_per_mm = flow.mm3_per_mm();
path.width = flow.width;
path.height = flow.height;
} else {
- thickness_delta = fabs(flow.scaled_spacing() - line.a_width);
+ thickness_delta = scale_(fabs(flow.width - wanted_width));
if (thickness_delta <= tolerance / 2) {
// the width difference between this line and the current flow width is
// within the accepted tolerance