diff options
Diffstat (limited to 'src/libslic3r/MedialAxis.cpp')
-rw-r--r-- | src/libslic3r/MedialAxis.cpp | 214 |
1 files changed, 165 insertions, 49 deletions
diff --git a/src/libslic3r/MedialAxis.cpp b/src/libslic3r/MedialAxis.cpp index 1ed1320f7..c44c1d97a 100644 --- a/src/libslic3r/MedialAxis.cpp +++ b/src/libslic3r/MedialAxis.cpp @@ -1395,6 +1395,65 @@ MedialAxis::remove_too_thin_points(ThickPolylines& pp) void MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size) { + // reduce the flow at the intersection ( + ) points + //FIXME: TODO: note that crossings are unnafected right now. they may need a different codepath directly in their method + //TODO: unit tests for that. + //TODO: never triggered. ther's only the sections passed by crossing fusion that aren't edge-case and it's not treated by this. => comment for now + //for each not-endpoint point + //std::vector<bool> endpoint_not_used(pp.size() * 2, true); + //for (size_t idx_endpoint = 0; idx_endpoint < endpoint_not_used.size(); idx_endpoint++) { + // ThickPolyline& polyline = pp[idx_endpoint / 2]; + // //update endpoint_not_used if not seen before + // if (idx_endpoint % 2 == 0 && endpoint_not_used[idx_endpoint]) { + // //update + // endpoint_not_used[(idx_endpoint / 2)] = !polyline.endpoints.first; + // endpoint_not_used[(idx_endpoint / 2) + 1] = endpoint_not_used[(idx_endpoint / 2) + 1] && !polyline.endpoints.second; + // } + // if (endpoint_not_used[idx_endpoint]) { + // int nb_endpoints; + // Point pt = idx_endpoint % 2 == 0 ? polyline.first_point() : polyline.last_point(); + // if (idx_endpoint % 2 == 0 && pt.coincides_with(polyline.last_point())) { + // nb_endpoints++; + // endpoint_not_used[(idx_endpoint / 2) + 1] = false; + // } + // //good, now find other points + // for (size_t idx_other_pp = (idx_endpoint / 2) + 1; idx_other_pp < pp.size(); idx_other_pp++) { + // ThickPolyline& other = pp[idx_other_pp]; + // if (pt.coincides_with(other.first_point())) { + // nb_endpoints++; + // endpoint_not_used[idx_other_pp * 2] = false; + // } + // if (pt.coincides_with(other.last_point())) { + // nb_endpoints++; + // endpoint_not_used[idx_other_pp * 2 + 1] = false; + // } + // } + // if (nb_endpoints < 3) + // continue; + // // reduce width accordingly + // float reduction = 2.f / nb_endpoints; + // std::cout << "reduce " << reduction << " points!\n"; + // if (idx_endpoint % 2 == 0 ) { + // polyline.width.front() *= reduction; + // if(pt.coincides_with(polyline.last_point())) + // polyline.width.back() *= reduction; + // } else { + // polyline.width.back() *= reduction; + // } + // //good, now find other points + // for (size_t idx_other_pp = (idx_endpoint / 2) + 1; idx_other_pp < pp.size(); idx_other_pp++) { + // ThickPolyline& other = pp[idx_other_pp]; + // if (pt.coincides_with(other.first_point())) { + // other.width.front() *= reduction; + // } + // if (pt.coincides_with(other.last_point())) { + // other.width.back() *= reduction; + // } + // } + // //TODO: restore good width at width dist, or reduce other points up to width dist + // } + //} + //remove too short polyline bool changes = true; while (changes) { @@ -1408,11 +1467,16 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz // (we can't do this check before endpoints extension and clipping because we don't // know how long will the endpoints be extended since it depends on polygon thickness // which is variable - extension will be <= max_width/2 on each side) - if ((polyline.endpoints.first || polyline.endpoints.second) - && polyline.length() < max_width / 2) { - if (shortest_size > polyline.length()) { - shortest_size = polyline.length(); - shortest_idx = i; + if ((polyline.endpoints.first || polyline.endpoints.second)) { + coordf_t max_width = max_width / 2; + for (coordf_t w : polyline.width) + max_width = std::max(max_width, w); + if(polyline.length() < max_width) { + if (shortest_size > polyline.length()) { + shortest_size = polyline.length(); + shortest_idx = i; + } + } } @@ -1857,6 +1921,7 @@ MedialAxis::build(ThickPolylines &polylines_out) // svg.draw(pp); // svg.Close(); //} + //TODO: reduce the flow at the intersection ( + ) points on crossing? concatenate_polylines_with_crossing(pp); //{ // std::stringstream stri; @@ -1879,7 +1944,6 @@ MedialAxis::build(ThickPolylines &polylines_out) // svg.Close(); //} - //TODO: reduce the flow at the intersection ( + ) points ? ensure_not_overextrude(pp); //{ // std::stringstream stri; @@ -1923,82 +1987,115 @@ MedialAxis::build(ThickPolylines &polylines_out) } ExtrusionEntityCollection -thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) +thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow, coord_t resolution_internal) { + assert(resolution_internal > SCALED_EPSILON); + // 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 - const coord_t tolerance = 4 * SCALED_RESOLUTION;//scale_(0.05); + const coord_t tolerance = flow.scaled_width() / 10;//scale_(0.05); ExtrusionEntityCollection coll; for (const ThickPolyline &p : polylines) { ExtrusionPaths paths; ExtrusionPath path(role); ThickLines lines = p.thicklines(); - + + coordf_t saved_line_len = 0; for (int i = 0; i < (int)lines.size(); ++i) { ThickLine& line = lines[i]; - + const coordf_t line_len = line.length(); - if (line_len < SCALED_EPSILON) continue; - + const coordf_t prev_line_len = saved_line_len; + saved_line_len = line_len; + assert(line.a_width >= 0); assert(line.b_width >= 0); coord_t thickness_delta = std::abs(line.a_width - line.b_width); - if (thickness_delta > tolerance && ceil(float(thickness_delta) / float(tolerance)) > 2) { - const uint16_t segments = 1 + (uint16_t) std::min((uint32_t)16000, (uint32_t)ceil(float(thickness_delta) / float(tolerance))); - Points pp; - std::vector<coordf_t> width; - { + + // split lines ? + if (resolution_internal < line_len) { + if (thickness_delta > tolerance && ceil(float(thickness_delta) / float(tolerance)) > 2) { + const uint16_t segments = 1 + (uint16_t)std::min((uint32_t)16000, (uint32_t)ceil(float(thickness_delta) / float(tolerance))); + Points pp; + std::vector<coordf_t> width; + { + for (size_t j = 0; j < segments; ++j) { + pp.push_back(line.a.interpolate(((double)j) / segments, line.b)); + double percent_width = ((double)j) / (segments - 1); + width.push_back(line.a_width * (1 - percent_width) + line.b_width * percent_width); + } + pp.push_back(line.b); + + assert(pp.size() == segments + 1); + assert(width.size() == segments); + } + + // delete this line and insert new ones + lines.erase(lines.begin() + i); for (size_t j = 0; j < segments; ++j) { - pp.push_back(line.a.interpolate(((double)j) / segments, line.b)); - double percent_width = ((double)j) / (segments-1); - width.push_back(line.a_width * (1 - percent_width) + line.b_width * percent_width); + ThickLine new_line(pp[j], pp[j + 1]); + new_line.a_width = width[j]; + new_line.b_width = width[j]; + lines.insert(lines.begin() + i + j, new_line); } - pp.push_back(line.b); - assert(pp.size() == segments + 1); - assert(width.size() == segments); + // go back to the start of this loop iteration + --i; + continue; + } else if (thickness_delta > 0) { + //create a middle point + ThickLine new_line(line.a.interpolate(0.5, line.b), line.b); + new_line.a_width = line.b_width; + new_line.b_width = line.b_width; + line.b = new_line.a; + line.b_width = line.a_width; + lines.insert(lines.begin() + i + 1, new_line); + + // go back to the start of this loop iteration + --i; + continue; } - - // delete this line and insert new ones + } else if (i > 0 && resolution_internal > line_len + prev_line_len) { + ThickLine& prev_line = lines[i - 1]; + //merge lines? + coordf_t width = prev_line_len * (prev_line.a_width + prev_line.b_width) / 2; + width += line_len * (line.a_width + line.b_width) / 2; + prev_line.b = line.b; + coordf_t new_length = prev_line.length(); + width /= new_length; + prev_line.a_width = width; + prev_line.b_width = width; + saved_line_len = new_length; + //erase 'line' lines.erase(lines.begin() + i); - for (size_t j = 0; j < segments; ++j) { - ThickLine new_line(pp[j], pp[j + 1]); - new_line.a_width = width[j]; - new_line.b_width = width[j]; - lines.insert(lines.begin() + i + j, new_line); - } - --i; continue; } else if (thickness_delta > 0) { - //create a middle point - ThickLine new_line(line.a.interpolate(0.5, line.b), line.b); - new_line.a_width = line.b_width; - new_line.b_width = line.b_width; - line.b = new_line.a; + //set width as a middle-ground + line.a_width = (line.a_width + line.b_width) / 2; line.b_width = line.a_width; - lines.insert(lines.begin() + i + 1, new_line); - - --i; - continue; } + } + for (int i = 0; i < (int)lines.size(); ++i) { + ThickLine& line = lines[i]; + //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); + double wanted_width = unscaled(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); + wanted_width = unscaled(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); + wanted_width = unscaled(line.a_width)*0.35 + 1.3 * flow.height * (1. - 0.25 * PI); } if (path.polyline.points.empty()) { @@ -2012,7 +2109,7 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl path.width = flow.width; path.height = flow.height; } else { - thickness_delta = scale_(fabs(flow.width - wanted_width)); + coord_t thickness_delta = scale_t(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 @@ -2021,12 +2118,21 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl // we need to initialize a new line paths.emplace_back(std::move(path)); path = ExtrusionPath(role); - --i; + flow.width = wanted_width; + path.polyline.append(line.a); + path.polyline.append(line.b); + assert(flow.mm3_per_mm() == flow.mm3_per_mm()); + assert(flow.width == flow.width); + assert(flow.height == flow.height); + path.mm3_per_mm = flow.mm3_per_mm(); + path.width = flow.width; + path.height = flow.height; } } } if (path.polyline.is_valid()) paths.emplace_back(std::move(path)); + // Append paths to collection. if (!paths.empty()) { if (paths.front().first_point().coincides_with(paths.back().last_point())) { @@ -2034,11 +2140,21 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl } else { if (role == erThinWall){ //thin walls : avoid to cut them, please. + //also, keep the start, as the start should be already in a frontier where possible. ExtrusionEntityCollection unsortable_coll(paths); - unsortable_coll.no_sort = true; + unsortable_coll.set_can_sort_reverse(false, false); coll.append(unsortable_coll); - }else //gap fill : cut them as much as you want - coll.append(paths); + } else { + if (paths.size() <= 1) { + coll.append(paths); + } else { + ExtrusionEntityCollection unsortable_coll(paths); + //gap fill : can reverse, but refrain from cutting them as it creates a mess. + // I say that, but currently (false, true) does bad things. + unsortable_coll.set_can_sort_reverse(false, true); + coll.append(unsortable_coll); + } + } } } } |