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:
Diffstat (limited to 'xs/src/libslic3r/PerimeterGenerator.cpp')
-rw-r--r--xs/src/libslic3r/PerimeterGenerator.cpp592
1 files changed, 590 insertions, 2 deletions
diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp
index 7218e028f..11e9fd12a 100644
--- a/xs/src/libslic3r/PerimeterGenerator.cpp
+++ b/xs/src/libslic3r/PerimeterGenerator.cpp
@@ -5,9 +5,33 @@
#include "Geometry.hpp"
#include <cmath>
#include <cassert>
+#include <vector>
+
+#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 <algorithm>
+#include <cassert>
+#include <list>
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) << " <? " << 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 = nearest_p;
+ intersect.child_best = p;
+ }
+ }
+ }
+ }
+ return intersect;
+}
+
+
+int id = 0;
+ExtrusionLoop
+PerimeterGenerator::_extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, const Point entry_point, const Line &direction) const
+{
+
+ const int my_id = ++id;
+ bool need_to_reverse = false;
+ Polyline initial_polyline;
+ const coord_t dist_cut = (coord_t)scale_(this->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<PerimeterPolylineNode> 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<bool> 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<PerimeterGeneratorLoop> 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