mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-12 17:39:00 +08:00
Fix too detailed gapfill
* add resolution_internal to control it (and gyroid) * disallow gapfill lines to be split
This commit is contained in:
parent
ae73056055
commit
49e4e20a1b
@ -83,6 +83,7 @@ group:Layer height
|
|||||||
setting:first_layer_height
|
setting:first_layer_height
|
||||||
group:Filtering
|
group:Filtering
|
||||||
setting:resolution
|
setting:resolution
|
||||||
|
setting:resolution_internal
|
||||||
setting:model_precision
|
setting:model_precision
|
||||||
setting:slice_closing_radius
|
setting:slice_closing_radius
|
||||||
group:Modifying slices
|
group:Modifying slices
|
||||||
|
@ -231,7 +231,7 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType
|
|||||||
co.ArcTolerance = miterLimit;
|
co.ArcTolerance = miterLimit;
|
||||||
else
|
else
|
||||||
co.MiterLimit = miterLimit;
|
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.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||||
co.AddPaths(input, joinType, endType);
|
co.AddPaths(input, joinType, endType);
|
||||||
ClipperLib::Paths retval;
|
ClipperLib::Paths retval;
|
||||||
|
@ -376,7 +376,7 @@ void ExtrusionPrinter::use(const ExtrusionEntityCollection &collection) {
|
|||||||
if (i != 0) ss << ",";
|
if (i != 0) ss << ",";
|
||||||
collection.entities[i]->visit(*this);
|
collection.entities[i]->visit(*this);
|
||||||
}
|
}
|
||||||
if(collection.no_sort) ss<<", no_sort=true";
|
if(!collection.can_sort()) ss<<", no_sort=true";
|
||||||
ss << "}";
|
ss << "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
// 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
|
// and caller might rely on winding order
|
||||||
if (!ptr->can_reverse())
|
if (ptr->can_reverse() && !ptr->is_loop())
|
||||||
ptr->reverse();
|
ptr->reverse();
|
||||||
}
|
}
|
||||||
std::reverse(this->entities.begin(), this->entities.end());
|
std::reverse(this->entities.begin(), this->entities.end());
|
||||||
@ -151,7 +151,7 @@ ExtrusionEntityCollection ExtrusionEntityCollection::flatten(bool preserve_order
|
|||||||
}
|
}
|
||||||
void
|
void
|
||||||
FlatenEntities::use(const ExtrusionEntityCollection &coll) {
|
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);
|
FlatenEntities unsortable(coll, preserve_ordering);
|
||||||
for (const ExtrusionEntity* entity : coll.entities) {
|
for (const ExtrusionEntity* entity : coll.entities) {
|
||||||
entity->visit(unsortable);
|
entity->visit(unsortable);
|
||||||
|
@ -24,6 +24,11 @@ inline ExtrusionEntitiesPtr filter_by_extrusion_role(const ExtrusionEntitiesPtr
|
|||||||
|
|
||||||
class ExtrusionEntityCollection : public ExtrusionEntity
|
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:
|
public:
|
||||||
virtual ExtrusionEntityCollection* clone() const override { return new ExtrusionEntityCollection(*this); }
|
virtual ExtrusionEntityCollection* clone() const override { return new ExtrusionEntityCollection(*this); }
|
||||||
// Create a new object, initialize it with this object using the move semantics.
|
// Create a new object, initialize it with this object using the move semantics.
|
||||||
@ -33,14 +38,13 @@ public:
|
|||||||
/// Owned ExtrusionEntities and descendent ExtrusionEntityCollections.
|
/// Owned ExtrusionEntities and descendent ExtrusionEntityCollections.
|
||||||
/// Iterating over this needs to check each child to see if it, too is a collection.
|
/// Iterating over this needs to check each child to see if it, too is a collection.
|
||||||
ExtrusionEntitiesPtr entities; // we own these entities
|
ExtrusionEntitiesPtr entities; // we own these entities
|
||||||
bool no_sort;
|
ExtrusionEntityCollection(): no_sort(false), no_reverse(false) {}
|
||||||
ExtrusionEntityCollection(): no_sort(false) {}
|
ExtrusionEntityCollection(const ExtrusionEntityCollection &other) : no_sort(other.no_sort), no_reverse(other.no_reverse) { this->append(other.entities); }
|
||||||
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), no_reverse(other.no_reverse) {}
|
||||||
ExtrusionEntityCollection(ExtrusionEntityCollection &&other) : entities(std::move(other.entities)), no_sort(other.no_sort) {}
|
|
||||||
explicit ExtrusionEntityCollection(const ExtrusionPaths &paths);
|
explicit ExtrusionEntityCollection(const ExtrusionPaths &paths);
|
||||||
ExtrusionEntityCollection& operator=(const ExtrusionEntityCollection &other);
|
ExtrusionEntityCollection& operator=(const ExtrusionEntityCollection &other);
|
||||||
ExtrusionEntityCollection& operator=(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(); }
|
~ExtrusionEntityCollection() { clear(); }
|
||||||
|
|
||||||
/// Operator to convert and flatten this collection to a single vector of ExtrusionPaths.
|
/// Operator to convert and flatten this collection to a single vector of ExtrusionPaths.
|
||||||
@ -55,7 +59,9 @@ public:
|
|||||||
}
|
}
|
||||||
return out;
|
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(); }
|
bool empty() const { return this->entities.empty(); }
|
||||||
void clear();
|
void clear();
|
||||||
void swap (ExtrusionEntityCollection &c);
|
void swap (ExtrusionEntityCollection &c);
|
||||||
@ -152,7 +158,7 @@ class FlatenEntities : public ExtrusionVisitorConst {
|
|||||||
public:
|
public:
|
||||||
FlatenEntities(bool preserve_ordering) : preserve_ordering(preserve_ordering) {}
|
FlatenEntities(bool preserve_ordering) : preserve_ordering(preserve_ordering) {}
|
||||||
FlatenEntities(ExtrusionEntityCollection pattern, 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() {
|
ExtrusionEntityCollection get() {
|
||||||
return to_fill;
|
return to_fill;
|
||||||
|
@ -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);
|
m_regions[region_id]->fills.append(fills_by_priority[0]->entities);
|
||||||
delete fills_by_priority[0];
|
delete fills_by_priority[0];
|
||||||
} else {
|
} else {
|
||||||
m_regions[region_id]->fills.no_sort = true;
|
m_regions[region_id]->fills.set_can_sort_reverse(false, false);
|
||||||
ExtrusionEntityCollection* eec = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection* eec = new ExtrusionEntityCollection();
|
||||||
eec->no_sort = true;
|
eec->set_can_sort_reverse(false, false);
|
||||||
m_regions[region_id]->fills.entities.push_back(eec);
|
m_regions[region_id]->fills.entities.push_back(eec);
|
||||||
for (ExtrusionEntityCollection* per_priority : fills_by_priority) {
|
for (ExtrusionEntityCollection* per_priority : fills_by_priority) {
|
||||||
if (!per_priority->entities.empty())
|
if (!per_priority->entities.empty())
|
||||||
@ -580,9 +580,9 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
|||||||
for (LayerRegion *layerm : m_regions)
|
for (LayerRegion *layerm : m_regions)
|
||||||
for (const ExtrusionEntity *thin_fill : layerm->thin_fills.entities) {
|
for (const ExtrusionEntity *thin_fill : layerm->thin_fills.entities) {
|
||||||
ExtrusionEntityCollection *collection = new ExtrusionEntityCollection();
|
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]);
|
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);
|
static_cast<ExtrusionEntityCollection*>(no_sort_fill->entities[0])->entities.push_back(collection);
|
||||||
} else
|
} else
|
||||||
layerm->fills.entities.push_back(collection);
|
layerm->fills.entities.push_back(collection);
|
||||||
@ -593,7 +593,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
|||||||
for (LayerRegion *layerm : m_regions)
|
for (LayerRegion *layerm : m_regions)
|
||||||
for (size_t i1 = 0; i1 < layerm->fills.entities.size(); ++i1) {
|
for (size_t i1 = 0; i1 < layerm->fills.entities.size(); ++i1) {
|
||||||
assert(dynamic_cast<ExtrusionEntityCollection*>(layerm->fills.entities[i1]) != nullptr);
|
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]);
|
ExtrusionEntityCollection* no_sort_fill = static_cast<ExtrusionEntityCollection*>(layerm->fills.entities[0]);
|
||||||
assert(no_sort_fill != nullptr);
|
assert(no_sort_fill != nullptr);
|
||||||
assert(!no_sort_fill->empty());
|
assert(!no_sort_fill->empty());
|
||||||
@ -601,7 +601,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
|
|||||||
ExtrusionEntityCollection* priority_fill = dynamic_cast<ExtrusionEntityCollection*>(no_sort_fill->entities[i2]);
|
ExtrusionEntityCollection* priority_fill = dynamic_cast<ExtrusionEntityCollection*>(no_sort_fill->entities[i2]);
|
||||||
assert(priority_fill != nullptr);
|
assert(priority_fill != nullptr);
|
||||||
assert(!priority_fill->empty());
|
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)
|
for (size_t i3 = 0; i3 < priority_fill->entities.size(); ++i3)
|
||||||
assert(dynamic_cast<ExtrusionEntityCollection*>(priority_fill->entities[i3]) != nullptr);
|
assert(dynamic_cast<ExtrusionEntityCollection*>(priority_fill->entities[i3]) != nullptr);
|
||||||
}
|
}
|
||||||
@ -780,7 +780,7 @@ void Layer::make_ironing()
|
|||||||
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
||||||
ironing_params.layerm->ironings.entities.push_back(eec);
|
ironing_params.layerm->ironings.entities.push_back(eec);
|
||||||
// Don't sort the ironing infill lines as they are monotonicly ordered.
|
// 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(
|
extrusion_entities_append_paths(
|
||||||
eec->entities, std::move(polylines),
|
eec->entities, std::move(polylines),
|
||||||
erIroning,
|
erIroning,
|
||||||
|
@ -211,7 +211,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶
|
|||||||
// Save into layer.
|
// Save into layer.
|
||||||
auto *eec = new ExtrusionEntityCollection();
|
auto *eec = new ExtrusionEntityCollection();
|
||||||
/// pass the no_sort attribute to the extrusion path
|
/// 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
|
/// add it into the collection
|
||||||
out.push_back(eec);
|
out.push_back(eec);
|
||||||
//get the role
|
//get the role
|
||||||
@ -269,7 +269,7 @@ Fill::do_gap_fill(const ExPolygons& gapfill_areas, const FillParams& params, Ext
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
//set role if needed
|
||||||
/*if (params.role != erSolidInfill) {
|
/*if (params.role != erSolidInfill) {
|
||||||
ExtrusionSetRole set_good_role(params.role);
|
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
|
//move them into the collection
|
||||||
if (!gap_fill.entities.empty()) {
|
if (!gap_fill.entities.empty()) {
|
||||||
ExtrusionEntityCollection* coll_gapfill = new ExtrusionEntityCollection();
|
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_gapfill->append(std::move(gap_fill.entities));
|
||||||
coll_out.push_back(coll_gapfill);
|
coll_out.push_back(coll_gapfill);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ FillConcentricWGapFill::fill_surface_extrusion(
|
|||||||
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
|
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
|
||||||
|
|
||||||
ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection();
|
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(
|
extrusion_entities_append_loops(
|
||||||
coll_nosort->entities, loops,
|
coll_nosort->entities, loops,
|
||||||
good_role,
|
good_role,
|
||||||
@ -154,7 +154,7 @@ FillConcentricWGapFill::fill_surface_extrusion(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!polylines.empty() && !is_bridge(good_role)) {
|
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
|
//set role if needed
|
||||||
if (good_role != erSolidInfill) {
|
if (good_role != erSolidInfill) {
|
||||||
ExtrusionSetRole set_good_role(good_role);
|
ExtrusionSetRole set_good_role(good_role);
|
||||||
|
@ -101,13 +101,8 @@ static std::vector<Vec2d> make_one_period(double width, double scaleFactor, doub
|
|||||||
return points;
|
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
|
//scale factor for 5% : 8 712 388
|
||||||
// 1z = 10^-6 mm ?
|
// 1z = 10^-6 mm ?
|
||||||
@ -167,13 +162,22 @@ void FillGyroid::_fill_surface_single(
|
|||||||
// align bounding box to a multiple of our grid module
|
// 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)));
|
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
|
// generate pattern
|
||||||
Polylines polylines = make_gyroid_waves(
|
Polylines polylines = make_gyroid_waves(
|
||||||
(double)scale_(this->z),
|
scale_d(this->z),
|
||||||
density_adjusted,
|
scaleFactor,
|
||||||
this->get_spacing(),
|
|
||||||
ceil(bb.size()(0) / distance) + 1.,
|
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
|
// shift the polyline to the grid origin
|
||||||
for (Polyline &pl : polylines)
|
for (Polyline &pl : polylines)
|
||||||
|
@ -3208,7 +3208,7 @@ FillRectilinearPeri::fill_surface_extrusion(const Surface *surface, const FillPa
|
|||||||
{
|
{
|
||||||
ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection();
|
||||||
//you don't want to sort the extrusions: big infill first, small second
|
//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 ===
|
// === extrude perimeter ===
|
||||||
Polylines polylines_1;
|
Polylines polylines_1;
|
||||||
@ -3231,7 +3231,7 @@ FillRectilinearPeri::fill_surface_extrusion(const Surface *surface, const FillPa
|
|||||||
// Save into layer.
|
// Save into layer.
|
||||||
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
||||||
/// pass the no_sort attribute to the extrusion path
|
/// 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
|
/// add it into the collection
|
||||||
eecroot->entities.push_back(eec);
|
eecroot->entities.push_back(eec);
|
||||||
//get the role
|
//get the role
|
||||||
@ -3263,7 +3263,7 @@ FillRectilinearPeri::fill_surface_extrusion(const Surface *surface, const FillPa
|
|||||||
// Save into layer.
|
// Save into layer.
|
||||||
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
||||||
/// pass the no_sort attribute to the extrusion path
|
/// 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
|
/// add it into the collection
|
||||||
eecroot->entities.push_back(eec);
|
eecroot->entities.push_back(eec);
|
||||||
//get the role
|
//get the role
|
||||||
@ -3365,7 +3365,7 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi
|
|||||||
if (!polylines_out.empty()) {
|
if (!polylines_out.empty()) {
|
||||||
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
||||||
/// pass the no_sort attribute to the extrusion path
|
/// 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);
|
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
|
||||||
|
|
||||||
@ -3489,7 +3489,7 @@ FillRectilinearWGapFill::split_polygon_gap_fill(const Surface &surface, const Fi
|
|||||||
void
|
void
|
||||||
FillRectilinearWGapFill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const {
|
FillRectilinearWGapFill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const {
|
||||||
ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection();
|
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);
|
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
|
||||||
|
|
||||||
//// remove areas for gapfill
|
//// 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
|
/// pass the no_sort attribute to the extrusion path
|
||||||
//don't force monotonic if not top or bottom
|
//don't force monotonic if not top or bottom
|
||||||
if (is_monotonic())
|
if (is_monotonic())
|
||||||
eec->no_sort = true;
|
eec->set_can_sort_reverse(false, false);
|
||||||
else
|
else
|
||||||
eec->no_sort = this->no_sort();
|
eec->set_can_sort_reverse(!this->no_sort(), !this->no_sort());
|
||||||
|
|
||||||
extrusion_entities_append_paths(
|
extrusion_entities_append_paths(
|
||||||
eec->entities, polylines_rectilinear,
|
eec->entities, polylines_rectilinear,
|
||||||
|
@ -24,7 +24,7 @@ namespace Slic3r {
|
|||||||
|
|
||||||
// Save into layer smoothing path.
|
// Save into layer smoothing path.
|
||||||
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
||||||
eec->no_sort = params.monotonic;
|
eec->set_can_sort_reverse(!params.monotonic, !params.monotonic);
|
||||||
FillParams params_modifided = params;
|
FillParams params_modifided = params;
|
||||||
if (params.config != NULL && idx > 0) params_modifided.density /= (float)params.config->fill_smooth_width.get_abs_value(1);
|
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;
|
else if (params.config != NULL && idx == 0) params_modifided.density *= 1;
|
||||||
@ -131,7 +131,7 @@ namespace Slic3r {
|
|||||||
//create root node
|
//create root node
|
||||||
ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection();
|
||||||
//you don't want to sort the extrusions: big infill first, small second
|
//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
|
// first infill
|
||||||
FillParams first_pass_params = params;
|
FillParams first_pass_params = params;
|
||||||
|
@ -3455,7 +3455,7 @@ std::string GCode::extrude_entity(const ExtrusionEntity &entity, const std::stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GCode::use(const ExtrusionEntityCollection &collection) {
|
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) {
|
for (const ExtrusionEntity* next_entity : collection.entities) {
|
||||||
next_entity->visit(*this);
|
next_entity->visit(*this);
|
||||||
}
|
}
|
||||||
|
@ -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) : 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) {}
|
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
|
class Line3
|
||||||
|
@ -1923,12 +1923,14 @@ MedialAxis::build(ThickPolylines &polylines_out)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ExtrusionEntityCollection
|
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
|
// 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
|
// 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
|
// 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;
|
ExtrusionEntityCollection coll;
|
||||||
for (const ThickPolyline &p : polylines) {
|
for (const ThickPolyline &p : polylines) {
|
||||||
@ -1936,69 +1938,100 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
|
|||||||
ExtrusionPath path(role);
|
ExtrusionPath path(role);
|
||||||
ThickLines lines = p.thicklines();
|
ThickLines lines = p.thicklines();
|
||||||
|
|
||||||
|
coordf_t saved_line_len = 0;
|
||||||
for (int i = 0; i < (int)lines.size(); ++i) {
|
for (int i = 0; i < (int)lines.size(); ++i) {
|
||||||
ThickLine& line = lines[i];
|
ThickLine& line = lines[i];
|
||||||
|
|
||||||
const coordf_t line_len = line.length();
|
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.a_width >= 0);
|
||||||
assert(line.b_width >= 0);
|
assert(line.b_width >= 0);
|
||||||
coord_t thickness_delta = std::abs(line.a_width - line.b_width);
|
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)));
|
// split lines ?
|
||||||
Points pp;
|
if (resolution_internal < line_len) {
|
||||||
std::vector<coordf_t> 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)));
|
||||||
for (size_t j = 0; j < segments; ++j) {
|
Points pp;
|
||||||
pp.push_back(line.a.interpolate(((double)j) / segments, line.b));
|
std::vector<coordf_t> width;
|
||||||
double percent_width = ((double)j) / (segments-1);
|
{
|
||||||
width.push_back(line.a_width * (1 - percent_width) + line.b_width * percent_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);
|
||||||
}
|
}
|
||||||
pp.push_back(line.b);
|
|
||||||
|
|
||||||
assert(pp.size() == segments + 1);
|
// delete this line and insert new ones
|
||||||
assert(width.size() == segments);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
} else if (i > 0 && resolution_internal > line_len + prev_line_len) {
|
||||||
// delete this line and insert new ones
|
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);
|
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;
|
--i;
|
||||||
continue;
|
continue;
|
||||||
} else if (thickness_delta > 0) {
|
} else if (thickness_delta > 0) {
|
||||||
//create a middle point
|
//set width as a middle-ground
|
||||||
ThickLine new_line(line.a.interpolate(0.5, line.b), line.b);
|
line.a_width = (line.a_width + line.b_width) / 2;
|
||||||
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;
|
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.
|
//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.
|
//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.
|
// 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.
|
// 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) {
|
if (role == erGapFill) {
|
||||||
// Convert from spacing to extrusion width based on the extrusion model
|
// Convert from spacing to extrusion width based on the extrusion model
|
||||||
// of a square extrusion ended with semi circles.
|
// 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)) {
|
} 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.
|
//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
|
//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.
|
// 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()) {
|
if (path.polyline.points.empty()) {
|
||||||
@ -2012,7 +2045,7 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
|
|||||||
path.width = flow.width;
|
path.width = flow.width;
|
||||||
path.height = flow.height;
|
path.height = flow.height;
|
||||||
} else {
|
} 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) {
|
if (thickness_delta <= tolerance / 2) {
|
||||||
// the width difference between this line and the current flow width is
|
// the width difference between this line and the current flow width is
|
||||||
// within the accepted tolerance
|
// within the accepted tolerance
|
||||||
@ -2021,12 +2054,21 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
|
|||||||
// we need to initialize a new line
|
// we need to initialize a new line
|
||||||
paths.emplace_back(std::move(path));
|
paths.emplace_back(std::move(path));
|
||||||
path = ExtrusionPath(role);
|
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())
|
if (path.polyline.is_valid())
|
||||||
paths.emplace_back(std::move(path));
|
paths.emplace_back(std::move(path));
|
||||||
|
|
||||||
// Append paths to collection.
|
// Append paths to collection.
|
||||||
if (!paths.empty()) {
|
if (!paths.empty()) {
|
||||||
if (paths.front().first_point().coincides_with(paths.back().last_point())) {
|
if (paths.front().first_point().coincides_with(paths.back().last_point())) {
|
||||||
@ -2034,11 +2076,21 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
|
|||||||
} else {
|
} else {
|
||||||
if (role == erThinWall){
|
if (role == erThinWall){
|
||||||
//thin walls : avoid to cut them, please.
|
//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);
|
ExtrusionEntityCollection unsortable_coll(paths);
|
||||||
unsortable_coll.no_sort = true;
|
unsortable_coll.set_can_sort_reverse(false, false);
|
||||||
coll.append(unsortable_coll);
|
coll.append(unsortable_coll);
|
||||||
}else //gap fill : cut them as much as you want
|
} else {
|
||||||
coll.append(paths);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
/// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -939,7 +939,7 @@ void PerimeterGenerator::process()
|
|||||||
// append thin walls
|
// append thin walls
|
||||||
if (!thin_walls.empty()) {
|
if (!thin_walls.empty()) {
|
||||||
ExtrusionEntityCollection tw = thin_variable_width
|
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);
|
entities.append(tw.entities);
|
||||||
thin_walls.clear();
|
thin_walls.clear();
|
||||||
@ -1086,7 +1086,17 @@ void PerimeterGenerator::process()
|
|||||||
// create extrusion from lines
|
// create extrusion from lines
|
||||||
if (!polylines.empty()) {
|
if (!polylines.empty()) {
|
||||||
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines,
|
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);
|
this->gap_fill->append(gap_fill.entities);
|
||||||
/* Make sure we don't infill narrow parts that are already gap-filled
|
/* 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).
|
(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)
|
// append thin walls to the nearest-neighbor search (only for first iteration)
|
||||||
if (!thin_walls.empty()) {
|
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);
|
coll.append(tw.entities);
|
||||||
thin_walls.clear();
|
thin_walls.clear();
|
||||||
}
|
}
|
||||||
@ -1631,7 +1641,7 @@ void PerimeterGenerator::_merge_thin_walls(ExtrusionEntityCollection &extrusions
|
|||||||
current_loop = last_loop;
|
current_loop = last_loop;
|
||||||
}
|
}
|
||||||
virtual void use(ExtrusionEntityCollection &collection) override {
|
virtual void use(ExtrusionEntityCollection &collection) override {
|
||||||
collection.no_sort = false;
|
collection.set_can_sort_reverse(true, true);
|
||||||
//for each loop? (or other collections)
|
//for each loop? (or other collections)
|
||||||
for (ExtrusionEntity *entity : collection.entities)
|
for (ExtrusionEntity *entity : collection.entities)
|
||||||
entity->visit(*this);
|
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,
|
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));
|
ExtrusionPath(poly_after, *searcher.search_result.path));
|
||||||
//create thin wall path exttrusion
|
//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;
|
ChangeFlow change_flow;
|
||||||
if (tws.entities.size() == 1 && tws.entities[0]->is_loop()) {
|
if (tws.entities.size() == 1 && tws.entities[0]->is_loop()) {
|
||||||
//loop, just add it
|
//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)
|
//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);
|
extrusions.append(tws.entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,9 +627,10 @@ const std::vector<std::string>& Preset::print_options()
|
|||||||
"thin_walls_overlap",
|
"thin_walls_overlap",
|
||||||
"thin_walls_speed",
|
"thin_walls_speed",
|
||||||
"thin_walls_merge",
|
"thin_walls_merge",
|
||||||
//precision, spoothign
|
//precision, smoothing
|
||||||
"model_precision",
|
"model_precision",
|
||||||
"resolution",
|
"resolution",
|
||||||
|
"resolution_internal",
|
||||||
"curve_smoothing_precision",
|
"curve_smoothing_precision",
|
||||||
"curve_smoothing_cutoff_dist",
|
"curve_smoothing_cutoff_dist",
|
||||||
"curve_smoothing_angle_convex",
|
"curve_smoothing_angle_convex",
|
||||||
|
@ -234,9 +234,12 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||||||
steps.emplace_back(psBrim);
|
steps.emplace_back(psBrim);
|
||||||
steps.emplace_back(psSkirt);
|
steps.emplace_back(psSkirt);
|
||||||
} else if (
|
} else if (
|
||||||
opt_key == "nozzle_diameter"
|
opt_key == "filament_shrink"
|
||||||
|
|| opt_key == "nozzle_diameter"
|
||||||
|
|| opt_key == "model_precision"
|
||||||
|| opt_key == "resolution"
|
|| 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:
|
// 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.
|
// 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.
|
// 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 {
|
} else {
|
||||||
ExtrusionEntityCollection* print_me_first = new ExtrusionEntityCollection();
|
ExtrusionEntityCollection* print_me_first = new ExtrusionEntityCollection();
|
||||||
parent->entities.push_back(print_me_first);
|
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)
|
for (Polyline& line : to_cut.lines)
|
||||||
if (line.points.back() == line.points.front()) {
|
if (line.points.back() == line.points.front()) {
|
||||||
ExtrusionPath path(erSkirt, mm3_per_mm, width, height);
|
ExtrusionPath path(erSkirt, mm3_per_mm, width, height);
|
||||||
|
@ -3364,7 +3364,18 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->precision = 8;
|
def->precision = 8;
|
||||||
def->mode = comExpert;
|
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 = this->add("retract_before_travel", coFloats);
|
||||||
def->label = L("Minimum travel after retraction");
|
def->label = L("Minimum travel after retraction");
|
||||||
|
@ -1377,6 +1377,7 @@ public:
|
|||||||
ConfigOptionString printer_model;
|
ConfigOptionString printer_model;
|
||||||
ConfigOptionString printer_notes;
|
ConfigOptionString printer_notes;
|
||||||
ConfigOptionFloat resolution;
|
ConfigOptionFloat resolution;
|
||||||
|
ConfigOptionFloat resolution_internal;
|
||||||
ConfigOptionFloats retract_before_travel;
|
ConfigOptionFloats retract_before_travel;
|
||||||
ConfigOptionBools retract_layer_change;
|
ConfigOptionBools retract_layer_change;
|
||||||
ConfigOptionInt skirt_brim;
|
ConfigOptionInt skirt_brim;
|
||||||
@ -1485,6 +1486,7 @@ protected:
|
|||||||
OPT_PTR(printer_model);
|
OPT_PTR(printer_model);
|
||||||
OPT_PTR(printer_notes);
|
OPT_PTR(printer_notes);
|
||||||
OPT_PTR(resolution);
|
OPT_PTR(resolution);
|
||||||
|
OPT_PTR(resolution_internal);
|
||||||
OPT_PTR(retract_before_travel);
|
OPT_PTR(retract_before_travel);
|
||||||
OPT_PTR(retract_layer_change);
|
OPT_PTR(retract_layer_change);
|
||||||
OPT_PTR(seam_gap);
|
OPT_PTR(seam_gap);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#define CATCH_CONFIG_DISABLE
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
#include "test_utils.hpp"
|
#include "test_utils.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
@ -9,10 +10,11 @@ using namespace std::literals::string_literals;
|
|||||||
|
|
||||||
SCENARIO("Reading deflated AMF files", "[AMF]") {
|
SCENARIO("Reading deflated AMF files", "[AMF]") {
|
||||||
auto _tmp_config = DynamicPrintConfig{};
|
auto _tmp_config = DynamicPrintConfig{};
|
||||||
|
auto _tmp_conf_sub = ConfigSubstitutionContext{ForwardCompatibilitySubstitutionRule::Disable};
|
||||||
GIVEN("Compressed AMF file of a 20mm cube") {
|
GIVEN("Compressed AMF file of a 20mm cube") {
|
||||||
auto model {new Slic3r::Model()};
|
auto model {new Slic3r::Model()};
|
||||||
WHEN("file is read") {
|
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.") {
|
THEN("Does not return false.") {
|
||||||
REQUIRE(result_code == true);
|
REQUIRE(result_code == true);
|
||||||
}
|
}
|
||||||
@ -21,7 +23,7 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
WHEN("single file is read with some subdirectories") {
|
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.") {
|
THEN("Read returns false.") {
|
||||||
REQUIRE(result_code == true);
|
REQUIRE(result_code == true);
|
||||||
}
|
}
|
||||||
@ -30,7 +32,7 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
WHEN("file is read with multiple files in the archive") {
|
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.") {
|
THEN("Read returns ture.") {
|
||||||
REQUIRE(result_code == true);
|
REQUIRE(result_code == true);
|
||||||
}
|
}
|
||||||
@ -43,7 +45,7 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
|
|||||||
GIVEN("Uncompressed AMF file of a 20mm cube") {
|
GIVEN("Uncompressed AMF file of a 20mm cube") {
|
||||||
auto model {new Slic3r::Model()};
|
auto model {new Slic3r::Model()};
|
||||||
WHEN("file is read") {
|
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.") {
|
THEN("Does not return false.") {
|
||||||
REQUIRE(result_code == true);
|
REQUIRE(result_code == true);
|
||||||
}
|
}
|
||||||
@ -52,7 +54,7 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
WHEN("nonexistant file is read") {
|
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.") {
|
THEN("Read returns false.") {
|
||||||
REQUIRE(result_code == false);
|
REQUIRE(result_code == false);
|
||||||
}
|
}
|
||||||
@ -66,12 +68,13 @@ SCENARIO("Reading deflated AMF files", "[AMF]") {
|
|||||||
|
|
||||||
SCENARIO("Reading AMF file", "[AMF]") {
|
SCENARIO("Reading AMF file", "[AMF]") {
|
||||||
auto _tmp_config = DynamicPrintConfig{};
|
auto _tmp_config = DynamicPrintConfig{};
|
||||||
|
auto _tmp_conf_sub = ConfigSubstitutionContext{ ForwardCompatibilitySubstitutionRule::Disable };
|
||||||
GIVEN("badly formed AMF file (missing vertices)") {
|
GIVEN("badly formed AMF file (missing vertices)") {
|
||||||
auto model {new Slic3r::Model()};
|
auto model {new Slic3r::Model()};
|
||||||
WHEN("AMF model is read") {
|
WHEN("AMF model is read") {
|
||||||
auto ret = Slic3r::load_amf(get_model_path("test_amf/5061-malicious.amf").c_str(), &_tmp_config, model, false);
|
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 True") {
|
THEN("read should return False") {
|
||||||
REQUIRE(ret);
|
REQUIRE(!ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete model;
|
delete model;
|
||||||
@ -80,7 +83,7 @@ SCENARIO("Reading AMF file", "[AMF]") {
|
|||||||
auto model {new Slic3r::Model()};
|
auto model {new Slic3r::Model()};
|
||||||
WHEN("AMF model is read") {
|
WHEN("AMF model is read") {
|
||||||
std::cerr << "TEST_DATA_DIR/test_amf/read-amf.amf";
|
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") {
|
THEN("read should return True") {
|
||||||
REQUIRE(ret);
|
REQUIRE(ret);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#define CATCH_CONFIG_DISABLE
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
@ -10,6 +11,11 @@
|
|||||||
|
|
||||||
using namespace Slic3r;
|
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]") {
|
SCENARIO("test clipper limits", "[ClipperUtils]") {
|
||||||
GIVEN("100mm square") {
|
GIVEN("100mm square") {
|
||||||
WHEN("offset") {
|
WHEN("offset") {
|
||||||
@ -23,11 +29,15 @@ SCENARIO("test clipper limits", "[ClipperUtils]") {
|
|||||||
THEN("offset 10000") {
|
THEN("offset 10000") {
|
||||||
REQUIRE(offset(square, scale_(10000)).size() == 1);
|
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") {
|
THEN("offset 100000") {
|
||||||
REQUIRE(offset(square, scale_(100000)).size() == 1);
|
REQUIRE(offset(square, scale_(100000)).size() == 0);
|
||||||
}
|
}
|
||||||
THEN("offset 1000000") {
|
THEN("offset 1000000") {
|
||||||
REQUIRE(offset(square, scale_(1000000)).size() == 1);
|
REQUIRE(offset(square, scale_(1000000)).size() == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -432,7 +432,7 @@ SCENARIO("Elephant foot compensation", "[ElephantFoot]") {
|
|||||||
ExPolygon expoly = contour_with_hole();
|
ExPolygon expoly = contour_with_hole();
|
||||||
WHEN("Compensated") {
|
WHEN("Compensated") {
|
||||||
// Elephant foot compensation shall not pinch off bits from this contour.
|
// 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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_with_hole.svg").c_str(),
|
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)) } },
|
{ { { 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") {
|
GIVEN("Tiny contour") {
|
||||||
ExPolygon expoly({ { 133382606, 94912473 }, { 134232493, 95001115 }, { 133783926, 95159440 }, { 133441897, 95180666 }, { 133408242, 95191984 }, { 133339012, 95166830 }, { 132991642, 95011087 }, { 133206549, 94908304 } });
|
ExPolygon expoly({ { 133382606, 94912473 }, { 134232493, 95001115 }, { 133783926, 95159440 }, { 133441897, 95180666 }, { 133408242, 95191984 }, { 133339012, 95166830 }, { 132991642, 95011087 }, { 133206549, 94908304 } });
|
||||||
WHEN("Compensated") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_tiny.svg").c_str(),
|
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)) } },
|
{ { { 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") {
|
GIVEN("Large box") {
|
||||||
ExPolygon expoly( { {50000000, 50000000 }, { 0, 50000000 }, { 0, 0 }, { 50000000, 0 } } );
|
ExPolygon expoly( { {50000000, 50000000 }, { 0, 50000000 }, { 0, 0 }, { 50000000, 0 } } );
|
||||||
WHEN("Compensated") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_large_box.svg").c_str(),
|
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)) } },
|
{ { { 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)") {
|
GIVEN("Thin ring (GH issue #2085)") {
|
||||||
ExPolygon expoly = thin_ring();
|
ExPolygon expoly = thin_ring();
|
||||||
WHEN("Compensated") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_thin_ring.svg").c_str(),
|
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)) } },
|
{ { { 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();
|
expoly = union_ex({ expoly, expoly2 }).front();
|
||||||
|
|
||||||
WHEN("Partially compensated") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_0.svg").c_str(),
|
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)) } },
|
{ { { 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") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_1.svg").c_str(),
|
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)) } },
|
{ { { 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)") {
|
GIVEN("Box with hole close to wall (GH issue #2998)") {
|
||||||
ExPolygon expoly = box_with_hole_close_to_wall();
|
ExPolygon expoly = box_with_hole_close_to_wall();
|
||||||
WHEN("Compensated") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_2.svg").c_str(),
|
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)) } },
|
{ { { 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();
|
ExPolygon expoly = spirograph_gear_1mm();
|
||||||
|
|
||||||
WHEN("Partially compensated") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_2.svg").c_str(),
|
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)) } },
|
{ { { 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") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_3.svg").c_str(),
|
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)) } },
|
{ { { 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") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_4.svg").c_str(),
|
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)) } },
|
{ { { 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") {
|
GIVEN("Vase with fins") {
|
||||||
ExPolygon expoly = vase_with_fins();
|
ExPolygon expoly = vase_with_fins();
|
||||||
WHEN("Compensated") {
|
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
|
#ifdef TESTS_EXPORT_SVGS
|
||||||
SVG::export_expolygons(debug_out_path("elephant_foot_compensation_vase_with_fins.svg").c_str(),
|
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)) } },
|
{ { { expoly }, { "gray", "black", "blue", coord_t(scale_(0.02)), 0.5f, "black", coord_t(scale_(0.05)) } },
|
||||||
|
@ -18,7 +18,7 @@ ExtrusionPath* createEP(std::initializer_list<Point> vec) {
|
|||||||
}
|
}
|
||||||
ExtrusionEntityCollection* createEC(std::initializer_list<ExtrusionEntity*> vec, bool no_sort = false) {
|
ExtrusionEntityCollection* createEC(std::initializer_list<ExtrusionEntity*> vec, bool no_sort = false) {
|
||||||
ExtrusionEntityCollection *ec = new ExtrusionEntityCollection{};
|
ExtrusionEntityCollection *ec = new ExtrusionEntityCollection{};
|
||||||
ec->no_sort = no_sort;
|
ec->set_can_sort_reverse(!no_sort, !no_sort);
|
||||||
ec->entities = vec;
|
ec->entities = vec;
|
||||||
return ec;
|
return ec;
|
||||||
}
|
}
|
||||||
@ -319,7 +319,7 @@ SCENARIO("Path chaining", "[Geometry][!mayfail]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
GIVEN("Gyroid infill end points") {
|
GIVEN("Gyroid infill end points") {
|
||||||
Polylines polylines = {
|
const Polylines polylines = {
|
||||||
{ {28122608, 3221037}, {27919139, 56036027} },
|
{ {28122608, 3221037}, {27919139, 56036027} },
|
||||||
{ {33642863, 3400772}, {30875220, 56450360} },
|
{ {33642863, 3400772}, {30875220, 56450360} },
|
||||||
{ {34579315, 3599827}, {35049758, 55971572} },
|
{ {34579315, 3599827}, {35049758, 55971572} },
|
||||||
@ -343,16 +343,81 @@ SCENARIO("Path chaining", "[Geometry][!mayfail]") {
|
|||||||
{ {8266122, 14250611}, {6244813, 17751595} },
|
{ {8266122, 14250611}, {6244813, 17751595} },
|
||||||
{ {12177955, 9886741}, {10703348, 11491900} }
|
{ {12177955, 9886741}, {10703348, 11491900} }
|
||||||
};
|
};
|
||||||
Polylines chained = chain_polylines(polylines);
|
const Polylines chained = chain_polylines(polylines);
|
||||||
THEN("Chained taking the shortest path") {
|
THEN("Chained taking the shortest path") {
|
||||||
double connection_length = 0.;
|
double connection_length = 0.;
|
||||||
for (size_t i = 1; i < chained.size(); ++i) {
|
std::cout << "{ {" << chained[0].points.front().x() << ", " << chained[0].points.front().y() << "}, {" << chained[0].points.back().x() << ", " << chained[0].points.back().x() << "} },\n";
|
||||||
const Polyline &pl1 = chained[i - 1];
|
for (size_t i = 1; i < chained.size(); ++i) {
|
||||||
const Polyline &pl2 = chained[i];
|
const Polyline& pl1 = chained[i - 1];
|
||||||
connection_length += (pl2.first_point() - pl1.last_point()).cast<double>().norm();
|
const Polyline& pl2 = chained[i];
|
||||||
}
|
connection_length += (pl2.first_point() - pl1.last_point()).cast<double>().norm();
|
||||||
REQUIRE(connection_length < 85206000.);
|
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") {
|
GIVEN("Loop pieces") {
|
||||||
Point a { 2185796, 19058485 };
|
Point a { 2185796, 19058485 };
|
||||||
|
Loading…
x
Reference in New Issue
Block a user