diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 9752744453..7a506e236e 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -143,16 +143,19 @@ void Layer::make_perimeters() if (! (*it)->slices.empty()) { LayerRegion* other_layerm = *it; const PrintRegionConfig &other_config = other_layerm->region()->config(); - if (config.perimeter_extruder == other_config.perimeter_extruder - && config.perimeters == other_config.perimeters - && config.perimeter_speed == other_config.perimeter_speed - && config.external_perimeter_speed == other_config.external_perimeter_speed - && config.gap_fill_speed == other_config.gap_fill_speed - && config.overhangs == other_config.overhangs + if (config.perimeter_extruder == other_config.perimeter_extruder + && config.perimeters == other_config.perimeters + && config.perimeter_speed == other_config.perimeter_speed + && config.external_perimeter_speed == other_config.external_perimeter_speed + && config.gap_fill_speed == other_config.gap_fill_speed + && config.overhangs == other_config.overhangs && config.opt_serialize("perimeter_extrusion_width") == other_config.opt_serialize("perimeter_extrusion_width") - && config.thin_walls == other_config.thin_walls - && config.external_perimeters_first == other_config.external_perimeters_first - && config.infill_overlap == other_config.infill_overlap) + && config.thin_walls == other_config.thin_walls + && config.external_perimeters_first == other_config.external_perimeters_first + && config.infill_overlap == other_config.infill_overlap + && config.fuzzy_skin == other_config.fuzzy_skin + && config.fuzzy_skin_thickness == other_config.fuzzy_skin_thickness + && config.fuzzy_skin_point_dist == other_config.fuzzy_skin_point_dist) { other_layerm->perimeters.clear(); other_layerm->fills.clear(); diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index eef737f971..4b8aba0ebd 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -112,30 +112,69 @@ static void variable_width(const ThickPolylines& polylines, ExtrusionRole role, class PerimeterGeneratorLoop { public: // Polygon of this contour. - Polygon polygon; + Polygon polygon; // Is it a contour or a hole? // Contours are CCW oriented, holes are CW oriented. - bool is_contour; + bool is_contour; // Depth in the hierarchy. External perimeter has depth = 0. An external perimeter could be both a contour and a hole. - unsigned short depth; + unsigned short depth; + // Should this contur be fuzzyfied on path generation? + bool fuzzify; // Children contour, may be both CCW and CW oriented (outer contours or holes). std::vector children; - PerimeterGeneratorLoop(Polygon &&polygon, unsigned short depth, bool is_contour) : - polygon(std::move(polygon)), is_contour(is_contour), depth(depth) {} + PerimeterGeneratorLoop(const Polygon &polygon, unsigned short depth, bool is_contour, bool fuzzify) : + polygon(polygon), is_contour(is_contour), depth(depth), fuzzify(fuzzify) {} // External perimeter. It may be CCW or CW oriented (outer contour or hole contour). bool is_external() const { return this->depth == 0; } // An island, which may have holes, but it does not have another internal island. bool is_internal_contour() const; }; -typedef std::vector PerimeterGeneratorLoops; +// Thanks Cura developers for this function. +static void fuzzy_polygon(Polygon &poly, double fuzzy_skin_thickness, double fuzzy_skin_point_dist) +{ + const double min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value + const double range_random_point_dist = fuzzy_skin_point_dist / 2.; + double dist_left_over = double(rand()) * (min_dist_between_points / 2) / double(RAND_MAX); // the distance to be traversed on the line before making the first new point + Point* p0 = &poly.points.back(); + Points out; + out.reserve(poly.points.size()); + for (Point &p1 : poly.points) + { // 'a' is the (next) new point between p0 and p1 + Vec2d p0p1 = (p1 - *p0).cast(); + double p0p1_size = p0p1.norm(); + // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size + double dist_last_point = dist_left_over + p0p1_size * 2.; + for (double p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; + p0pa_dist += min_dist_between_points + double(rand()) * range_random_point_dist / double(RAND_MAX)) + { + double r = double(rand()) * (fuzzy_skin_thickness * 2.) / double(RAND_MAX) - fuzzy_skin_thickness; + out.emplace_back(*p0 + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast()); + dist_last_point = p0pa_dist; + } + dist_left_over = p0p1_size - dist_last_point; + p0 = &p1; + } + while (out.size() < 3) { + size_t point_idx = poly.size() - 2; + out.emplace_back(poly[point_idx]); + if (point_idx == 0) + break; + -- point_idx; + } + if (out.size() >= 3) + poly.points = std::move(out); +} + +using PerimeterGeneratorLoops = std::vector; static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perimeter_generator, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) { // loops is an arrayref of ::Loop objects // turn each one into an ExtrusionLoop object - ExtrusionEntityCollection coll; + ExtrusionEntityCollection coll; + Polygon fuzzified; for (const PerimeterGeneratorLoop &loop : loops) { bool is_external = loop.is_external(); @@ -153,12 +192,17 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime // detect overhanging/bridging perimeters ExtrusionPaths paths; + const Polygon &polygon = loop.fuzzify ? fuzzified : loop.polygon; + if (loop.fuzzify) { + fuzzified = loop.polygon; + fuzzy_polygon(fuzzified, scaled(perimeter_generator.config->fuzzy_skin_thickness.value), scaled(perimeter_generator.config->fuzzy_skin_point_dist.value)); + } if (perimeter_generator.config->overhangs && perimeter_generator.layer_id > 0 && !(perimeter_generator.object_config->support_material && perimeter_generator.object_config->support_material_contact_distance.value == 0)) { // get non-overhang paths by intersecting this loop with the grown lower slices extrusion_paths_append( paths, - intersection_pl((Polygons)loop.polygon, perimeter_generator.lower_slices_polygons()), + intersection_pl({ polygon }, perimeter_generator.lower_slices_polygons()), role, is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(), is_external ? perimeter_generator.ext_perimeter_flow.width : perimeter_generator.perimeter_flow.width, @@ -169,7 +213,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime // the loop centerline and original lower slices is >= half nozzle diameter extrusion_paths_append( paths, - diff_pl((Polygons)loop.polygon, perimeter_generator.lower_slices_polygons()), + diff_pl({ polygon }, perimeter_generator.lower_slices_polygons()), erOverhangPerimeter, perimeter_generator.mm3_per_mm_overhang(), perimeter_generator.overhang_flow.width, @@ -180,7 +224,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime chain_and_reorder_extrusion_paths(paths, &paths.front().first_point()); } else { ExtrusionPath path(role); - path.polyline = loop.polygon.split_at_first_point(); + path.polyline = polygon.split_at_first_point(); path.mm3_per_mm = is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(); path.width = is_external ? perimeter_generator.ext_perimeter_flow.width : perimeter_generator.perimeter_flow.width; path.height = (float)perimeter_generator.layer_height; @@ -230,42 +274,6 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime return out; } -// Thanks Cura developers for this function. -static void fuzzy_polygon(Polygon &poly, double fuzzy_skin_thickness, double fuzzy_skin_point_dist) -{ - const double min_dist_between_points = fuzzy_skin_point_dist * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value - const double range_random_point_dist = fuzzy_skin_point_dist / 2.; - double dist_left_over = double(rand()) * (min_dist_between_points / 2) / double(RAND_MAX); // the distance to be traversed on the line before making the first new point - Point* p0 = &poly.points.back(); - Points out; - out.reserve(poly.points.size()); - for (Point &p1 : poly.points) - { // 'a' is the (next) new point between p0 and p1 - Vec2d p0p1 = (p1 - *p0).cast(); - double p0p1_size = p0p1.norm(); - // so that p0p1_size - dist_last_point evaulates to dist_left_over - p0p1_size - double dist_last_point = dist_left_over + p0p1_size * 2.; - for (double p0pa_dist = dist_left_over; p0pa_dist < p0p1_size; - p0pa_dist += min_dist_between_points + double(rand()) * range_random_point_dist / double(RAND_MAX)) - { - double r = double(rand()) * (fuzzy_skin_thickness * 2.) / double(RAND_MAX) - fuzzy_skin_thickness; - out.emplace_back(*p0 + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast()); - dist_last_point = p0pa_dist; - } - dist_left_over = p0p1_size - dist_last_point; - p0 = &p1; - } - while (out.size() < 3) { - size_t point_idx = poly.size() - 2; - out.emplace_back(poly[point_idx]); - if (point_idx == 0) - break; - -- point_idx; - } - if (out.size() >= 3) - poly.points = std::move(out); -} - void PerimeterGenerator::process() { // other perimeters @@ -392,27 +400,22 @@ void PerimeterGenerator::process() // If i > loop_number, we were looking just for gaps. break; } - const bool fuzzify = this->config->fuzzy_skin != FuzzySkinType::None && i == 0 && this->layer_id > 0; - for (ExPolygon expolygon : offsets) { - // Outer contour may overlap with an inner contour, - // inner contour may overlap with another inner contour, - // outer contour may overlap with itself. - //FIXME evaluate the overlaps, annotate each point with an overlap depth, - if (fuzzify) { - // External perimeter, above the 1st layer. - fuzzy_polygon(expolygon.contour, fuzzy_skin_thickness, fuzzy_skin_point_dist); - if (this->config->fuzzy_skin == FuzzySkinType::All) - for (Polygon &hole : expolygon.holes) - fuzzy_polygon(hole, fuzzy_skin_thickness, fuzzy_skin_point_dist); - } + { + const bool fuzzify_contours = this->config->fuzzy_skin != FuzzySkinType::None && i == 0 && this->layer_id > 0; + const bool fuzzify_holes = fuzzify_contours && this->config->fuzzy_skin == FuzzySkinType::All; + for (const ExPolygon &expolygon : offsets) { + // Outer contour may overlap with an inner contour, + // inner contour may overlap with another inner contour, + // outer contour may overlap with itself. + //FIXME evaluate the overlaps, annotate each point with an overlap depth, + // compensate for the depth of intersection. + contours[i].emplace_back(expolygon.contour, i, true, fuzzify_contours); - // compensate for the depth of intersection. - contours[i].emplace_back(std::move(expolygon.contour), i, true); - - if (! expolygon.holes.empty()) { - holes[i].reserve(holes[i].size() + expolygon.holes.size()); - for (Polygon &hole : expolygon.holes) - holes[i].emplace_back(std::move(hole), i, false); + if (! expolygon.holes.empty()) { + holes[i].reserve(holes[i].size() + expolygon.holes.size()); + for (const Polygon &hole : expolygon.holes) + holes[i].emplace_back(hole, i, false, fuzzify_holes); + } } } last = std::move(offsets);