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:
authorsupermerill <merill@free.fr>2021-12-11 23:45:48 +0300
committersupermerill <merill@free.fr>2021-12-11 23:45:48 +0300
commit0d84565b5a34aa1e2b6b14d2cfb63c50449a00b1 (patch)
treef27168ff2e6d6eb438b4ed57ad019def887a92ff
parenteaa52a4d13600d6aac321742eb75c2b28b62351c (diff)
parentb1e044855e1f38a5b177ce9b58d3d09cef89c3f1 (diff)
Merge branch 'stable'2.3.57.7
-rw-r--r--resources/ui_layout/print.ui1
-rw-r--r--src/libslic3r/ClipperUtils.cpp2
-rw-r--r--src/libslic3r/ExtrusionEntity.cpp16
-rw-r--r--src/libslic3r/ExtrusionEntity.hpp2
-rw-r--r--src/libslic3r/ExtrusionEntityCollection.cpp4
-rw-r--r--src/libslic3r/ExtrusionEntityCollection.hpp20
-rw-r--r--src/libslic3r/Fill/Fill.cpp24
-rw-r--r--src/libslic3r/Fill/FillBase.cpp6
-rw-r--r--src/libslic3r/Fill/FillConcentric.cpp4
-rw-r--r--src/libslic3r/Fill/FillGyroid.cpp24
-rw-r--r--src/libslic3r/Fill/FillRectilinear.cpp16
-rw-r--r--src/libslic3r/Fill/FillSmooth.cpp4
-rw-r--r--src/libslic3r/GCode.cpp46
-rw-r--r--src/libslic3r/Line.hpp2
-rw-r--r--src/libslic3r/MedialAxis.cpp214
-rw-r--r--src/libslic3r/MedialAxis.hpp2
-rw-r--r--src/libslic3r/PerimeterGenerator.cpp22
-rw-r--r--src/libslic3r/Preset.cpp3
-rw-r--r--src/libslic3r/Print.cpp9
-rw-r--r--src/libslic3r/PrintConfig.cpp13
-rw-r--r--src/libslic3r/PrintConfig.hpp2
-rw-r--r--tests/libslic3r/test_amf.cpp21
-rw-r--r--tests/libslic3r/test_clipper_utils.cpp14
-rw-r--r--tests/libslic3r/test_elephant_foot_compensation.cpp22
-rw-r--r--tests/libslic3r/test_geometry.cpp89
25 files changed, 421 insertions, 161 deletions
diff --git a/resources/ui_layout/print.ui b/resources/ui_layout/print.ui
index b5f893b70..622c612b8 100644
--- a/resources/ui_layout/print.ui
+++ b/resources/ui_layout/print.ui
@@ -83,6 +83,7 @@ group:Layer height
setting:first_layer_height
group:Filtering
setting:resolution
+ setting:resolution_internal
setting:model_precision
setting:slice_closing_radius
group:Modifying slices
diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp
index 431c4ed0f..078c2d3f2 100644
--- a/src/libslic3r/ClipperUtils.cpp
+++ b/src/libslic3r/ClipperUtils.cpp
@@ -231,7 +231,7 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType
co.ArcTolerance = miterLimit;
else
co.MiterLimit = miterLimit;
- double delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
+ double delta_scaled = delta * double(CLIPPER_OFFSET_SCALE);
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
co.AddPaths(input, joinType, endType);
ClipperLib::Paths retval;
diff --git a/src/libslic3r/ExtrusionEntity.cpp b/src/libslic3r/ExtrusionEntity.cpp
index 6b0611cca..250359aef 100644
--- a/src/libslic3r/ExtrusionEntity.cpp
+++ b/src/libslic3r/ExtrusionEntity.cpp
@@ -213,21 +213,25 @@ void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang)
this->split_at_vertex(p);
}
-void ExtrusionLoop::clip_end(double distance, ExtrusionPaths* paths) const
+ExtrusionPaths clip_end(ExtrusionPaths& paths, double distance)
{
- *paths = this->paths;
+ ExtrusionPaths removed;
- while (distance > 0 && !paths->empty()) {
- ExtrusionPath &last = paths->back();
+ while (distance > 0 && !paths.empty()) {
+ ExtrusionPath& last = paths.back();
+ removed.push_back(last);
double len = last.length();
if (len <= distance) {
- paths->pop_back();
+ paths.pop_back();
distance -= len;
} else {
last.polyline.clip_end(distance);
+ removed.back().polyline.clip_start(removed.back().polyline.length() - distance);
break;
}
}
+ std::reverse(removed.begin(), removed.end());
+ return removed;
}
bool ExtrusionLoop::has_overhang_point(const Point &point) const
@@ -376,7 +380,7 @@ void ExtrusionPrinter::use(const ExtrusionEntityCollection &collection) {
if (i != 0) ss << ",";
collection.entities[i]->visit(*this);
}
- if(collection.no_sort) ss<<", no_sort=true";
+ if(!collection.can_sort()) ss<<", no_sort=true";
ss << "}";
}
diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp
index 5369998cf..36198f125 100644
--- a/src/libslic3r/ExtrusionEntity.hpp
+++ b/src/libslic3r/ExtrusionEntity.hpp
@@ -279,6 +279,7 @@ protected:
ExtrusionRole m_role;
};
typedef std::vector<ExtrusionPath> ExtrusionPaths;
+ExtrusionPaths clip_end(ExtrusionPaths& paths, double distance);
class ExtrusionPath3D : public ExtrusionPath {
public:
@@ -451,7 +452,6 @@ public:
double length() const override;
bool split_at_vertex(const Point &point);
void split_at(const Point &point, bool prefer_non_overhang);
- void clip_end(double distance, ExtrusionPaths* paths) const;
// Test, whether the point is extruded by a bridging flow.
// This used to be used to avoid placing seams on overhangs, but now the EdgeGrid is used instead.
bool has_overhang_point(const Point &point) const;
diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp
index c31b06966..1dd41f67f 100644
--- a/src/libslic3r/ExtrusionEntityCollection.cpp
+++ b/src/libslic3r/ExtrusionEntityCollection.cpp
@@ -61,7 +61,7 @@ void ExtrusionEntityCollection::reverse()
{
// Don't reverse it if it's a loop, as it doesn't change anything in terms of elements ordering
// and caller might rely on winding order
- if (!ptr->can_reverse())
+ if (ptr->can_reverse() && !ptr->is_loop())
ptr->reverse();
}
std::reverse(this->entities.begin(), this->entities.end());
@@ -151,7 +151,7 @@ ExtrusionEntityCollection ExtrusionEntityCollection::flatten(bool preserve_order
}
void
FlatenEntities::use(const ExtrusionEntityCollection &coll) {
- if ((coll.no_sort || this->to_fill.no_sort) && preserve_ordering) {
+ if ((!coll.can_sort() || !this->to_fill.can_sort()) && preserve_ordering) {
FlatenEntities unsortable(coll, preserve_ordering);
for (const ExtrusionEntity* entity : coll.entities) {
entity->visit(unsortable);
diff --git a/src/libslic3r/ExtrusionEntityCollection.hpp b/src/libslic3r/ExtrusionEntityCollection.hpp
index 08d2fddba..3e625eeeb 100644
--- a/src/libslic3r/ExtrusionEntityCollection.hpp
+++ b/src/libslic3r/ExtrusionEntityCollection.hpp
@@ -24,6 +24,11 @@ inline ExtrusionEntitiesPtr filter_by_extrusion_role(const ExtrusionEntitiesPtr
class ExtrusionEntityCollection : public ExtrusionEntity
{
+private:
+ // set to tru to forbit to reorder and reverse all entities indie us.
+ bool no_sort;
+ // even if no_sort, allow to reverse() us (and our entities if they allow it, but they should)
+ bool no_reverse;
public:
virtual ExtrusionEntityCollection* clone() const override { return new ExtrusionEntityCollection(*this); }
// Create a new object, initialize it with this object using the move semantics.
@@ -33,14 +38,13 @@ public:
/// Owned ExtrusionEntities and descendent ExtrusionEntityCollections.
/// Iterating over this needs to check each child to see if it, too is a collection.
ExtrusionEntitiesPtr entities; // we own these entities
- bool no_sort;
- ExtrusionEntityCollection(): no_sort(false) {}
- ExtrusionEntityCollection(const ExtrusionEntityCollection &other) : no_sort(other.no_sort) { this->append(other.entities); }
- ExtrusionEntityCollection(ExtrusionEntityCollection &&other) : entities(std::move(other.entities)), no_sort(other.no_sort) {}
+ ExtrusionEntityCollection(): no_sort(false), no_reverse(false) {}
+ ExtrusionEntityCollection(const ExtrusionEntityCollection &other) : no_sort(other.no_sort), no_reverse(other.no_reverse) { this->append(other.entities); }
+ ExtrusionEntityCollection(ExtrusionEntityCollection &&other) : entities(std::move(other.entities)), no_sort(other.no_sort), no_reverse(other.no_reverse) {}
explicit ExtrusionEntityCollection(const ExtrusionPaths &paths);
ExtrusionEntityCollection& operator=(const ExtrusionEntityCollection &other);
ExtrusionEntityCollection& operator=(ExtrusionEntityCollection &&other)
- { this->entities = std::move(other.entities); this->no_sort = other.no_sort; return *this; }
+ { this->entities = std::move(other.entities); this->no_sort = other.no_sort; this->no_reverse = other.no_reverse; return *this; }
~ExtrusionEntityCollection() { clear(); }
/// Operator to convert and flatten this collection to a single vector of ExtrusionPaths.
@@ -55,7 +59,9 @@ public:
}
return out;
}
- bool can_reverse() const override { return !this->no_sort; }
+ void set_can_sort_reverse(bool sort, bool reverse) { this->no_sort = !sort; this->no_reverse = !reverse; }
+ bool can_sort() const { return !this->no_sort; }
+ bool can_reverse() const override { return can_sort() || !this->no_reverse; }
bool empty() const { return this->entities.empty(); }
void clear();
void swap (ExtrusionEntityCollection &c);
@@ -152,7 +158,7 @@ class FlatenEntities : public ExtrusionVisitorConst {
public:
FlatenEntities(bool preserve_ordering) : preserve_ordering(preserve_ordering) {}
FlatenEntities(ExtrusionEntityCollection pattern, bool preserve_ordering) : preserve_ordering(preserve_ordering) {
- to_fill.no_sort = pattern.no_sort;
+ to_fill.set_can_sort_reverse(pattern.can_sort(), pattern.can_reverse());
}
ExtrusionEntityCollection get() {
return to_fill;
diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp
index d09a9b9b6..0639f95ab 100644
--- a/src/libslic3r/Fill/Fill.cpp
+++ b/src/libslic3r/Fill/Fill.cpp
@@ -413,9 +413,9 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
m_regions[region_id]->fills.append(fills_by_priority[0]->entities);
delete fills_by_priority[0];
} else {
- m_regions[region_id]->fills.no_sort = true;
+ m_regions[region_id]->fills.set_can_sort_reverse(false, false);
ExtrusionEntityCollection* eec = new ExtrusionEntityCollection();
- eec->no_sort = true;
+ eec->set_can_sort_reverse(false, false);
m_regions[region_id]->fills.entities.push_back(eec);
for (ExtrusionEntityCollection* per_priority : fills_by_priority) {
if (!per_priority->entities.empty())
@@ -486,6 +486,8 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
surface_fill.params.flow = Flow::new_from_spacing((float)f->get_spacing(), surface_fill.params.flow.nozzle_diameter, (float)surface_fill.params.flow.height, overlap, surface_fill.params.flow.bridge);
}
+ //union with safety offset to avoid separation from the appends of different surface with same settings.
+ surface_fill.expolygons = union_ex(surface_fill.expolygons, true);
for (ExPolygon &expoly : surface_fill.expolygons) {
//set overlap polygons
@@ -508,7 +510,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
//adjust the bridge density
if (surface_fill.params.flow.bridge && surface_fill.params.density > 0.99 /*&& layerm->region()->config().bridge_overlap.get_abs_value(1) != 1*/) {
- ////varies the overlap to have teh best coverage for the bridge
+ ////varies the overlap to have the best coverage for the bridge
//surface_fill.params.density *= float(layerm->region()->config().bridge_overlap.get_abs_value(1));
double min_spacing = 0.999 * surface_fill.params.spacing / surface_fill.params.config->bridge_overlap.get_abs_value(surface_fill.params.density);
double max_spacing = 1.001 * surface_fill.params.spacing / surface_fill.params.config->bridge_overlap_min.get_abs_value(surface_fill.params.density);
@@ -516,9 +518,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
if (min_spacing < max_spacing * 1.01) {
// create a bouding box of the rotated surface
coord_t bounding_box_size_x = 0;
- Polygon poly = surface_fill.surface.expolygon.contour;
coord_t bounding_box_min_x = 0;
- poly.rotate(PI / 2 - (surface_fill.params.bridge_angle < 0 ? surface_fill.params.angle : surface_fill.params.bridge_angle));
ExPolygons expolys;
if (surface_fill.params.bridge_angle > 0 && !f->no_overlap_expolygons.empty()) {
//take only the no-overlap area
@@ -530,7 +530,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
bool first = true;
for (ExPolygon& expoly : expolys) {
expoly.holes.clear();
- expoly.rotate(PI / 2 - (surface_fill.params.bridge_angle < 0 ? surface_fill.params.angle : surface_fill.params.bridge_angle));
+ expoly.rotate(PI / 2 + (surface_fill.params.bridge_angle < 0 ? surface_fill.params.angle : surface_fill.params.bridge_angle));
if (first) {
bb = expoly.contour.bounding_box();
first = false;
@@ -558,6 +558,8 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
surface_fill.params.density = surface_fill.params.config->bridge_overlap.get_abs_value(surface_fill.params.density);
}
}
+ Polygon poly = surface_fill.surface.expolygon.contour;
+ poly.rotate(PI / 2 + (surface_fill.params.bridge_angle < 0 ? surface_fill.params.angle : surface_fill.params.bridge_angle));
surface_fill.params.dont_adjust = true;
surface_fill.params.bridge_offset = std::abs(poly.bounding_box().min.x() - bounding_box_min_x);
}
@@ -580,9 +582,9 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
for (LayerRegion *layerm : m_regions)
for (const ExtrusionEntity *thin_fill : layerm->thin_fills.entities) {
ExtrusionEntityCollection *collection = new ExtrusionEntityCollection();
- if (layerm->fills.no_sort && layerm->fills.entities.size() > 0 && layerm->fills.entities[0]->is_collection()) {
+ if (!layerm->fills.can_sort() && layerm->fills.entities.size() > 0 && layerm->fills.entities[0]->is_collection()) {
ExtrusionEntityCollection* no_sort_fill = static_cast<ExtrusionEntityCollection*>(layerm->fills.entities[0]);
- if (no_sort_fill->no_sort && no_sort_fill->entities.size() > 0 && no_sort_fill->entities[0]->is_collection())
+ if (!no_sort_fill->can_sort() && no_sort_fill->entities.size() > 0 && no_sort_fill->entities[0]->is_collection())
static_cast<ExtrusionEntityCollection*>(no_sort_fill->entities[0])->entities.push_back(collection);
} else
layerm->fills.entities.push_back(collection);
@@ -593,7 +595,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
for (LayerRegion *layerm : m_regions)
for (size_t i1 = 0; i1 < layerm->fills.entities.size(); ++i1) {
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i1]) != nullptr);
- if (layerm->fills.no_sort && layerm->fills.entities.size() > 0 && i1 == 0){
+ if (!layerm->fills.can_sort() && layerm->fills.entities.size() > 0 && i1 == 0){
ExtrusionEntityCollection* no_sort_fill = static_cast<ExtrusionEntityCollection*>(layerm->fills.entities[0]);
assert(no_sort_fill != nullptr);
assert(!no_sort_fill->empty());
@@ -601,7 +603,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
ExtrusionEntityCollection* priority_fill = dynamic_cast<ExtrusionEntityCollection*>(no_sort_fill->entities[i2]);
assert(priority_fill != nullptr);
assert(!priority_fill->empty());
- if (no_sort_fill->no_sort) {
+ if (!no_sort_fill->can_sort()) {
for (size_t i3 = 0; i3 < priority_fill->entities.size(); ++i3)
assert(dynamic_cast<ExtrusionEntityCollection*>(priority_fill->entities[i3]) != nullptr);
}
@@ -780,7 +782,7 @@ void Layer::make_ironing()
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
ironing_params.layerm->ironings.entities.push_back(eec);
// Don't sort the ironing infill lines as they are monotonicly ordered.
- eec->no_sort = true;
+ eec->set_can_sort_reverse(false, false);
extrusion_entities_append_paths(
eec->entities, std::move(polylines),
erIroning,
diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp
index 26b73bd25..1e6dff4aa 100644
--- a/src/libslic3r/Fill/FillBase.cpp
+++ b/src/libslic3r/Fill/FillBase.cpp
@@ -211,7 +211,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
// Save into layer.
auto *eec = new ExtrusionEntityCollection();
/// pass the no_sort attribute to the extrusion path
- eec->no_sort = this->no_sort();
+ eec->set_can_sort_reverse(!this->no_sort(), !this->no_sort());
/// add it into the collection
out.push_back(eec);
//get the role
@@ -269,7 +269,7 @@ Fill::do_gap_fill(const ExPolygons& gapfill_areas, const FillParams& params, Ext
}
#endif
- ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, params.flow);
+ ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, params.flow, scale_t(params.config->get_computed_value("resolution_internal")));
//set role if needed
/*if (params.role != erSolidInfill) {
ExtrusionSetRole set_good_role(params.role);
@@ -278,7 +278,7 @@ Fill::do_gap_fill(const ExPolygons& gapfill_areas, const FillParams& params, Ext
//move them into the collection
if (!gap_fill.entities.empty()) {
ExtrusionEntityCollection* coll_gapfill = new ExtrusionEntityCollection();
- coll_gapfill->no_sort = this->no_sort();
+ coll_gapfill->set_can_sort_reverse(!this->no_sort(), !this->no_sort());
coll_gapfill->append(std::move(gap_fill.entities));
coll_out.push_back(coll_gapfill);
}
diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp
index 6da55e454..c8616f42f 100644
--- a/src/libslic3r/Fill/FillConcentric.cpp
+++ b/src/libslic3r/Fill/FillConcentric.cpp
@@ -128,7 +128,7 @@ FillConcentricWGapFill::fill_surface_extrusion(
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection();
- coll_nosort->no_sort = true; //can be sorted inside the pass
+ coll_nosort->set_can_sort_reverse(false, false); //can be sorted inside the pass
extrusion_entities_append_loops(
coll_nosort->entities, loops,
good_role,
@@ -154,7 +154,7 @@ FillConcentricWGapFill::fill_surface_extrusion(
}
}
if (!polylines.empty() && !is_bridge(good_role)) {
- ExtrusionEntityCollection gap_fill = thin_variable_width(polylines, erGapFill, params.flow);
+ ExtrusionEntityCollection gap_fill = thin_variable_width(polylines, erGapFill, params.flow, scale_t(params.config->get_computed_value("resolution_internal")));
//set role if needed
if (good_role != erSolidInfill) {
ExtrusionSetRole set_good_role(good_role);
diff --git a/src/libslic3r/Fill/FillGyroid.cpp b/src/libslic3r/Fill/FillGyroid.cpp
index c51cdf914..0ff0972c5 100644
--- a/src/libslic3r/Fill/FillGyroid.cpp
+++ b/src/libslic3r/Fill/FillGyroid.cpp
@@ -101,13 +101,8 @@ static std::vector<Vec2d> make_one_period(double width, double scaleFactor, doub
return points;
}
-static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double line_spacing, double width, double height)
+static Polylines make_gyroid_waves(coordf_t gridZ, coordf_t scaleFactor, double width, double height, double tolerance)
{
- const double scaleFactor = scale_(line_spacing) / density_adjusted;
-
- // tolerance in scaled units. clamp the maximum tolerance as there's
- // no processing-speed benefit to do so beyond a certain point
- const double tolerance = std::min(line_spacing / 2, FillGyroid::PatternTolerance) / unscale<double>(scaleFactor);
//scale factor for 5% : 8 712 388
// 1z = 10^-6 mm ?
@@ -167,13 +162,22 @@ void FillGyroid::_fill_surface_single(
// align bounding box to a multiple of our grid module
bb.merge(_align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance)));
+ // tolerance in scaled units. clamp the maximum tolerance as there's
+ // no processing-speed benefit to do so beyond a certain point
+ const coordf_t scaleFactor = scale_d(this->get_spacing()) / density_adjusted;
+ const double tolerance_old = std::min(this->get_spacing() / 2, FillGyroid::PatternTolerance) / unscaled(scaleFactor);
+ const double tolerance_old2 = std::min(this->get_spacing() / 2, FillGyroid::PatternTolerance) * density_adjusted / this->get_spacing();
+ const double tolerance = params.config->get_computed_value("resolution_internal") * density_adjusted / this->get_spacing();
+ std::cout << "gyroid tolerance: " << tolerance_old << " == " << tolerance_old2 << " ? "<< tolerance << "\n";
+ std::cout << "this->get_spacing(): " << this->get_spacing() << " , scaleFactor= " << unscaled(scaleFactor) << " , min(spa, 0.2)= " << std::min(this->get_spacing() / 2, FillGyroid::PatternTolerance) << "\n";
+
// generate pattern
Polylines polylines = make_gyroid_waves(
- (double)scale_(this->z),
- density_adjusted,
- this->get_spacing(),
+ scale_d(this->z),
+ scaleFactor,
ceil(bb.size()(0) / distance) + 1.,
- ceil(bb.size()(1) / distance) + 1.);
+ ceil(bb.size()(1) / distance) + 1.,
+ tolerance);
// shift the polyline to the grid origin
for (Polyline &pl : polylines)
diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp
index 598ef50d1..fd53d96a8 100644
--- a/src/libslic3r/Fill/FillRectilinear.cpp
+++ b/src/libslic3r/Fill/FillRectilinear.cpp
@@ -777,7 +777,7 @@ std::vector<SegmentedIntersectionLine> FillRectilinear::_vert_lines_for_polygon(
size_t n_vlines = 1 + (bounding_box.max.x() - bounding_box.min.x() - 10) / line_spacing;
coord_t x0 = bounding_box.min.x();
if (params.flow.bridge && params.bridge_offset >= 0) {
- x0 += params.bridge_offset;
+ x0 += params.bridge_offset;
}else if (params.full_infill())
x0 += (line_spacing + coord_t(SCALED_EPSILON)) / 2;
@@ -3208,7 +3208,7 @@ FillRectilinearPeri::fill_surface_extrusion(const Surface *surface, const FillPa
{
ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection();
//you don't want to sort the extrusions: big infill first, small second
- eecroot->no_sort = true;
+ eecroot->set_can_sort_reverse(false, false);
// === extrude perimeter ===
Polylines polylines_1;
@@ -3231,7 +3231,7 @@ FillRectilinearPeri::fill_surface_extrusion(const Surface *surface, const FillPa
// Save into layer.
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
/// pass the no_sort attribute to the extrusion path
- eec->no_sort = this->no_sort();
+ eec->set_can_sort_reverse(!this->no_sort(), !this->no_sort());
/// add it into the collection
eecroot->entities.push_back(eec);
//get the role
@@ -3263,7 +3263,7 @@ FillRectilinearPeri::fill_surface_extrusion(const Surface *surface, const FillPa
// Save into layer.
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
/// pass the no_sort attribute to the extrusion path
- eec->no_sort = this->no_sort();
+ eec->set_can_sort_reverse(!this->no_sort(), !this->no_sort());
/// add it into the collection
eecroot->entities.push_back(eec);
//get the role
@@ -3365,7 +3365,7 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi
if (!polylines_out.empty()) {
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
/// pass the no_sort attribute to the extrusion path
- eec->no_sort = this->no_sort();
+ eec->set_can_sort_reverse(!this->no_sort(), !this->no_sort());
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
@@ -3489,7 +3489,7 @@ FillRectilinearWGapFill::split_polygon_gap_fill(const Surface &surface, const Fi
void
FillRectilinearWGapFill::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const {
ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection();
- coll_nosort->no_sort = true; //can be sorted inside the pass
+ coll_nosort->set_can_sort_reverse(false, false); //can be sorted inside the pass but thew two pass need to be done one after the other
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
//// remove areas for gapfill
@@ -3558,9 +3558,9 @@ FillRectilinearWGapFill::fill_surface_extrusion(const Surface *surface, const Fi
/// pass the no_sort attribute to the extrusion path
//don't force monotonic if not top or bottom
if (is_monotonic())
- eec->no_sort = true;
+ eec->set_can_sort_reverse(false, false);
else
- eec->no_sort = this->no_sort();
+ eec->set_can_sort_reverse(!this->no_sort(), !this->no_sort());
extrusion_entities_append_paths(
eec->entities, polylines_rectilinear,
diff --git a/src/libslic3r/Fill/FillSmooth.cpp b/src/libslic3r/Fill/FillSmooth.cpp
index 444e61132..2c6f54da8 100644
--- a/src/libslic3r/Fill/FillSmooth.cpp
+++ b/src/libslic3r/Fill/FillSmooth.cpp
@@ -24,7 +24,7 @@ namespace Slic3r {
// Save into layer smoothing path.
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
- eec->no_sort = params.monotonic;
+ eec->set_can_sort_reverse(!params.monotonic, !params.monotonic);
FillParams params_modifided = params;
if (params.config != NULL && idx > 0) params_modifided.density /= (float)params.config->fill_smooth_width.get_abs_value(1);
else if (params.config != NULL && idx == 0) params_modifided.density *= 1;
@@ -131,7 +131,7 @@ namespace Slic3r {
//create root node
ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection();
//you don't want to sort the extrusions: big infill first, small second
- eecroot->no_sort = true;
+ eecroot->set_can_sort_reverse(false, false);
// first infill
FillParams first_pass_params = params;
diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp
index ee6eb01f0..cd4a79af0 100644
--- a/src/libslic3r/GCode.cpp
+++ b/src/libslic3r/GCode.cpp
@@ -2949,13 +2949,23 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
// clip the path to avoid the extruder to get exactly on the first point of the loop;
// if polyline was shorter than the clipping distance we'd get a null polyline, so
// we discard it in that case
- double clip_length = 0;
+ coordf_t clip_length = 0;
+ coordf_t min_clip_length = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)) * 0.15;
if (m_enable_loop_clipping && m_writer.tool_is_extruder())
- clip_length = m_config.seam_gap.get_abs_value(m_writer.tool()->id(), scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
+ clip_length = scale_(m_config.seam_gap.get_abs_value(m_writer.tool()->id(), EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
// get paths
- ExtrusionPaths paths;
- loop.clip_end(clip_length, &paths);
+ ExtrusionPaths paths = loop.paths;
+ ExtrusionPaths clipped;
+ if (clip_length > min_clip_length) {
+ clipped = clip_end(paths, clip_length);
+ clip_end(clipped, min_clip_length);
+ for (ExtrusionPath& ep : clipped)
+ ep.mm3_per_mm = 0;
+ append(paths, clipped);
+ } else {
+ clip_end(paths, clip_length);
+ }
if (paths.empty()) return "";
// apply the small/external? perimeter speed
@@ -3063,7 +3073,9 @@ std::string GCode::extrude_loop_vase(const ExtrusionLoop &original_loop, const s
double e_per_mm_per_height = (path->mm3_per_mm / this->m_layer->height)
* m_writer.tool()->e_per_mm3()
* this->config().print_extrusion_multiplier.get_abs_value(1);
- if (m_writer.extrusion_axis().empty()) e_per_mm_per_height = 0;
+ if (m_writer.extrusion_axis().empty())
+ e_per_mm_per_height = 0;
+ //extrude
{
std::string comment = m_config.gcode_comments ? description : "";
for (const Line &line : path->polyline.lines()) {
@@ -3271,13 +3283,23 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
// clip the path to avoid the extruder to get exactly on the first point of the loop;
// if polyline was shorter than the clipping distance we'd get a null polyline, so
// we discard it in that case
- double clip_length = 0;
+ coordf_t clip_length = 0;
+ coordf_t min_clip_length = scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)) * 0.15;
if (m_enable_loop_clipping && m_writer.tool_is_extruder())
- clip_length = m_config.seam_gap.get_abs_value(m_writer.tool()->id(), scale_(EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
+ clip_length = scale_(m_config.seam_gap.get_abs_value(m_writer.tool()->id(), EXTRUDER_CONFIG_WITH_DEFAULT(nozzle_diameter, 0)));
// get paths
- ExtrusionPaths paths;
- loop.clip_end(clip_length, &paths);
+ ExtrusionPaths paths = loop.paths;
+ ExtrusionPaths clipped;
+ if (clip_length > min_clip_length) {
+ clipped = clip_end(paths, clip_length);
+ clip_end(clipped, min_clip_length);
+ for (ExtrusionPath& ep : clipped)
+ ep.mm3_per_mm = 0;
+ append(paths, clipped);
+ } else {
+ clip_end(paths, clip_length);
+ }
if (paths.empty()) return "";
// apply the small perimeter speed
@@ -3298,7 +3320,6 @@ std::string GCode::extrude_loop(const ExtrusionLoop &original_loop, const std::s
std::string gcode;
for (ExtrusionPaths::iterator path = paths.begin(); path != paths.end(); ++path) {
//path->simplify(SCALED_RESOLUTION); //should already be simplified
- //gcode += this->_extrude(*path, description, speed);
if(path->polyline.points.size()>1)
gcode += extrude_path(*path, description, speed);
}
@@ -3455,7 +3476,7 @@ std::string GCode::extrude_entity(const ExtrusionEntity &entity, const std::stri
}
void GCode::use(const ExtrusionEntityCollection &collection) {
- if (collection.no_sort || collection.role() == erMixed) {
+ if (!collection.can_sort() || collection.role() == erMixed) {
for (const ExtrusionEntity* next_entity : collection.entities) {
next_entity->visit(*this);
}
@@ -4380,7 +4401,8 @@ std::string GCode::toolchange(uint16_t extruder_id, double print_z) {
std::string gcode;
// Process the custom toolchange_gcode. If it is empty, insert just a Tn command.
- const std::string& toolchange_gcode = m_config.toolchange_gcode.value;
+ std::string toolchange_gcode = m_config.toolchange_gcode.value;
+ boost::trim(toolchange_gcode); //remove invisible characters that may compromize the 'toolchange_gcode.empty()'
std::string toolchange_gcode_parsed;
if (!toolchange_gcode.empty() && m_writer.multiple_extruders) {
DynamicConfig config;
diff --git a/src/libslic3r/Line.hpp b/src/libslic3r/Line.hpp
index d93e37e7f..88a9d4db2 100644
--- a/src/libslic3r/Line.hpp
+++ b/src/libslic3r/Line.hpp
@@ -97,7 +97,7 @@ public:
ThickLine(const Point& a, const Point& b) : Line(a, b), a_width(0), b_width(0) {}
ThickLine(const Point& a, const Point& b, double wa, double wb) : Line(a, b), a_width(wa), b_width(wb) {}
- double a_width, b_width;
+ coordf_t a_width, b_width;
};
class Line3
diff --git a/src/libslic3r/MedialAxis.cpp b/src/libslic3r/MedialAxis.cpp
index 1ed1320f7..c44c1d97a 100644
--- a/src/libslic3r/MedialAxis.cpp
+++ b/src/libslic3r/MedialAxis.cpp
@@ -1395,6 +1395,65 @@ MedialAxis::remove_too_thin_points(ThickPolylines& pp)
void
MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size)
{
+ // reduce the flow at the intersection ( + ) points
+ //FIXME: TODO: note that crossings are unnafected right now. they may need a different codepath directly in their method
+ //TODO: unit tests for that.
+ //TODO: never triggered. ther's only the sections passed by crossing fusion that aren't edge-case and it's not treated by this. => comment for now
+ //for each not-endpoint point
+ //std::vector<bool> endpoint_not_used(pp.size() * 2, true);
+ //for (size_t idx_endpoint = 0; idx_endpoint < endpoint_not_used.size(); idx_endpoint++) {
+ // ThickPolyline& polyline = pp[idx_endpoint / 2];
+ // //update endpoint_not_used if not seen before
+ // if (idx_endpoint % 2 == 0 && endpoint_not_used[idx_endpoint]) {
+ // //update
+ // endpoint_not_used[(idx_endpoint / 2)] = !polyline.endpoints.first;
+ // endpoint_not_used[(idx_endpoint / 2) + 1] = endpoint_not_used[(idx_endpoint / 2) + 1] && !polyline.endpoints.second;
+ // }
+ // if (endpoint_not_used[idx_endpoint]) {
+ // int nb_endpoints;
+ // Point pt = idx_endpoint % 2 == 0 ? polyline.first_point() : polyline.last_point();
+ // if (idx_endpoint % 2 == 0 && pt.coincides_with(polyline.last_point())) {
+ // nb_endpoints++;
+ // endpoint_not_used[(idx_endpoint / 2) + 1] = false;
+ // }
+ // //good, now find other points
+ // for (size_t idx_other_pp = (idx_endpoint / 2) + 1; idx_other_pp < pp.size(); idx_other_pp++) {
+ // ThickPolyline& other = pp[idx_other_pp];
+ // if (pt.coincides_with(other.first_point())) {
+ // nb_endpoints++;
+ // endpoint_not_used[idx_other_pp * 2] = false;
+ // }
+ // if (pt.coincides_with(other.last_point())) {
+ // nb_endpoints++;
+ // endpoint_not_used[idx_other_pp * 2 + 1] = false;
+ // }
+ // }
+ // if (nb_endpoints < 3)
+ // continue;
+ // // reduce width accordingly
+ // float reduction = 2.f / nb_endpoints;
+ // std::cout << "reduce " << reduction << " points!\n";
+ // if (idx_endpoint % 2 == 0 ) {
+ // polyline.width.front() *= reduction;
+ // if(pt.coincides_with(polyline.last_point()))
+ // polyline.width.back() *= reduction;
+ // } else {
+ // polyline.width.back() *= reduction;
+ // }
+ // //good, now find other points
+ // for (size_t idx_other_pp = (idx_endpoint / 2) + 1; idx_other_pp < pp.size(); idx_other_pp++) {
+ // ThickPolyline& other = pp[idx_other_pp];
+ // if (pt.coincides_with(other.first_point())) {
+ // other.width.front() *= reduction;
+ // }
+ // if (pt.coincides_with(other.last_point())) {
+ // other.width.back() *= reduction;
+ // }
+ // }
+ // //TODO: restore good width at width dist, or reduce other points up to width dist
+ // }
+ //}
+
//remove too short polyline
bool changes = true;
while (changes) {
@@ -1408,11 +1467,16 @@ MedialAxis::remove_too_short_polylines(ThickPolylines& pp, const coord_t min_siz
// (we can't do this check before endpoints extension and clipping because we don't
// know how long will the endpoints be extended since it depends on polygon thickness
// which is variable - extension will be <= max_width/2 on each side)
- if ((polyline.endpoints.first || polyline.endpoints.second)
- && polyline.length() < max_width / 2) {
- if (shortest_size > polyline.length()) {
- shortest_size = polyline.length();
- shortest_idx = i;
+ if ((polyline.endpoints.first || polyline.endpoints.second)) {
+ coordf_t max_width = max_width / 2;
+ for (coordf_t w : polyline.width)
+ max_width = std::max(max_width, w);
+ if(polyline.length() < max_width) {
+ if (shortest_size > polyline.length()) {
+ shortest_size = polyline.length();
+ shortest_idx = i;
+ }
+
}
}
@@ -1857,6 +1921,7 @@ MedialAxis::build(ThickPolylines &polylines_out)
// svg.draw(pp);
// svg.Close();
//}
+ //TODO: reduce the flow at the intersection ( + ) points on crossing?
concatenate_polylines_with_crossing(pp);
//{
// std::stringstream stri;
@@ -1879,7 +1944,6 @@ MedialAxis::build(ThickPolylines &polylines_out)
// svg.Close();
//}
- //TODO: reduce the flow at the intersection ( + ) points ?
ensure_not_overextrude(pp);
//{
// std::stringstream stri;
@@ -1923,82 +1987,115 @@ MedialAxis::build(ThickPolylines &polylines_out)
}
ExtrusionEntityCollection
-thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow)
+thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow, coord_t resolution_internal)
{
+ assert(resolution_internal > SCALED_EPSILON);
+
// this value determines granularity of adaptive width, as G-code does not allow
// variable extrusion within a single move; this value shall only affect the amount
// of segments, and any pruning shall be performed before we apply this tolerance
- const coord_t tolerance = 4 * SCALED_RESOLUTION;//scale_(0.05);
+ const coord_t tolerance = flow.scaled_width() / 10;//scale_(0.05);
ExtrusionEntityCollection coll;
for (const ThickPolyline &p : polylines) {
ExtrusionPaths paths;
ExtrusionPath path(role);
ThickLines lines = p.thicklines();
-
+
+ coordf_t saved_line_len = 0;
for (int i = 0; i < (int)lines.size(); ++i) {
ThickLine& line = lines[i];
-
+
const coordf_t line_len = line.length();
- if (line_len < SCALED_EPSILON) continue;
-
+ const coordf_t prev_line_len = saved_line_len;
+ saved_line_len = line_len;
+
assert(line.a_width >= 0);
assert(line.b_width >= 0);
coord_t thickness_delta = std::abs(line.a_width - line.b_width);
- if (thickness_delta > tolerance && ceil(float(thickness_delta) / float(tolerance)) > 2) {
- const uint16_t segments = 1 + (uint16_t) std::min((uint32_t)16000, (uint32_t)ceil(float(thickness_delta) / float(tolerance)));
- Points pp;
- std::vector<coordf_t> width;
- {
+
+ // split lines ?
+ if (resolution_internal < line_len) {
+ if (thickness_delta > tolerance && ceil(float(thickness_delta) / float(tolerance)) > 2) {
+ const uint16_t segments = 1 + (uint16_t)std::min((uint32_t)16000, (uint32_t)ceil(float(thickness_delta) / float(tolerance)));
+ Points pp;
+ std::vector<coordf_t> width;
+ {
+ for (size_t j = 0; j < segments; ++j) {
+ pp.push_back(line.a.interpolate(((double)j) / segments, line.b));
+ double percent_width = ((double)j) / (segments - 1);
+ width.push_back(line.a_width * (1 - percent_width) + line.b_width * percent_width);
+ }
+ pp.push_back(line.b);
+
+ assert(pp.size() == segments + 1);
+ assert(width.size() == segments);
+ }
+
+ // delete this line and insert new ones
+ lines.erase(lines.begin() + i);
for (size_t j = 0; j < segments; ++j) {
- pp.push_back(line.a.interpolate(((double)j) / segments, line.b));
- double percent_width = ((double)j) / (segments-1);
- width.push_back(line.a_width * (1 - percent_width) + line.b_width * percent_width);
+ ThickLine new_line(pp[j], pp[j + 1]);
+ new_line.a_width = width[j];
+ new_line.b_width = width[j];
+ lines.insert(lines.begin() + i + j, new_line);
}
- pp.push_back(line.b);
- assert(pp.size() == segments + 1);
- assert(width.size() == segments);
+ // go back to the start of this loop iteration
+ --i;
+ continue;
+ } else if (thickness_delta > 0) {
+ //create a middle point
+ ThickLine new_line(line.a.interpolate(0.5, line.b), line.b);
+ new_line.a_width = line.b_width;
+ new_line.b_width = line.b_width;
+ line.b = new_line.a;
+ line.b_width = line.a_width;
+ lines.insert(lines.begin() + i + 1, new_line);
+
+ // go back to the start of this loop iteration
+ --i;
+ continue;
}
-
- // delete this line and insert new ones
+ } else if (i > 0 && resolution_internal > line_len + prev_line_len) {
+ ThickLine& prev_line = lines[i - 1];
+ //merge lines?
+ coordf_t width = prev_line_len * (prev_line.a_width + prev_line.b_width) / 2;
+ width += line_len * (line.a_width + line.b_width) / 2;
+ prev_line.b = line.b;
+ coordf_t new_length = prev_line.length();
+ width /= new_length;
+ prev_line.a_width = width;
+ prev_line.b_width = width;
+ saved_line_len = new_length;
+ //erase 'line'
lines.erase(lines.begin() + i);
- for (size_t j = 0; j < segments; ++j) {
- ThickLine new_line(pp[j], pp[j + 1]);
- new_line.a_width = width[j];
- new_line.b_width = width[j];
- lines.insert(lines.begin() + i + j, new_line);
- }
-
--i;
continue;
} else if (thickness_delta > 0) {
- //create a middle point
- ThickLine new_line(line.a.interpolate(0.5, line.b), line.b);
- new_line.a_width = line.b_width;
- new_line.b_width = line.b_width;
- line.b = new_line.a;
+ //set width as a middle-ground
+ line.a_width = (line.a_width + line.b_width) / 2;
line.b_width = line.a_width;
- lines.insert(lines.begin() + i + 1, new_line);
-
- --i;
- continue;
}
+ }
+ for (int i = 0; i < (int)lines.size(); ++i) {
+ ThickLine& line = lines[i];
+
//gapfill : we want to be able to fill the voids (touching the perimeters), so the spacing is what we want.
//thinwall: we want the extrusion to not go out of the polygon, so the width is what we want.
// but we can't extrude with a negative spacing, so we have to gradually fall back to spacing if the width is too small.
// default: extrude a thin wall that doesn't go outside of the specified width.
- coordf_t wanted_width = unscale<coordf_t>(line.a_width);
+ double wanted_width = unscaled(line.a_width);
if (role == erGapFill) {
// Convert from spacing to extrusion width based on the extrusion model
// of a square extrusion ended with semi circles.
- wanted_width = unscale<coordf_t>(line.a_width) + flow.height * (1. - 0.25 * PI);
+ wanted_width = unscaled(line.a_width) + flow.height * (1. - 0.25 * PI);
} else if (unscale<coordf_t>(line.a_width) < 2 * flow.height * (1. - 0.25 * PI)) {
//width (too) small, be sure to not extrude with negative spacing.
//we began to fall back to spacing gradually even before the spacing go into the negative
// to make extrusion1 < extrusion2 if width1 < width2 even if width2 is too small.
- wanted_width = unscale<coordf_t>(line.a_width)*0.35 + 1.3 * flow.height * (1. - 0.25 * PI);
+ wanted_width = unscaled(line.a_width)*0.35 + 1.3 * flow.height * (1. - 0.25 * PI);
}
if (path.polyline.points.empty()) {
@@ -2012,7 +2109,7 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
path.width = flow.width;
path.height = flow.height;
} else {
- thickness_delta = scale_(fabs(flow.width - wanted_width));
+ coord_t thickness_delta = scale_t(fabs(flow.width - wanted_width));
if (thickness_delta <= tolerance / 2) {
// the width difference between this line and the current flow width is
// within the accepted tolerance
@@ -2021,12 +2118,21 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
// we need to initialize a new line
paths.emplace_back(std::move(path));
path = ExtrusionPath(role);
- --i;
+ flow.width = wanted_width;
+ path.polyline.append(line.a);
+ path.polyline.append(line.b);
+ assert(flow.mm3_per_mm() == flow.mm3_per_mm());
+ assert(flow.width == flow.width);
+ assert(flow.height == flow.height);
+ path.mm3_per_mm = flow.mm3_per_mm();
+ path.width = flow.width;
+ path.height = flow.height;
}
}
}
if (path.polyline.is_valid())
paths.emplace_back(std::move(path));
+
// Append paths to collection.
if (!paths.empty()) {
if (paths.front().first_point().coincides_with(paths.back().last_point())) {
@@ -2034,11 +2140,21 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
} else {
if (role == erThinWall){
//thin walls : avoid to cut them, please.
+ //also, keep the start, as the start should be already in a frontier where possible.
ExtrusionEntityCollection unsortable_coll(paths);
- unsortable_coll.no_sort = true;
+ unsortable_coll.set_can_sort_reverse(false, false);
coll.append(unsortable_coll);
- }else //gap fill : cut them as much as you want
- coll.append(paths);
+ } else {
+ if (paths.size() <= 1) {
+ coll.append(paths);
+ } else {
+ ExtrusionEntityCollection unsortable_coll(paths);
+ //gap fill : can reverse, but refrain from cutting them as it creates a mess.
+ // I say that, but currently (false, true) does bad things.
+ unsortable_coll.set_can_sort_reverse(false, true);
+ coll.append(unsortable_coll);
+ }
+ }
}
}
}
diff --git a/src/libslic3r/MedialAxis.hpp b/src/libslic3r/MedialAxis.hpp
index 69bd94268..18a7eb2f0 100644
--- a/src/libslic3r/MedialAxis.hpp
+++ b/src/libslic3r/MedialAxis.hpp
@@ -115,7 +115,7 @@ class MedialAxis {
};
/// create a ExtrusionEntityCollection from ThickPolylines, discretizing the variable width into little sections (of 4*SCALED_RESOLUTION length) where needed.
- ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow);
+ ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow, coord_t resolution_internal);
}
diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp
index 9f98eeff5..6ba0c0815 100644
--- a/src/libslic3r/PerimeterGenerator.cpp
+++ b/src/libslic3r/PerimeterGenerator.cpp
@@ -939,7 +939,7 @@ void PerimeterGenerator::process()
// append thin walls
if (!thin_walls.empty()) {
ExtrusionEntityCollection tw = thin_variable_width
- (thin_walls, erThinWall, this->ext_perimeter_flow);
+ (thin_walls, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_width/4, scale_t(this->print_config->resolution)));
entities.append(tw.entities);
thin_walls.clear();
@@ -1086,7 +1086,17 @@ void PerimeterGenerator::process()
// create extrusion from lines
if (!polylines.empty()) {
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines,
- erGapFill, this->solid_infill_flow);
+ erGapFill, this->solid_infill_flow, scale_t(this->print_config->resolution_internal));
+
+ //{
+ // static int isaqsdsdfsdfqzfn = 0;
+ // std::stringstream stri;
+ // stri << this->layer->id() << "_gapfill_" << isaqsdsdfsdfqzfn++ << ".svg";
+ // SVG svg(stri.str());
+ // svg.draw((surface.expolygon), "grey");
+ // svg.draw(polylines, "blue");
+ // svg.Close();
+ //}
this->gap_fill->append(gap_fill.entities);
/* Make sure we don't infill narrow parts that are already gap-filled
(we only consider this surface's gaps to reduce the diff() complexity).
@@ -1478,7 +1488,7 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
// append thin walls to the nearest-neighbor search (only for first iteration)
if (!thin_walls.empty()) {
- ExtrusionEntityCollection tw = thin_variable_width(thin_walls, erThinWall, this->ext_perimeter_flow);
+ ExtrusionEntityCollection tw = thin_variable_width(thin_walls, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_flow.scaled_width() / 4, scale_t(this->print_config->resolution)));
coll.append(tw.entities);
thin_walls.clear();
}
@@ -1631,7 +1641,7 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions
current_loop = last_loop;
}
virtual void use(ExtrusionEntityCollection &collection) override {
- collection.no_sort = false;
+ collection.set_can_sort_reverse(true, true);
//for each loop? (or other collections)
for (ExtrusionEntity *entity : collection.entities)
entity->visit(*this);
@@ -1672,7 +1682,7 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions
searcher.search_result.loop->paths.insert(searcher.search_result.loop->paths.begin() + 1 + searcher.search_result.idx_path,
ExtrusionPath(poly_after, *searcher.search_result.path));
//create thin wall path exttrusion
- ExtrusionEntityCollection tws = thin_variable_width({ tw }, erThinWall, this->ext_perimeter_flow);
+ ExtrusionEntityCollection tws = thin_variable_width({ tw }, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_flow.scaled_width() / 4, scale_t(this->print_config->resolution)));
ChangeFlow change_flow;
if (tws.entities.size() == 1 && tws.entities[0]->is_loop()) {
//loop, just add it
@@ -1708,7 +1718,7 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions
}
//now add thinwalls that have no anchor (make them reversable)
- ExtrusionEntityCollection tws = thin_variable_width(not_added, erThinWall, this->ext_perimeter_flow);
+ ExtrusionEntityCollection tws = thin_variable_width(not_added, erThinWall, this->ext_perimeter_flow, std::max(ext_perimeter_flow.scaled_width() / 4, scale_t(this->print_config->resolution)));
extrusions.append(tws.entities);
}
diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp
index d8be8af9e..45eace66b 100644
--- a/src/libslic3r/Preset.cpp
+++ b/src/libslic3r/Preset.cpp
@@ -627,9 +627,10 @@ const std::vector<std::string>& Preset::print_options()
"thin_walls_overlap",
"thin_walls_speed",
"thin_walls_merge",
- //precision, spoothign
+ //precision, smoothing
"model_precision",
"resolution",
+ "resolution_internal",
"curve_smoothing_precision",
"curve_smoothing_cutoff_dist",
"curve_smoothing_angle_convex",
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 41b52b78a..904ebe45c 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -234,9 +234,12 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
steps.emplace_back(psBrim);
steps.emplace_back(psSkirt);
} else if (
- opt_key == "nozzle_diameter"
+ opt_key == "filament_shrink"
+ || opt_key == "nozzle_diameter"
+ || opt_key == "model_precision"
|| opt_key == "resolution"
- || opt_key == "filament_shrink"
+ || opt_key == "resolution_internal"
+ || opt_key == "slice_closing_radius"
// Spiral Vase forces different kind of slicing than the normal model:
// In Spiral Vase mode, holes are closed and only the largest area contour is kept at each layer.
// Therefore toggling the Spiral Vase on / off requires complete reslicing.
@@ -2287,7 +2290,7 @@ void Print::_extrude_brim_from_tree(std::vector<std::vector<BrimLoop>>& loops, c
} else {
ExtrusionEntityCollection* print_me_first = new ExtrusionEntityCollection();
parent->entities.push_back(print_me_first);
- print_me_first->no_sort = true;
+ print_me_first->set_can_sort_reverse(false, false);
for (Polyline& line : to_cut.lines)
if (line.points.back() == line.points.front()) {
ExtrusionPath path(erSkirt, mm3_per_mm, width, height);
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index d67c516fd..7d7974457 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -3364,7 +3364,18 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->precision = 8;
def->mode = comExpert;
- def->set_default_value(new ConfigOptionFloat(0.002));
+ def->set_default_value(new ConfigOptionFloat(0.0125));
+
+ def = this->add("resolution_internal", coFloat);
+ def->label = L("Internal resolution");
+ def->category = OptionCategory::slicing;
+ def->tooltip = L("Minimum detail resolution, used for internal strutures (gapfill and some infill patterns)."
+ "\nDon't put a too small value (0.05mm is way too low for many printers), as it may creates too many very small segments that may difficult to display and print.");
+ def->sidetext = L("mm");
+ def->min = 0.001;
+ def->precision = 8;
+ def->mode = comExpert;
+ def->set_default_value(new ConfigOptionFloat(0.2));
def = this->add("retract_before_travel", coFloats);
def->label = L("Minimum travel after retraction");
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index 8d5047e62..8e64e70ea 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -1377,6 +1377,7 @@ public:
ConfigOptionString printer_model;
ConfigOptionString printer_notes;
ConfigOptionFloat resolution;
+ ConfigOptionFloat resolution_internal;
ConfigOptionFloats retract_before_travel;
ConfigOptionBools retract_layer_change;
ConfigOptionInt skirt_brim;
@@ -1485,6 +1486,7 @@ protected:
OPT_PTR(printer_model);
OPT_PTR(printer_notes);
OPT_PTR(resolution);
+ OPT_PTR(resolution_internal);
OPT_PTR(retract_before_travel);
OPT_PTR(retract_layer_change);
OPT_PTR(seam_gap);
diff --git a/tests/libslic3r/test_amf.cpp b/tests/libslic3r/test_amf.cpp
index 48cb9d0d1..ff806d17f 100644
--- a/tests/libslic3r/test_amf.cpp
+++ b/tests/libslic3r/test_amf.cpp
@@ -1,3 +1,4 @@
+#define CATCH_CONFIG_DISABLE
#include <catch2/catch.hpp>
#include "test_utils.hpp"
#include "libslic3r/Model.hpp"
@@ -9,10 +10,11 @@ using namespace std::literals::string_literals;
SCENARIO("Reading deflated AMF files", "[AMF]") {
auto _tmp_config = DynamicPrintConfig{};
+ auto _tmp_conf_sub = ConfigSubstitutionContext{ForwardCompatibilitySubstitutionRule::Disable};
GIVEN("Compressed AMF file of a 20mm cube") {
auto model {new Slic3r::Model()};
WHEN("file is read") {
- bool result_code = load_amf(get_model_path("test_amf/20mmbox_deflated.amf"s).c_str(), &_tmp_config, model, false);
+ bool result_code = load_amf(get_model_path("test_amf/20mmbox_deflated.amf"s).c_str(), &_tmp_config, &_tmp_conf_sub, model, false);
THEN("Does not return false.") {
REQUIRE(result_code == true);
}
@@ -21,7 +23,7 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
}
}
WHEN("single file is read with some subdirectories") {
- bool result_code = load_amf(get_model_path("test_amf/20mmbox_deflated-in_directories.amf"s).c_str(), &_tmp_config, model, false);
+ bool result_code = load_amf(get_model_path("test_amf/20mmbox_deflated-in_directories.amf"s).c_str(), &_tmp_config, &_tmp_conf_sub, model, false);
THEN("Read returns false.") {
REQUIRE(result_code == true);
}
@@ -30,7 +32,7 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
}
}
WHEN("file is read with multiple files in the archive") {
- bool result_code = load_amf(get_model_path("test_amf/20mmbox_deflated-mult_files.amf"s).c_str(), &_tmp_config, model, false);
+ bool result_code = load_amf(get_model_path("test_amf/20mmbox_deflated-mult_files.amf"s).c_str(), &_tmp_config, &_tmp_conf_sub, model, false);
THEN("Read returns ture.") {
REQUIRE(result_code == true);
}
@@ -43,7 +45,7 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
GIVEN("Uncompressed AMF file of a 20mm cube") {
auto model {new Slic3r::Model()};
WHEN("file is read") {
- bool result_code = load_amf(get_model_path("test_amf/20mmbox.amf"s).c_str(), &_tmp_config, model, false);
+ bool result_code = load_amf(get_model_path("test_amf/20mmbox.amf"s).c_str(), &_tmp_config, &_tmp_conf_sub, model, false);
THEN("Does not return false.") {
REQUIRE(result_code == true);
}
@@ -52,7 +54,7 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
}
}
WHEN("nonexistant file is read") {
- bool result_code = load_amf(get_model_path("test_amf/20mmbox-doesnotexist.amf"s).c_str(), &_tmp_config, model, false);
+ bool result_code = load_amf(get_model_path("test_amf/20mmbox-doesnotexist.amf"s).c_str(), &_tmp_config, &_tmp_conf_sub, model, false);
THEN("Read returns false.") {
REQUIRE(result_code == false);
}
@@ -66,12 +68,13 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
SCENARIO("Reading AMF file", "[AMF]") {
auto _tmp_config = DynamicPrintConfig{};
+ auto _tmp_conf_sub = ConfigSubstitutionContext{ ForwardCompatibilitySubstitutionRule::Disable };
GIVEN("badly formed AMF file (missing vertices)") {
auto model {new Slic3r::Model()};
WHEN("AMF model is read") {
- auto ret = Slic3r::load_amf(get_model_path("test_amf/5061-malicious.amf").c_str(), &_tmp_config, model, false);
- THEN("read should return True") {
- REQUIRE(ret);
+ auto ret = Slic3r::load_amf(get_model_path("test_amf/5061-malicious.amf").c_str(), &_tmp_config, &_tmp_conf_sub, model, false);
+ THEN("read should return False") {
+ REQUIRE(!ret);
}
}
delete model;
@@ -80,7 +83,7 @@ SCENARIO("Reading AMF file", "[AMF]") {
auto model {new Slic3r::Model()};
WHEN("AMF model is read") {
std::cerr << "TEST_DATA_DIR/test_amf/read-amf.amf";
- auto ret = Slic3r::load_amf(get_model_path("test_amf/read-amf.amf").c_str(), &_tmp_config, model, false);
+ auto ret = Slic3r::load_amf(get_model_path("test_amf/read-amf.amf").c_str(), &_tmp_config, &_tmp_conf_sub, model, false);
THEN("read should return True") {
REQUIRE(ret);
}
diff --git a/tests/libslic3r/test_clipper_utils.cpp b/tests/libslic3r/test_clipper_utils.cpp
index f83d973b3..a6a43b6f2 100644
--- a/tests/libslic3r/test_clipper_utils.cpp
+++ b/tests/libslic3r/test_clipper_utils.cpp
@@ -1,3 +1,4 @@
+#define CATCH_CONFIG_DISABLE
#include <catch2/catch.hpp>
#include <numeric>
@@ -10,6 +11,11 @@
using namespace Slic3r;
+// 32 bit = 10^9
+// 64 bits: 10^18
+// scale : 1 000 000 (10^6) ~ 2^20
+// clipper scale : 2^17
+// => clipper useful range: 2^26 ~ 10 000 000m => 10 000 km
SCENARIO("test clipper limits", "[ClipperUtils]") {
GIVEN("100mm square") {
WHEN("offset") {
@@ -23,11 +29,15 @@ SCENARIO("test clipper limits", "[ClipperUtils]") {
THEN("offset 10000") {
REQUIRE(offset(square, scale_(10000)).size() == 1);
}
+ // every segment shorter than 0.5% of the offset will be cut.
+ // that means 500 for an offset of 100000
+ // so from now, offsetting it will destroy evrything
+ // (since 2017)
THEN("offset 100000") {
- REQUIRE(offset(square, scale_(100000)).size() == 1);
+ REQUIRE(offset(square, scale_(100000)).size() == 0);
}
THEN("offset 1000000") {
- REQUIRE(offset(square, scale_(1000000)).size() == 1);
+ REQUIRE(offset(square, scale_(1000000)).size() == 0);
}
}
}
diff --git a/tests/libslic3r/test_elephant_foot_compensation.cpp b/tests/libslic3r/test_elephant_foot_compensation.cpp
index a95027a3a..3abd3e0fc 100644
--- a/tests/libslic3r/test_elephant_foot_compensation.cpp
+++ b/tests/libslic3r/test_elephant_foot_compensation.cpp
@@ -432,7 +432,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
ExPolygon expoly = contour_with_hole();
WHEN("Compensated") {
// Elephant foot compensation shall not pinch off bits from this contour.
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, false), 0.2f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, 1, false), 0.2f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_with_hole.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -447,7 +447,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
GIVEN("Tiny contour") {
ExPolygon expoly({ { 133382606, 94912473 }, { 134232493, 95001115 }, { 133783926, 95159440 }, { 133441897, 95180666 }, { 133408242, 95191984 }, { 133339012, 95166830 }, { 132991642, 95011087 }, { 133206549, 94908304 } });
WHEN("Compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, false), 0.2f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, 1, false), 0.2f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_tiny.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -462,7 +462,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
GIVEN("Large box") {
ExPolygon expoly( { {50000000, 50000000 }, { 0, 50000000 }, { 0, 0 }, { 50000000, 0 } } );
WHEN("Compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, false), 0.21f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, 1, false), 0.21f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_large_box.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -477,7 +477,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
GIVEN("Thin ring (GH issue #2085)") {
ExPolygon expoly = thin_ring();
WHEN("Compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, false), 0.25f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, 1, false), 0.25f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_thin_ring.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -529,7 +529,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
expoly = union_ex({ expoly, expoly2 }).front();
WHEN("Partially compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.45f, 0.2f, 0.4f, false), 0.25f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.45f, 0.2f, 0.4f, 1, false), 0.25f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_0.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -540,7 +540,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
}
}
WHEN("Fully compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.35f, 0.2f, 0.4f, false), 0.17f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.35f, 0.2f, 0.4f, 1, false), 0.17f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_1.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -555,7 +555,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
GIVEN("Box with hole close to wall (GH issue #2998)") {
ExPolygon expoly = box_with_hole_close_to_wall();
WHEN("Compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, false), 0.25f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, 1, false), 0.25f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_2.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -572,7 +572,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
ExPolygon expoly = spirograph_gear_1mm();
WHEN("Partially compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.45f, 0.2f, 0.4f, false), 0.25f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.45f, 0.2f, 0.4f, 1, false), 0.25f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_2.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -583,7 +583,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
}
}
WHEN("Fully compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.35f, 0.2f, 0.4f, false), 0.17f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.35f, 0.2f, 0.4f, 1, false), 0.17f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_3.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -594,7 +594,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
}
}
WHEN("Brutally compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.45f, 0.2f, 0.4f, false), 0.6f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.45f, 0.2f, 0.4f, 1, false), 0.6f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_4.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
@@ -609,7 +609,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
GIVEN("Vase with fins") {
ExPolygon expoly = vase_with_fins();
WHEN("Compensated") {
- ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, false), 0.41f);
+ ExPolygon expoly_compensated = elephant_foot_compensation(expoly, Flow(0.419999987f, 0.2f, 0.4f, 1, false), 0.41f);
#ifdef TESTS_EXPORT_SVGS
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_vase_with_fins.svg").c_str(),
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
diff --git a/tests/libslic3r/test_geometry.cpp b/tests/libslic3r/test_geometry.cpp
index 886578742..3b8ab4835 100644
--- a/tests/libslic3r/test_geometry.cpp
+++ b/tests/libslic3r/test_geometry.cpp
@@ -18,7 +18,7 @@ ExtrusionPath* createEP(std::initializer_list<Point> vec) {
}
ExtrusionEntityCollection* createEC(std::initializer_list<ExtrusionEntity*> vec, bool no_sort = false) {
ExtrusionEntityCollection *ec = new ExtrusionEntityCollection{};
- ec->no_sort = no_sort;
+ ec->set_can_sort_reverse(!no_sort, !no_sort);
ec->entities = vec;
return ec;
}
@@ -319,7 +319,7 @@ SCENARIO("Path chaining", "[Geometry][!mayfail]") {
}
}
GIVEN("Gyroid infill end points") {
- Polylines polylines = {
+ const Polylines polylines = {
{ {28122608, 3221037}, {27919139, 56036027} },
{ {33642863, 3400772}, {30875220, 56450360} },
{ {34579315, 3599827}, {35049758, 55971572} },
@@ -343,16 +343,81 @@ SCENARIO("Path chaining", "[Geometry][!mayfail]") {
{ {8266122, 14250611}, {6244813, 17751595} },
{ {12177955, 9886741}, {10703348, 11491900} }
};
- Polylines chained = chain_polylines(polylines);
- THEN("Chained taking the shortest path") {
- double connection_length = 0.;
- for (size_t i = 1; i < chained.size(); ++i) {
- const Polyline &pl1 = chained[i - 1];
- const Polyline &pl2 = chained[i];
- connection_length += (pl2.first_point() - pl1.last_point()).cast<double>().norm();
- }
- REQUIRE(connection_length < 85206000.);
- }
+ const Polylines chained = chain_polylines(polylines);
+ THEN("Chained taking the shortest path") {
+ double connection_length = 0.;
+ std::cout << "{ {" << chained[0].points.front().x() << ", " << chained[0].points.front().y() << "}, {" << chained[0].points.back().x() << ", " << chained[0].points.back().x() << "} },\n";
+ for (size_t i = 1; i < chained.size(); ++i) {
+ const Polyline& pl1 = chained[i - 1];
+ const Polyline& pl2 = chained[i];
+ connection_length += (pl2.first_point() - pl1.last_point()).cast<double>().norm();
+ std::cout << "{ {" << chained[i].points.front().x() << ", " << chained[i].points.front().y() << "}, {" << chained[i].points.back().x() << ", " << chained[i].points.back().x() << "} },\n";
+ }
+ REQUIRE(connection_length < 85206000.);
+ }
+ const ExtrusionPath pattern(ExtrusionRole::erPerimeter);
+ THEN("Chained taking the shortest path with extrusionpaths") {
+ ExtrusionEntityCollection coll;
+ for (auto poly : polylines)
+ coll.entities.push_back(new ExtrusionPath(poly, pattern));
+ chain_and_reorder_extrusion_entities(coll.entities, &polylines[18].points.back());
+ double connection_length = 0.;
+ std::cout << "{ {" << coll.entities[0]->as_polyline().points.front().x() << ", " << coll.entities[0]->as_polyline().points.front().y() << "}, {" << coll.entities[0]->as_polyline().points.back().x() << ", " << coll.entities[0]->as_polyline().points.back().y() << "} },\n";
+ for (size_t i = 1; i < coll.entities.size(); ++i) {
+ const Polyline& pl1 = coll.entities[i - 1]->as_polyline();
+ const Polyline& pl2 = coll.entities[i]->as_polyline();
+ connection_length += (pl2.first_point() - pl1.last_point()).cast<double>().norm();
+ std::cout << "{ {" << coll.entities[i]->as_polyline().points.front().x() << ", " << coll.entities[i]->as_polyline().points.front().y() << "}, {" << coll.entities[i]->as_polyline().points.back().x() << ", " << coll.entities[i]->as_polyline().points.back().y() << "} },\n";
+ }
+ REQUIRE(connection_length < 85206000.);
+ }
+ THEN("Chained can't unfold a eeCollection") {
+ ExtrusionEntityCollection coll;
+ for (auto poly : polylines)
+ coll.entities.push_back(new ExtrusionPath(poly, pattern));
+ ExtrusionEntitiesPtr data{ &coll };
+ chain_and_reorder_extrusion_entities(data, &polylines[18].points.back());
+ double connection_length = 0.;
+ for (size_t i = 1; i < coll.entities.size(); ++i) {
+ const Polyline& pl1 = coll.entities[i - 1]->as_polyline();
+ const Polyline& pl2 = coll.entities[i]->as_polyline();
+ connection_length += (pl2.first_point() - pl1.last_point()).cast<double>().norm();
+ }
+ REQUIRE(connection_length > 85206000.);
+ REQUIRE(polylines[18].points.front() != coll.entities[18]->first_point());
+ }
+ THEN("Chained does not take the shortest path with extrusionpaths if in an un-sortable un-reversable collection") {
+ ExtrusionEntityCollection coll;
+ for (auto poly : polylines)
+ coll.entities.push_back(new ExtrusionPath(poly, pattern));
+ ExtrusionEntitiesPtr data{ &coll };
+ coll.set_can_sort_reverse(false, false);
+ chain_and_reorder_extrusion_entities(data, &polylines[18].points.back());
+ double connection_length = 0.;
+ for (size_t i = 1; i < coll.entities.size(); ++i) {
+ const Polyline& pl1 = coll.entities[i - 1]->as_polyline();
+ const Polyline& pl2 = coll.entities[i]->as_polyline();
+ connection_length += (pl2.first_point() - pl1.last_point()).cast<double>().norm();
+ }
+ REQUIRE(connection_length > 85206000.);
+ REQUIRE(polylines[18].points.front() == coll.entities[18]->first_point());
+ }
+ THEN("Chained does not take the shortest path with extrusionpaths if in an un-sortable collection") {
+ ExtrusionEntityCollection coll;
+ for (auto poly : polylines)
+ coll.entities.push_back(new ExtrusionPath(poly, pattern));
+ ExtrusionEntitiesPtr data{ &coll };
+ coll.set_can_sort_reverse(false, true);
+ chain_and_reorder_extrusion_entities(data, &polylines[18].points.back());
+ double connection_length = 0.;
+ for (size_t i = 1; i < coll.entities.size(); ++i) {
+ const Polyline& pl1 = coll.entities[i - 1]->as_polyline();
+ const Polyline& pl2 = coll.entities[i]->as_polyline();
+ connection_length += (pl2.first_point() - pl1.last_point()).cast<double>().norm();
+ }
+ REQUIRE(connection_length > 85206000.);
+ REQUIRE(polylines[18].points.front() != coll.entities[18]->first_point());
+ }
}
GIVEN("Loop pieces") {
Point a { 2185796, 19058485 };