From a985771c9b319aa69dd99769d5920762b4352844 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 9 Oct 2018 19:16:00 +0200 Subject: [PATCH 1/3] bugfix thin_wall --- xs/src/libslic3r/MedialAxis.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xs/src/libslic3r/MedialAxis.cpp b/xs/src/libslic3r/MedialAxis.cpp index 27b77e197a9..4fbbf5344e7 100644 --- a/xs/src/libslic3r/MedialAxis.cpp +++ b/xs/src/libslic3r/MedialAxis.cpp @@ -624,11 +624,15 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con new_back = polyline.points.back(); } else { (void)this->expolygon.contour.first_intersection(line, &new_back); + // safety check if no intersection + if (new_back.x == 0 && new_back.y == 0) return; polyline.points.push_back(new_back); polyline.width.push_back(polyline.width.back()); } Point new_bound; (void)bounds.contour.first_intersection(line, &new_bound); + // safety check if no intersection + if (new_bound.x == 0 && new_bound.y == 0) return; /* if (new_bound.coincides_with_epsilon(new_back)) { return; }*/ From 6d63e0dae5e793268a746173c3269848f330f2c7 Mon Sep 17 00:00:00 2001 From: supermerill Date: Mon, 15 Oct 2018 14:09:21 +0200 Subject: [PATCH 2/3] continous mode for perimeters (it merge the loops into a big one) --- xs/src/libslic3r/ExtrusionEntity.hpp | 5 +- xs/src/libslic3r/GCode.cpp | 2 + xs/src/libslic3r/Layer.cpp | 5 +- xs/src/libslic3r/Line.cpp | 8 + xs/src/libslic3r/Line.hpp | 1 + xs/src/libslic3r/MultiPoint.cpp | 37 ++ xs/src/libslic3r/MultiPoint.hpp | 2 + xs/src/libslic3r/PerimeterGenerator.cpp | 592 +++++++++++++++++++++++- xs/src/libslic3r/PerimeterGenerator.hpp | 13 +- xs/src/libslic3r/Point.hpp | 2 + xs/src/libslic3r/PrintConfig.cpp | 10 +- xs/src/libslic3r/PrintConfig.hpp | 2 + xs/src/libslic3r/PrintObject.cpp | 1 + xs/src/slic3r/GUI/Preset.cpp | 2 +- xs/src/slic3r/GUI/Tab.cpp | 7 +- 15 files changed, 677 insertions(+), 12 deletions(-) diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index 15363e8edab..d338771f4e4 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -196,9 +196,10 @@ class ExtrusionMultiPath : public ExtrusionEntity // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. double min_mm3_per_mm() const; Polyline as_polyline() const; - virtual double total_volume() const { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } + virtual double total_volume() const { double volume = 0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } }; + // Single continuous extrusion loop, possibly with varying extrusion thickness, extrusion height or bridging / non bridging. class ExtrusionLoop : public ExtrusionEntity { @@ -244,7 +245,7 @@ class ExtrusionLoop : public ExtrusionEntity // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. double min_mm3_per_mm() const; Polyline as_polyline() const { return this->polygon().split_at_first_point(); } - virtual double total_volume() const { double volume =0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } + virtual double total_volume() const { double volume = 0.; for (const auto& path : paths) volume += path.total_volume(); return volume; } private: ExtrusionLoopRole m_loop_role; diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 27c838037cb..708fe500c92 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -2367,6 +2367,8 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, speed = m_config.get_abs_value("top_solid_infill_speed"); } else if (path.role() == erGapFill) { speed = m_config.get_abs_value("gap_fill_speed"); + } else if (path.role() == erNone) { + speed = m_config.get_abs_value("travel_speed"); } else { CONFESS("Invalid speed"); } diff --git a/xs/src/libslic3r/Layer.cpp b/xs/src/libslic3r/Layer.cpp index 652bcdaa044..4b3ecb3f23d 100644 --- a/xs/src/libslic3r/Layer.cpp +++ b/xs/src/libslic3r/Layer.cpp @@ -101,8 +101,9 @@ void Layer::make_perimeters() && config.gap_fill_speed == other_config.gap_fill_speed && config.overhangs == other_config.overhangs && config.serialize("perimeter_extrusion_width").compare(other_config.serialize("perimeter_extrusion_width")) == 0 - && config.thin_walls == other_config.thin_walls - && config.external_perimeters_first == other_config.external_perimeters_first) { + && config.thin_walls == other_config.thin_walls + && config.external_perimeters_first == other_config.external_perimeters_first + && config.perimeter_loop == other_config.perimeter_loop) { layerms.push_back(other_layerm); done.insert(it - this->regions.begin()); } diff --git a/xs/src/libslic3r/Line.cpp b/xs/src/libslic3r/Line.cpp index e9d5d7742c9..691d55b80b6 100644 --- a/xs/src/libslic3r/Line.cpp +++ b/xs/src/libslic3r/Line.cpp @@ -218,6 +218,14 @@ Line::ccw(const Point& point) const return point.ccw(*this); } +coord_t +Line::dot(Line &l2) const +{ + Vector v_1 = vector(); + Vector v_2 = l2.vector(); + return v_1.x*v_2.x + v_1.y*v_2.y; +} + double Line3::length() const { return a.distance_to(b); diff --git a/xs/src/libslic3r/Line.hpp b/xs/src/libslic3r/Line.hpp index 4826017ab5b..81e86aab0b5 100644 --- a/xs/src/libslic3r/Line.hpp +++ b/xs/src/libslic3r/Line.hpp @@ -47,6 +47,7 @@ class Line void extend_start(double distance); bool intersection(const Line& line, Point* intersection) const; double ccw(const Point& point) const; + coord_t dot(Line &l2) const; }; class ThickLine : public Line diff --git a/xs/src/libslic3r/MultiPoint.cpp b/xs/src/libslic3r/MultiPoint.cpp index 2e65492cd8e..bfa0779efff 100644 --- a/xs/src/libslic3r/MultiPoint.cpp +++ b/xs/src/libslic3r/MultiPoint.cpp @@ -173,6 +173,43 @@ MultiPoint::dump_perl() const return ret.str(); } +// Projection of a point onto the polygon. +Point MultiPoint::point_projection(const Point &point) const { + Point proj = point; + double dmin = std::numeric_limits::max(); + if (!this->points.empty()) { + for (size_t i = 0; i < this->points.size()-1; ++i) { + const Point &pt0 = this->points[i]; + const Point &pt1 = this->points[i + 1]; + double d = pt0.distance_to(point); + if (d < dmin) { + dmin = d; + proj = pt0; + } + d = pt1.distance_to(point); + if (d < dmin) { + dmin = d; + proj = pt1; + } + Pointf v1(coordf_t(pt1.x - pt0.x), coordf_t(pt1.y - pt0.y)); + coordf_t div = dot(v1); + if (div > 0.) { + Pointf v2(coordf_t(point.x - pt0.x), coordf_t(point.y - pt0.y)); + coordf_t t = dot(v1, v2) / div; + if (t > 0. && t < 1.) { + Point foot(coord_t(floor(coordf_t(pt0.x) + t * v1.x + 0.5)), coord_t(floor(coordf_t(pt0.y) + t * v1.y + 0.5))); + d = foot.distance_to(point); + if (d < dmin) { + dmin = d; + proj = foot; + } + } + } + } + } + return proj; +} + //FIXME This is very inefficient in term of memory use. // The recursive algorithm shall run in place, not allocating temporary data in each recursion. Points diff --git a/xs/src/libslic3r/MultiPoint.hpp b/xs/src/libslic3r/MultiPoint.hpp index 0970e9a6743..d97b6b1aa6d 100644 --- a/xs/src/libslic3r/MultiPoint.hpp +++ b/xs/src/libslic3r/MultiPoint.hpp @@ -76,6 +76,8 @@ class MultiPoint bool intersection(const Line& line, Point* intersection) const; bool first_intersection(const Line& line, Point* intersection) const; std::string dump_perl() const; + // Projection of a point onto the lines defined by the points. + virtual Point point_projection(const Point &point) const; static Points _douglas_peucker(const Points &points, const double tolerance); }; diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp index e5fee9dfc5a..19040c6fb37 100644 --- a/xs/src/libslic3r/PerimeterGenerator.cpp +++ b/xs/src/libslic3r/PerimeterGenerator.cpp @@ -5,9 +5,33 @@ #include "Geometry.hpp" #include #include +#include + +#include "BoundingBox.hpp" +#include "ExPolygon.hpp" +#include "Geometry.hpp" +#include "Polygon.hpp" +#include "Line.hpp" +#include "ClipperUtils.hpp" +#include "SVG.hpp" +#include "polypartition.h" +#include "poly2tri/poly2tri.h" +#include +#include +#include namespace Slic3r { + PerimeterGeneratorLoops get_all_Childs(PerimeterGeneratorLoop loop) { + PerimeterGeneratorLoops ret; + for (PerimeterGeneratorLoop &child : loop.children) { + ret.push_back(child); + PerimeterGeneratorLoops vals = get_all_Childs(child); + ret.insert(ret.end(), vals.begin(), vals.end()); + } + return ret; + } + void PerimeterGenerator::process() { // other perimeters @@ -401,8 +425,30 @@ void PerimeterGenerator::process() NEXT_CONTOUR: ; } } - // at this point, all loops should be in contours[0] - ExtrusionEntityCollection entities = this->_traverse_loops(contours.front(), thin_walls); + // at this point, all loops should be in contours[0] (= contours.front() ) + ExtrusionEntityCollection entities; + if (config->perimeter_loop.value) { + //onlyone_perimter = >fusion all perimeterLoops + for (PerimeterGeneratorLoop &loop : contours.front()) { + ExtrusionLoop extr_loop = this->_traverse_and_join_loops(loop, get_all_Childs(loop), loop.polygon.points.front()); + //ExtrusionLoop extr_loop = this->_traverse_and_join_loops_old(loop, loop.polygon.points.front(), true); + extr_loop.paths.back().polyline.points.push_back(extr_loop.paths.front().polyline.points.front()); + entities.append(extr_loop); + } + + // append thin walls + if (!thin_walls.empty()) { + ExtrusionEntityCollection tw = this->_variable_width + (thin_walls, erExternalPerimeter, this->ext_perimeter_flow); + + entities.append(tw.entities); + thin_walls.clear(); + } + } else { + entities = this->_traverse_loops(contours.front(), thin_walls); + } + + // if brim will be printed, reverse the order of perimeters so that // we continue inwards after having finished the brim // TODO: add test for perimeter order @@ -487,6 +533,7 @@ void PerimeterGenerator::process() } // for each island } + ExtrusionEntityCollection PerimeterGenerator::_traverse_loops( const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const { @@ -596,6 +643,547 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops( return entities; } +PerimeterIntersectionPoint +get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) { + //find best points of intersections + PerimeterIntersectionPoint intersect; + intersect.distance = 0x7FFFFFFF; + intersect.idx_polyline_outter = -1; + intersect.idx_children = -1; + for (size_t idx_child = 0; idx_child < children.size(); idx_child++) { + const PerimeterGeneratorLoop &child = children[idx_child]; + for (size_t idx_poly = 0; idx_poly < myPolylines.paths.size(); idx_poly++) { + if (myPolylines.paths[idx_poly].extruder_id == (unsigned int)-1) continue; + if (myPolylines.paths[idx_poly].length() < dist_cut + SCALED_RESOLUTION) continue; + + //first, try to find 2 point near enough + for (size_t idx_point = 0; idx_point < myPolylines.paths[idx_poly].polyline.points.size(); idx_point++) { + const Point &p = myPolylines.paths[idx_poly].polyline.points[idx_point]; + const Point &nearest_p = *child.polygon.closest_point(p); + const coord_t dist = (coord_t)nearest_p.distance_to(p); + if (dist + SCALED_EPSILON / 2 < intersect.distance) { + //ok, copy the idx + intersect.distance = dist; + intersect.idx_children = idx_child; + intersect.idx_polyline_outter = idx_poly; + intersect.outter_best = p; + intersect.child_best = nearest_p; + } + } + if (intersect.distance <= max_dist) { + return intersect; + } + + //second, try to check from one of my points + //don't check the last point, as it's used to go outter, can't use it to go inner. + for (size_t idx_point = 1; idx_point < myPolylines.paths[idx_poly].polyline.points.size()-1; idx_point++) { + const Point &p = myPolylines.paths[idx_poly].polyline.points[idx_point]; + Point nearest_p = child.polygon.point_projection(p); + coord_t dist = (coord_t)nearest_p.distance_to(p); + //if no projection, go to next + if (dist == 0) continue; + //std::cout << " child point " << idx_point << "/" << (myPolylines[idx_poly].me.polyline.points.size() - 1 )<< " dist = " << unscale(dist) << " < ? " << unscale(intersect.distance)<<" \n"; + if (dist + SCALED_EPSILON / 2 < intersect.distance) { + //ok, copy the idx + intersect.distance = dist; + intersect.idx_children = idx_child; + intersect.idx_polyline_outter = idx_poly; + intersect.outter_best = p; + intersect.child_best = nearest_p; + } + } + if (intersect.distance <= max_dist) { + return intersect; + } + //lastly, try to check from one of his points + for (size_t idx_point = 0; idx_point < child.polygon.points.size(); idx_point++) { + const Point &p = child.polygon.points[idx_point]; + Point nearest_p = myPolylines.paths[idx_poly].polyline.point_projection(p); + coord_t dist = (coord_t)nearest_p.distance_to(p); + //if no projection, go to next + if (dist == 0) continue; + //if (nearest_p.coincides_with_epsilon(myPolylines.paths[idx_poly].polyline.points.back())) { + // Line segment(*(myPolylines.paths[idx_poly].polyline.points.end() - 2), myPolylines.paths[idx_poly].polyline.points.back()); + // dist = (coord_t)segment.point_at(segment.length() - dist_cut).distance_to(p); + //} + //std::cout << " my point " << idx_point << " dist=" << unscale(dist) << " print_config->nozzle_diameter.get_at(this->config->perimeter_extruder - 1)); + + + if (loop.polygon.points.size() < 3) return ExtrusionLoop(elrDefault); + if (loop.polygon.length() < dist_cut * 2) { + ExtrusionLoop single_point(elrDefault); + Polyline poly_point; + poly_point.append(loop.polygon.centroid()); + single_point.paths.emplace_back( + loop.is_external() ? erExternalPerimeter : erPerimeter, + (double)(loop.is_external() ? this->_ext_mm3_per_mm : this->_mm3_per_mm), + (float)(loop.is_external() ? this->ext_perimeter_flow.width : this->perimeter_flow.width), + (float)(this->layer_height)); + single_point.paths.back().polyline = poly_point; + return single_point; + } + //std::cout << "idx_closest_from_entry_point : " << loop.polygon.closest_point_index(entry_point) << "/" << loop.polygon.points.size()<<"\n"; + const size_t idx_closest_from_entry_point = loop.polygon.closest_point_index(entry_point); + //std::cout << "loop.polygon.points[idx_closest_from_entry_point].distance_to(entry_point) : " << unscale(loop.polygon.points[idx_closest_from_entry_point].distance_to(entry_point)) << "\n"; + if (loop.polygon.points[idx_closest_from_entry_point].distance_to(entry_point) > SCALED_EPSILON) { + //create new Point + //get first point + size_t idx_before = -1; + for (size_t idx_p_a = 0; idx_p_a < loop.polygon.points.size(); ++idx_p_a) { + Line l(loop.polygon.points[idx_p_a], loop.polygon.points[(idx_p_a + 1 == loop.polygon.points.size()) ? 0 : (idx_p_a + 1)]); + if (entry_point.distance_to(l) < SCALED_EPSILON) { + idx_before = idx_p_a; + break; + } + } + if (idx_before == (size_t)-1) std::cout << "ERROR: _traverse_and_join_loops : idx_before can't be finded to create new point\n"; + initial_polyline = loop.polygon.split_at_index(idx_before); + initial_polyline.points.push_back(entry_point); + initial_polyline.points[0] = entry_point; + } else { + initial_polyline = loop.polygon.split_at_index(idx_closest_from_entry_point); + } + + + //std::vector myPolylines; + ExtrusionLoop my_loop; + + ExtrusionLoop svg_out(elrDefault); + //overhang / notoverhang + { + bool is_external = loop.is_external(); + + ExtrusionRole role; + ExtrusionLoopRole loop_role; + role = is_external ? erExternalPerimeter : erPerimeter; + if (loop.is_internal_contour()) { + // Note that we set loop role to ContourInternalPerimeter + // also when loop is both internal and external (i.e. + // there's only one contour loop). + loop_role = elrContourInternalPerimeter; + } else { + loop_role = elrDefault; + } + + // detect overhanging/bridging perimeters + if (this->config->overhangs && this->layer_id > 0 + && !(this->object_config->support_material && this->object_config->support_material_contact_distance.value == 0)) { + ExtrusionPaths paths; + // get non-overhang paths by intersecting this loop with the grown lower slices + extrusion_paths_append( + paths, + intersection_pl(initial_polyline, this->_lower_slices_p), + role, + is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm, + is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width, + this->layer_height); + + // get overhang paths by checking what parts of this loop fall + // outside the grown lower slices (thus where the distance between + // the loop centerline and original lower slices is >= half nozzle diameter + extrusion_paths_append( + paths, + diff_pl(initial_polyline, this->_lower_slices_p), + erOverhangPerimeter, + this->_mm3_per_mm_overhang, + this->overhang_flow.width, + this->overhang_flow.height); + + // reapply the nearest point search for starting point + // We allow polyline reversal because Clipper may have randomly + // reversed polylines during clipping. + paths = (ExtrusionPaths)ExtrusionEntityCollection(paths).chained_path(); + + + if (direction.length() > 0) { + Polyline direction_polyline; + for (ExtrusionPath &path : paths) { + direction_polyline.points.insert(direction_polyline.points.end(), path.polyline.points.begin(), path.polyline.points.end()); + } + direction_polyline.clip_start(SCALED_RESOLUTION); + direction_polyline.clip_end(SCALED_RESOLUTION); + coord_t dot = direction.dot(Line(direction_polyline.points.back(), direction_polyline.points.front())); + need_to_reverse = dot>0; + } + if (need_to_reverse) { + std::reverse(paths.begin(), paths.end()); + } + //search for the first path + size_t good_idx = 0; + for (size_t idx_path = 0; idx_path < paths.size(); idx_path++) { + const ExtrusionPath &path = paths[idx_path]; + if (need_to_reverse) { + if (path.polyline.points.back().coincides_with_epsilon(initial_polyline.points.front())) { + good_idx = idx_path; + break; + } + } else { + if (path.polyline.points.front().coincides_with_epsilon(initial_polyline.points.front())) { + good_idx = idx_path; + break; + } + } + } + for (size_t idx_path = good_idx; idx_path < paths.size(); idx_path++) { + ExtrusionPath &path = paths[idx_path]; + if (need_to_reverse) path.reverse(); + my_loop.paths.emplace_back(path); + } + for (size_t idx_path = 0; idx_path < good_idx; idx_path++) { + ExtrusionPath &path = paths[idx_path]; + if (need_to_reverse) path.reverse(); + my_loop.paths.emplace_back(path); + } + } else { + + if (direction.length() > 0) { + Polyline direction_polyline = initial_polyline; + direction_polyline.clip_start(SCALED_RESOLUTION); + direction_polyline.clip_end(SCALED_RESOLUTION); + coord_t dot = direction.dot(Line(direction_polyline.points.back(), direction_polyline.points.front())); + need_to_reverse = dot>0; + } + + ExtrusionPath path(role); + path.polyline = initial_polyline; + if (need_to_reverse) path.polyline.reverse(); + path.mm3_per_mm = is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm; + path.width = is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width; + path.height = (float)(this->layer_height); + my_loop.paths.emplace_back(path); + } + + } + + return my_loop; +} + +ExtrusionLoop +PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop, const PerimeterGeneratorLoops &children, const Point entry_point) const +{ + //std::cout << " === ==== _traverse_and_join_loops ==== ===\n"; + + const coord_t dist_cut = (coord_t)scale_(this->print_config->nozzle_diameter.get_at(this->config->perimeter_extruder - 1)); + //TODO change this->external_perimeter_flow.scaled_width() if it's the first one! + const coord_t max_width_extrusion = this->perimeter_flow.scaled_width(); + ExtrusionLoop my_loop = _extrude_and_cut_loop(loop, entry_point); + vector path_is_ccw; + + for (size_t idx_poly = 0; idx_poly < my_loop.paths.size(); idx_poly++) { + path_is_ccw.push_back(true); + } + + //Polylines myPolylines = { myPolyline }; + //iterate on each point ot find the best place to go into the child + vector childs = children; + int child_idx = 0; + while (!childs.empty()) { + child_idx++; + PerimeterIntersectionPoint nearest = get_nearest_point(childs, my_loop, this->perimeter_flow.scaled_width(), this->perimeter_flow.scaled_width()* 0.8); + if (nearest.idx_children == (size_t)-1) { + //return ExtrusionEntityCollection(); + break; + } else { + stringstream log_bef; + const PerimeterGeneratorLoop &child = childs[nearest.idx_children]; + log_bef << "dist travel @search swap is : " << unscale(nearest.outter_best.distance_to(nearest.child_best)) + << " from " << unscale(nearest.outter_best.x) << ":" << unscale(nearest.outter_best.y) + << " to " << unscale(nearest.child_best.x) << ":" << unscale(nearest.child_best.y) + << "\n"; + //std::cout << "c." << child_idx << " === i have " << my_loop.paths.size() << " paths" << " == cut_path_is_ccw size " << path_is_ccw.size() << "\n"; + //std::cout << "change to child " << nearest.idx_children << " @ " << unscale(nearest.outter_best.x) << ":" << unscale(nearest.outter_best.y) + // << ", idxpolyline = " << nearest.idx_polyline_outter << "\n"; + //PerimeterGeneratorLoops less_childs = childs; + //less_childs.erase(less_childs.begin() + nearest.idx_children); + //create new node with recursive ask for the inner perimeter & COPY of the points, ready to be cut + const bool cut_path_is_ccw = path_is_ccw[nearest.idx_polyline_outter]; + my_loop.paths.insert(my_loop.paths.begin() + nearest.idx_polyline_outter + 1, my_loop.paths[nearest.idx_polyline_outter]); + path_is_ccw.insert(path_is_ccw.begin() + nearest.idx_polyline_outter + 1, cut_path_is_ccw); + + ExtrusionPath *outer_start = &my_loop.paths[nearest.idx_polyline_outter]; + ExtrusionPath *outer_end = &my_loop.paths[nearest.idx_polyline_outter + 1]; + Line deletedSection; + + //cut our polyline + //separate them + size_t nearest_idx_outter = outer_start->polyline.closest_point_index(nearest.outter_best); + if (outer_start->polyline.points[nearest_idx_outter].coincides_with_epsilon(nearest.outter_best)) { + if (nearest_idx_outter < outer_start->polyline.points.size() - 1) { + outer_start->polyline.points.erase(outer_start->polyline.points.begin() + nearest_idx_outter + 1, outer_start->polyline.points.end()); + } + if (nearest_idx_outter > 0) { + outer_end->polyline.points.erase(outer_end->polyline.points.begin(), outer_end->polyline.points.begin() + nearest_idx_outter); + } + } else { + //get first point + size_t idx_before = -1; + for (size_t idx_p_a = 0; idx_p_a < outer_start->polyline.points.size() - 1; ++idx_p_a) { + Line l(outer_start->polyline.points[idx_p_a], outer_start->polyline.points[idx_p_a + 1]); + if (nearest.outter_best.distance_to(l) < SCALED_EPSILON) { + idx_before = idx_p_a; + break; + } + } + if (idx_before == (size_t)-1) std::cout << "ERROR: idx_before can't be finded\n"; + + Points &my_polyline_points = outer_start->polyline.points; + my_polyline_points.erase(my_polyline_points.begin() + idx_before + 1, my_polyline_points.end()); + my_polyline_points.push_back(nearest.outter_best); + + if (idx_before < outer_end->polyline.points.size()-1) + outer_end->polyline.points.erase(outer_end->polyline.points.begin(), outer_end->polyline.points.begin() + idx_before + 1); + else + outer_end->polyline.points.erase(outer_end->polyline.points.begin()+1, outer_end->polyline.points.end()); + outer_end->polyline.points.insert(outer_end->polyline.points.begin(), nearest.outter_best); + } + log_bef << "dist travel before child loop get is : " << unscale(outer_start->polyline.points.back().distance_to(nearest.child_best)) + << " from " << unscale(outer_start->polyline.points.back().x) << ":" << unscale(outer_start->polyline.points.back().y) + << " to " << unscale(nearest.child_best.x) << ":" << unscale(nearest.child_best.y) + << "\n"; + Polyline to_reduce = outer_start->polyline; + if (to_reduce.points.size()>1) to_reduce.clip_end(SCALED_RESOLUTION); + deletedSection.a = to_reduce.points.back(); + to_reduce = outer_end->polyline; + if (to_reduce.points.size()>1) to_reduce.clip_start(SCALED_RESOLUTION); + deletedSection.b = to_reduce.points.front(); + + //get the inner loop to connect to us. + ExtrusionLoop child_loop = _extrude_and_cut_loop(child, nearest.child_best, deletedSection); + + //FIXME: if child_loophas no point or 1 point or not enough space !!!!!!! + const size_t child_paths_size = child_loop.paths.size(); + my_loop.paths.insert(my_loop.paths.begin() + nearest.idx_polyline_outter + 1, child_loop.paths.begin(), child_loop.paths.end()); + for (size_t i = 0; i < child_paths_size; i++) path_is_ccw.insert(path_is_ccw.begin() + nearest.idx_polyline_outter + 1, !cut_path_is_ccw); + + //add paths into my_loop => need to re-get the refs + outer_start = &my_loop.paths[nearest.idx_polyline_outter]; + outer_end = &my_loop.paths[nearest.idx_polyline_outter + child_paths_size + 1]; + ExtrusionPath *inner_start = &my_loop.paths[nearest.idx_polyline_outter+1]; + ExtrusionPath *inner_end = &my_loop.paths[nearest.idx_polyline_outter + child_paths_size]; + log_bef << "dist travel before trim is : " << unscale(outer_start->polyline.points.back().distance_to(inner_start->polyline.points.front())) + << " from " << unscale(outer_start->polyline.points.back().x) << ":" << unscale(outer_start->polyline.points.back().y) + << " to " << unscale(inner_start->polyline.points.front().x) << ":" << unscale(inner_start->polyline.points.front().y) + << "\n"; + //TRIM + //choose trim direction + if (outer_start->polyline.points.size() == 1) { + outer_end->polyline.clip_start(dist_cut); + my_loop.paths[nearest.idx_polyline_outter + child_paths_size ].polyline.clip_end(dist_cut); + } else if (outer_end->polyline.points.size() == 1) { + outer_start->polyline.clip_end(dist_cut); + inner_start->polyline.clip_start(dist_cut); + } else { + coord_t length_poly_1 = outer_start->polyline.length(); + coord_t length_poly_2 = outer_end->polyline.length(); + coord_t length_trim_1 = dist_cut / 2; + coord_t length_trim_2 = dist_cut / 2; + if (length_poly_1 < length_trim_1) { + length_trim_2 = length_trim_1 + length_trim_2 - length_poly_1; + } + if (length_poly_2 < length_trim_1) { + length_trim_1 = length_trim_1 + length_trim_2 - length_poly_2; + } + if (length_poly_1 > length_trim_1) { + outer_start->polyline.clip_end(length_trim_1); + } else { + outer_start->polyline.points.erase(outer_start->polyline.points.begin() + 1, outer_start->polyline.points.end()); + } + if (length_poly_2 > length_trim_2) { + outer_end->polyline.clip_start(length_trim_2); + } else { + outer_end->polyline.points.erase(outer_end->polyline.points.begin(), outer_end->polyline.points.end() - 1); + } + + length_poly_1 = inner_start->polyline.length(); + length_poly_2 = inner_end->polyline.length(); + length_trim_1 = dist_cut / 2; + length_trim_2 = dist_cut / 2; + if (length_poly_1 < length_trim_1) { + length_trim_2 = length_trim_1 + length_trim_2 - length_poly_1; + } + if (length_poly_2 < length_trim_1) { + length_trim_1 = length_trim_1 + length_trim_2 - length_poly_2; + } + if (length_poly_1 > length_trim_1) { + inner_start->polyline.clip_start(length_trim_1); + } else { + inner_start->polyline.points.erase( + inner_start->polyline.points.begin(), + inner_start->polyline.points.end() - 1); + } + if (length_poly_2 > length_trim_2) { + inner_end->polyline.clip_end(length_trim_2); + } else { + inner_end->polyline.points.erase( + inner_end->polyline.points.begin() + 1, + inner_end->polyline.points.end()); + } + } + + //last check to see if we need a reverse + { + log_bef << "dist travel before swap is : " << unscale(outer_start->polyline.points.back().distance_to(inner_start->polyline.points.front())) + << " from " << unscale(outer_start->polyline.points.back().x) << ":" << unscale(outer_start->polyline.points.back().y) + << " to " << unscale(inner_start->polyline.points.front().x) << ":" << unscale(inner_start->polyline.points.front().y) + << "\n"; + Line l1(outer_start->polyline.points.back(), inner_start->polyline.points.front()); + Line l2(inner_end->polyline.points.back(), outer_end->polyline.points.front()); + Point p_inter(0, 0); + bool is_interect = l1.intersection(l2, &p_inter); + if (is_interect && p_inter.distance_to(l1) < SCALED_EPSILON && p_inter.distance_to(l2) < SCALED_EPSILON) { + //intersection! need to reverse! + std::reverse(my_loop.paths.begin() + nearest.idx_polyline_outter + 1, my_loop.paths.begin() + nearest.idx_polyline_outter + child_paths_size + 1); + for (size_t idx = nearest.idx_polyline_outter + 1; idx < nearest.idx_polyline_outter + child_paths_size + 1; idx++) { + my_loop.paths[idx].reverse(); + } + outer_start = &my_loop.paths[nearest.idx_polyline_outter]; + outer_end = &my_loop.paths[nearest.idx_polyline_outter + child_paths_size + 1]; + inner_start = &my_loop.paths[nearest.idx_polyline_outter + 1]; + inner_end = &my_loop.paths[nearest.idx_polyline_outter + child_paths_size]; + } + + } + + //now add extrusionPAths to connect the two loops + ExtrusionPaths travel_path_begin;// (ExtrusionRole::erNone, 0, outer_start->width, outer_start->height); + //travel_path_begin.extruder_id = -1; + ExtrusionPaths travel_path_end;// (ExtrusionRole::erNone, 0, outer_end->width, outer_end->height); + //travel_path_end.extruder_id = -1; + double dist_travel = outer_start->polyline.points.back().distance_to(inner_start->polyline.points.front()); + if (dist_travel > max_width_extrusion * 10) { + std::cout << "ERROR: dist travel is to high : " << unscale(dist_travel) + << " from " << unscale(outer_start->polyline.points.back().x) << ":" << unscale(outer_start->polyline.points.back().y) + << " to " << unscale(inner_start->polyline.points.front().x) << ":" << unscale(inner_start->polyline.points.front().y) + << "\n"; + std::cout << log_bef.str(); + //std::cout << log.str(); + } + if (dist_travel > max_width_extrusion*1.5) { + travel_path_begin.emplace_back(ExtrusionRole::erPerimeter, outer_start->mm3_per_mm, outer_start->width, outer_start->height); + travel_path_begin.emplace_back(ExtrusionRole::erNone, 0, outer_start->width, outer_start->height); + travel_path_begin.emplace_back(ExtrusionRole::erPerimeter, outer_start->mm3_per_mm, outer_start->width, outer_start->height); + travel_path_begin[0].extruder_id = -1; + travel_path_begin[1].extruder_id = -1; + travel_path_begin[2].extruder_id = -1; + Line line(outer_start->polyline.points.back(), inner_start->polyline.points.front()); + Point p_dist_cut_extrude = (line.b - line.a); + p_dist_cut_extrude.x = (coord_t)(p_dist_cut_extrude.x * ((double)max_width_extrusion) / (line.length() * 2)); + p_dist_cut_extrude.y = (coord_t)(p_dist_cut_extrude.y * ((double)max_width_extrusion) / (line.length() * 2)); + //extrude a bit after the turn, to close the loop + Point p_start_travel = line.a; + p_start_travel += p_dist_cut_extrude; + travel_path_begin[0].polyline.append(outer_start->polyline.points.back()); + travel_path_begin[0].polyline.append(p_start_travel); + //extrude a bit before the final turn, to close the loop + Point p_end_travel = line.b; + p_end_travel -= p_dist_cut_extrude; + travel_path_begin[2].polyline.append(p_end_travel); + travel_path_begin[2].polyline.append(inner_start->polyline.points.front()); + //fake travel in the middle + travel_path_begin[1].polyline.append(p_start_travel); + travel_path_begin[1].polyline.append(p_end_travel); + } else { + // the path is small enough to extrude all along. + double flow_mult = 1; + if (dist_travel > max_width_extrusion) { + // the path is a bit too long, reduce the extrusion flow. + flow_mult = max_width_extrusion / dist_travel; + } + travel_path_begin.emplace_back(ExtrusionRole::erPerimeter, outer_start->mm3_per_mm * flow_mult, (float)(outer_start->width * flow_mult), outer_start->height); + travel_path_begin[0].extruder_id = -1; + travel_path_begin[0].polyline.append(outer_start->polyline.points.back()); + travel_path_begin[0].polyline.append(inner_start->polyline.points.front()); + } + dist_travel = inner_end->polyline.points.back().distance_to(outer_end->polyline.points.front()); + if (dist_travel > max_width_extrusion*1.5) { + travel_path_end.emplace_back(ExtrusionRole::erPerimeter, outer_end->mm3_per_mm, outer_end->width, outer_end->height); + travel_path_end.emplace_back(ExtrusionRole::erNone, 0, outer_end->width, outer_end->height); + travel_path_end.emplace_back(ExtrusionRole::erPerimeter, outer_end->mm3_per_mm, outer_end->width, outer_end->height); + travel_path_end[0].extruder_id = -1; + travel_path_end[1].extruder_id = -1; + travel_path_end[2].extruder_id = -1; + Line line(inner_end->polyline.points.back(), outer_end->polyline.points.front()); + Point p_dist_cut_extrude = (line.b - line.a); + p_dist_cut_extrude.x = (coord_t)(p_dist_cut_extrude.x * ((double)max_width_extrusion) / (line.length() * 2)); + p_dist_cut_extrude.y = (coord_t)(p_dist_cut_extrude.y * ((double)max_width_extrusion) / (line.length() * 2)); + //extrude a bit after the turn, to close the loop + Point p_start_travel_2 = line.a; + p_start_travel_2 += p_dist_cut_extrude; + travel_path_end[0].polyline.append(inner_end->polyline.points.back()); + travel_path_end[0].polyline.append(p_start_travel_2); + //extrude a bit before the final turn, to close the loop + Point p_end_travel_2 = line.b; + p_end_travel_2 -= p_dist_cut_extrude; + travel_path_end[2].polyline.append(p_end_travel_2); + travel_path_end[2].polyline.append(outer_end->polyline.points.front()); + //fake travel in the middle + travel_path_end[1].polyline.append(p_start_travel_2); + travel_path_end[1].polyline.append(p_end_travel_2); + } else { + // the path is small enough to extrude all along. + double flow_mult = 1; + if (dist_travel > max_width_extrusion) { + // the path is a bit too long, reduce the extrusion flow. + flow_mult = max_width_extrusion / dist_travel; + } + travel_path_end.emplace_back(ExtrusionRole::erPerimeter, outer_end->mm3_per_mm * flow_mult, (float)(outer_end->width * flow_mult), outer_end->height); + travel_path_end[0].extruder_id = -1; + travel_path_end[0].polyline.append(inner_end->polyline.points.back()); + travel_path_end[0].polyline.append(outer_end->polyline.points.front()); + } + //check if we add path or reuse bits + if (outer_start->polyline.points.size() == 1) { + outer_start->polyline = travel_path_begin.front().polyline; + travel_path_begin.erase(travel_path_begin.begin()); + outer_start->extruder_id = -1; + } else if (outer_end->polyline.points.size() == 1) { + outer_end->polyline = travel_path_end.back().polyline; + travel_path_end.erase(travel_path_end.end() - 1); + outer_end->extruder_id = -1; + } + //add paths into my_loop => after that all ref are wrong! + for (int i = travel_path_end.size() - 1; i >= 0; i--) { + my_loop.paths.insert(my_loop.paths.begin() + nearest.idx_polyline_outter + child_paths_size + 1, travel_path_end[i]); + path_is_ccw.insert(path_is_ccw.begin() + nearest.idx_polyline_outter + child_paths_size + 1, cut_path_is_ccw); + } + for (int i = travel_path_begin.size() - 1; i >= 0; i--) { + my_loop.paths.insert(my_loop.paths.begin() + nearest.idx_polyline_outter + 1, travel_path_begin[i]); + path_is_ccw.insert(path_is_ccw.begin() + nearest.idx_polyline_outter + 1, cut_path_is_ccw); + } + } + + //update for next loop + childs.erase(childs.begin() + nearest.idx_children); + } + + return my_loop; +} + + ExtrusionEntityCollection PerimeterGenerator::_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const { // this value determines granularity of adaptive width, as G-code does not allow diff --git a/xs/src/libslic3r/PerimeterGenerator.hpp b/xs/src/libslic3r/PerimeterGenerator.hpp index f89311c1995..57d5f7d1350 100644 --- a/xs/src/libslic3r/PerimeterGenerator.hpp +++ b/xs/src/libslic3r/PerimeterGenerator.hpp @@ -8,9 +8,18 @@ #include "Polygon.hpp" #include "PrintConfig.hpp" #include "SurfaceCollection.hpp" +#include "ExtrusionEntityCollection.hpp" namespace Slic3r { +struct PerimeterIntersectionPoint { + size_t idx_children; + Point child_best; + Point outter_best; + size_t idx_polyline_outter; + coord_t distance; +}; + // Hierarchy of perimeters. class PerimeterGeneratorLoop { public: @@ -89,9 +98,11 @@ class PerimeterGenerator { double _mm3_per_mm; double _mm3_per_mm_overhang; Polygons _lower_slices_p; - + ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const; + ExtrusionLoop _traverse_and_join_loops(const PerimeterGeneratorLoop &loop, const PerimeterGeneratorLoops &childs, const Point entryPoint) const; + ExtrusionLoop _extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, const Point entryPoint, const Line &direction = Line(Point(0,0),Point(0,0))) const; ExtrusionEntityCollection _variable_width (const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const; }; diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp index 347966c03a6..ff1f3ecc930 100644 --- a/xs/src/libslic3r/Point.hpp +++ b/xs/src/libslic3r/Point.hpp @@ -46,6 +46,8 @@ class Point Point& operator+=(const Point& rhs) { this->x += rhs.x; this->y += rhs.y; return *this; } Point& operator-=(const Point& rhs) { this->x -= rhs.x; this->y -= rhs.y; return *this; } Point& operator*=(const coord_t& rhs) { this->x *= rhs; this->y *= rhs; return *this; } + //Point& operator=(const Point& p) { this->x = p.x; this->y = p.y; return *this; } + //Point& operator=(Point&& p) { this->x = p.x; this->y = p.y; return *this; } std::string wkt() const; std::string dump_perl() const; diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index b76bb780504..c01f4a52f28 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -394,10 +394,18 @@ PrintConfigDef::PrintConfigDef() def->label = L("External perimeters first"); def->category = L("Layers and Perimeters"); def->tooltip = L("Print contour perimeters from the outermost one to the innermost one " - "instead of the default inverse order."); + "instead of the default inverse order."); def->cli = "external-perimeters-first!"; def->default_value = new ConfigOptionBool(false); + def = this->add("perimeter_loop", coBool); + def->label = L("Looping perimeters"); + def->category = L("Layers and Perimeters"); + def->tooltip = L("Join the perimeters to create only one continuous extrusion without any z-hop." + " Long inside travel (from external to holes) are not extruded to give some place to the infill."); + def->cli = "loop-perimeter!"; + def->default_value = new ConfigOptionBool(false); + def = this->add("extra_perimeters", coBool); def->label = L("Extra perimeters if needed"); def->category = L("Layers and Perimeters"); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 121af0e27ac..1df32f77b2a 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -431,6 +431,7 @@ class PrintRegionConfig : public StaticPrintConfig ConfigOptionFloatOrPercent external_perimeter_extrusion_width; ConfigOptionFloatOrPercent external_perimeter_speed; ConfigOptionBool external_perimeters_first; + ConfigOptionBool perimeter_loop; ConfigOptionBool extra_perimeters; ConfigOptionBool only_one_perimeter_top; ConfigOptionFloat fill_angle; @@ -482,6 +483,7 @@ class PrintRegionConfig : public StaticPrintConfig OPT_PTR(external_perimeter_extrusion_width); OPT_PTR(external_perimeter_speed); OPT_PTR(external_perimeters_first); + OPT_PTR(perimeter_loop); OPT_PTR(extra_perimeters); OPT_PTR(only_one_perimeter_top); OPT_PTR(fill_angle); diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 6566c262bc9..b762e943724 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -156,6 +156,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector& Preset::print_options() "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "only_one_perimeter_top", "single_extruder_multi_material_priming", "compatible_printers", "compatible_printers_condition", "inherits", "infill_dense", "infill_dense_algo", "no_perimeter_unsupported", "min_perimeter_unsupported", "noperi_bridge_only", - "support_material_solid_first_layer" + "support_material_solid_first_layer", "perimeter_loop" }; return s_opts; } diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp index b2d608aa5f0..07a1d2b26ff 100644 --- a/xs/src/slic3r/GUI/Tab.cpp +++ b/xs/src/slic3r/GUI/Tab.cpp @@ -819,8 +819,9 @@ void TabPrint::build() optgroup->append_line(line); optgroup = page->new_optgroup(_(L("Advanced"))); - optgroup->append_single_option_line("seam_position"); - optgroup->append_single_option_line("external_perimeters_first"); + optgroup->append_single_option_line("seam_position"); + optgroup->append_single_option_line("external_perimeters_first"); + optgroup->append_single_option_line("perimeter_loop"); page = add_options_page(_(L("Infill")), "infill.png"); optgroup = page->new_optgroup(_(L("Infill"))); @@ -1168,7 +1169,7 @@ void TabPrint::update() bool have_perimeters = m_config->opt_int("perimeters") > 0; for (auto el : {"extra_perimeters", "only_one_perimeter_top", "ensure_vertical_shell_thickness", "thin_walls", "overhangs", "seam_position", "external_perimeters_first", "external_perimeter_extrusion_width", - "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" }) + "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "perimeter_loop" }) get_field(el)->toggle(have_perimeters); bool have_no_perimeter_unsupported = have_perimeters && m_config->opt_bool("no_perimeter_unsupported"); From d7056e539450df5e2a728abb3c3e29190fb08ff4 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 16 Oct 2018 15:31:47 +0200 Subject: [PATCH 3/3] bug fix for support generation (when ExtrusionEntityCollection are inside the collection instead of extrusionPath) --- xs/src/libslic3r/SupportMaterial.cpp | 30 +++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index 2dcf304817a..15d39fadb70 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -1938,8 +1938,8 @@ struct MyLayerExtruded *this->m_polygons_to_extrude = union_(*this->m_polygons_to_extrude, true); } // 2) Merge the extrusions. - this->extrusions.insert(this->extrusions.end(), other.extrusions.begin(), other.extrusions.end()); - other.extrusions.clear(); + this->extrusions.entities.insert(this->extrusions.entities.end(), other.extrusions.entities.begin(), other.extrusions.entities.end()); + other.extrusions.entities.clear(); // 3) Merge the infill polygons. Slic3r::polygons_append(this->layer->polygons, std::move(other.layer->polygons)); this->layer->polygons = union_(this->layer->polygons, true); @@ -1954,7 +1954,7 @@ struct MyLayerExtruded // The source layer. It carries the height and extrusion type (bridging / non bridging, extrusion height). PrintObjectSupportMaterial::MyLayer *layer; // Collect extrusions. They will be exported sorted by the bottom height. - ExtrusionEntitiesPtr extrusions; + ExtrusionEntityCollection extrusions; // In case the extrusions are non-empty, m_polygons_to_extrude may contain the rest areas yet to be filled by additional support. // This is useful mainly for the loop interfaces, which are generated before the zig-zag infills. Polygons *m_polygons_to_extrude; @@ -2188,7 +2188,7 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const // Transform loops into ExtrusionPath objects. extrusion_entities_append_paths( - top_contact_layer.extrusions, + top_contact_layer.extrusions.entities, STDMOVE(loop_lines), erSupportMaterialInterface, flow.mm3_per_mm(), flow.width, flow.height); } @@ -2215,7 +2215,7 @@ static std::string dbg_index_to_color(int idx) // to stick too firmly to the object. void modulate_extrusion_by_overlapping_layers( // Extrusions generated for this_layer. - ExtrusionEntitiesPtr &extrusions_in_out, + ExtrusionEntityCollection &extrusions_in_out, const PrintObjectSupportMaterial::MyLayer &this_layer, // Multiple layers overlapping with this_layer, sorted bottom up. const PrintObjectSupportMaterial::MyLayersPtr &overlapping_layers) @@ -2225,10 +2225,12 @@ void modulate_extrusion_by_overlapping_layers( // The extrusions do not overlap with any other extrusion. return; + ExtrusionEntityCollection flatten_extrusions_in_out = extrusions_in_out.flatten(); + // Get the initial extrusion parameters. - ExtrusionPath *extrusion_path_template = dynamic_cast(extrusions_in_out.front()); + ExtrusionPath *extrusion_path_template = dynamic_cast(flatten_extrusions_in_out.entities.front()); assert(extrusion_path_template != nullptr); - ExtrusionRole extrusion_role = extrusion_path_template->role(); + ExtrusionRole extrusion_role = extrusion_path_template->role(); float extrusion_width = extrusion_path_template->width; struct ExtrusionPathFragment @@ -2301,7 +2303,7 @@ void modulate_extrusion_by_overlapping_layers( // Collect the paths of this_layer. { Polylines &polylines = path_fragments.back().polylines; - for (ExtrusionEntitiesPtr::const_iterator it = extrusions_in_out.begin(); it != extrusions_in_out.end(); ++ it) { + for (ExtrusionEntitiesPtr::const_iterator it = flatten_extrusions_in_out.entities.begin(); it != flatten_extrusions_in_out.entities.end(); ++it) { ExtrusionPath *path = dynamic_cast(*it); assert(path != nullptr); polylines.emplace_back(Polyline(std::move(path->polyline))); @@ -2436,18 +2438,18 @@ void modulate_extrusion_by_overlapping_layers( if (!multipath.paths.empty()) { if (multipath.paths.size() == 1) { // This path was not fragmented. - extrusions_in_out.push_back(new ExtrusionPath(std::move(multipath.paths.front()))); + extrusions_in_out.entities.push_back(new ExtrusionPath(std::move(multipath.paths.front()))); } else { // This path was fragmented. Copy the collection as a whole object, so the order inside the collection will not be changed // during the chaining of extrusions_in_out. - extrusions_in_out.push_back(new ExtrusionMultiPath(std::move(multipath))); + extrusions_in_out.entities.push_back(new ExtrusionMultiPath(std::move(multipath))); } } } // If there are any non-consumed fragments, add them separately. //FIXME this shall not happen, if the Clipper works as expected and all paths split to fragments could be re-connected. for (auto it_fragment = path_fragments.begin(); it_fragment != path_fragments.end(); ++ it_fragment) - extrusion_entities_append_paths(extrusions_in_out, std::move(it_fragment->polylines), extrusion_role, it_fragment->mm3_per_mm, it_fragment->width, it_fragment->height); + extrusion_entities_append_paths(extrusions_in_out.entities, std::move(it_fragment->polylines), extrusion_role, it_fragment->mm3_per_mm, it_fragment->width, it_fragment->height); } void PrintObjectSupportMaterial::generate_toolpaths( @@ -2742,7 +2744,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( } fill_expolygons_generate_paths( // Destination - layer_ex.extrusions, + layer_ex.extrusions.entities, // Regions to fill union_ex(layer_ex.polygons_to_extrude(), true), // Filler and its parameters @@ -2794,13 +2796,13 @@ void PrintObjectSupportMaterial::generate_toolpaths( // TODO: use offset2_ex() to_infill = offset_ex(to_infill, - 0.4 * float(flow.scaled_spacing())); extrusion_entities_append_paths( - base_layer.extrusions, + base_layer.extrusions.entities, to_polylines(STDMOVE(to_infill_polygons)), erSupportMaterial, flow.mm3_per_mm(), flow.width, flow.height); } fill_expolygons_generate_paths( // Destination - base_layer.extrusions, + base_layer.extrusions.entities, // Regions to fill STDMOVE(to_infill), // Filler and its parameters