mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-12 23:08:59 +08:00
Merge branch 'master_slic3rPE_PR'
This commit is contained in:
commit
280bb5dc15
@ -196,9 +196,10 @@ public:
|
||||
// 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 @@ public:
|
||||
// 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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -47,6 +47,7 @@ public:
|
||||
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
|
||||
|
@ -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;
|
||||
}*/
|
||||
|
@ -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<double>::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
|
||||
|
@ -76,6 +76,8 @@ public:
|
||||
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);
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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 @@ private:
|
||||
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;
|
||||
};
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
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;
|
||||
|
@ -395,10 +395,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");
|
||||
|
@ -433,6 +433,7 @@ public:
|
||||
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;
|
||||
@ -485,6 +486,7 @@ protected:
|
||||
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);
|
||||
|
@ -157,6 +157,7 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector<t_config_
|
||||
|| opt_key == "infill_overlap"
|
||||
|| opt_key == "thin_walls"
|
||||
|| opt_key == "external_perimeters_first"
|
||||
|| opt_key == "perimeter_loop"
|
||||
|| opt_key == "no_perimeter_unsupported"
|
||||
|| opt_key == "min_perimeter_unsupported"
|
||||
|| opt_key == "noperi_bridge_only") {
|
||||
|
@ -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<ExtrusionPath*>(extrusions_in_out.front());
|
||||
ExtrusionPath *extrusion_path_template = dynamic_cast<ExtrusionPath*>(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<ExtrusionPath*>(*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
|
||||
|
@ -307,7 +307,7 @@ const std::vector<std::string>& 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", "exact_last_layer_height"
|
||||
"support_material_solid_first_layer", "exact_last_layer_height", "perimeter_loop"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
@ -821,8 +821,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")));
|
||||
@ -1194,7 +1195,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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user