Review of spacing & volume compute, add a test for that.

Change a bit the fill api, to allow a bit safer spacing init and ensure nothing erase a parameter in mid-compute.
This commit is contained in:
supermerill 2019-11-12 19:08:36 +01:00
parent 9ae142ef3e
commit 9c6008e5e0
17 changed files with 455 additions and 214 deletions

View File

@ -234,6 +234,23 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
if (density <= 0)
continue;
}
//Set Params for fill
// apply half spacing using this flow's own spacing and generate infill
FillParams params;
params.density = float(0.01 * density);
params.dont_adjust = false;
params.fill_exactly = layerm.region()->config().enforce_full_fill_volume.getBool();
params.dont_connect = layerm.region()->config().infill_not_connected.getBool();
//adjust flow (to over-extrude when needed)
float flow_percent = 1;
if (surface.has_pos_top()) flow_percent *= layerm.region()->config().fill_top_flow_ratio.get_abs_value(1);
params.flow_mult = flow_percent;
//adjust spacing (to over-extrude when needed)
if (surface.has_mod_overBridge()) {
params.density = layerm.region()->config().over_bridge_flow_ratio.get_abs_value(1);
}
params.config = &layerm.region()->config();
// get filler object
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(fill_pattern));
@ -249,32 +266,37 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
-1, // auto width
*layerm.layer()->object()
);
// calculate flow spacing for infill pattern generation
bool using_internal_flow = false;
if (! surface.has_fill_solid() && ! is_bridge) {
// it's internal infill, so we can calculate a generic flow spacing
// for all layers, for avoiding the ugly effect of
// misaligned infill on first layer because of different extrusion width and
// layer height
Flow internal_flow = layerm.region()->flow(
frInfill,
layerm.layer()->object()->config().layer_height.value, // TODO: handle infill_every_layers?
false, // no bridge
false, // no first layer
-1, // auto width
*layerm.layer()->object()
);
f->spacing = internal_flow.spacing();
using_internal_flow = true;
} else {
f->spacing = flow.spacing();
{
coordf_t spacing;
if (!surface.has_fill_solid() && !is_bridge) {
// it's internal infill, so we can calculate a generic flow spacing
// for all layers, for avoiding the ugly effect of
// misaligned infill on first layer because of different extrusion width and
// layer height
Flow internal_flow = layerm.region()->flow(
frInfill,
layerm.layer()->object()->config().layer_height.value, // TODO: handle infill_every_layers?
false, // no bridge
false, // no first layer
-1, // auto width
*layerm.layer()->object()
);
spacing = internal_flow.spacing();
using_internal_flow = true;
}
else {
spacing = flow.spacing();
}
f->init_spacing(spacing, params);
}
double link_max_length = 0.;
if (! is_bridge) {
if (density > 80.) // 80%
link_max_length = 3 * f->spacing; // slic3r default : 3
link_max_length = 3 * f->get_spacing(); // slic3r default : 3
}
f->layer_id = layerm.layer()->id();
@ -288,7 +310,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
//give the overlap size to let the infill do his overlap
//add overlap if at least one perimeter
if (layerm.region()->config().perimeters > 0) {
f->overlap = layerm.region()->config().get_abs_value("infill_overlap", (perimeter_spacing + (f->spacing)) / 2);
f->overlap = layerm.region()->config().get_abs_value("infill_overlap", (perimeter_spacing + (f->get_spacing())) / 2);
if (f->overlap!=0) {
f->no_overlap_expolygons = intersection_ex(layerm.fill_no_overlap_expolygons, ExPolygons() = { surface.expolygon });
} else {
@ -298,13 +320,6 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
f->overlap = 0;
f->no_overlap_expolygons.push_back(surface.expolygon);
}
// apply half spacing using this flow's own spacing and generate infill
FillParams params;
params.density = float(0.01 * density);
params.dont_adjust = false;
params.fill_exactly = layerm.region()->config().enforce_full_fill_volume.getBool();
params.dont_connect = layerm.region()->config().infill_not_connected.getBool();
// calculate actual flow from spacing (which might have been adjusted by the infill
// pattern generator)
@ -313,21 +328,10 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
// so we can safely ignore the slight variation that might have
// been applied to $f->flow_spacing
} else {
flow = Flow::new_from_spacing(f->spacing, flow.nozzle_diameter, (float)h, is_bridge);
flow = Flow::new_from_spacing(f->get_spacing(), flow.nozzle_diameter, (float)h, is_bridge);
}
//adjust flow (to over-extrude when needed)
float flow_percent = 1;
if (surface.has_pos_top()) flow_percent *= layerm.region()->config().fill_top_flow_ratio.get_abs_value(1);
params.flow_mult = flow_percent;
//adjust spacing (to over-extrude when needed)
if (surface.has_mod_overBridge()){
params.density = layerm.region()->config().over_bridge_flow_ratio.get_abs_value(1);
}
params.flow = &flow;
params.config = &layerm.region()->config();
f->fill_surface_extrusion(&surface, params, out.entities);
}

View File

@ -15,6 +15,7 @@
#include "FillRectilinear2.hpp"
#include "FillRectilinear3.hpp"
#include "FillSmooth.hpp"
#include "../MedialAxis.hpp"
namespace Slic3r {
@ -55,7 +56,7 @@ Fill* Fill::new_from_type(const std::string &type)
return (it == enum_keys_map.end()) ? nullptr : new_from_type(InfillPattern(it->second));
}
Polylines Fill::fill_surface(const Surface *surface, const FillParams &params)
Polylines Fill::fill_surface(const Surface *surface, const FillParams &params) const
{
// Perform offset.
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, double(scale_(0 - 0.5 * this->spacing)));
@ -140,7 +141,7 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
return std::pair<float, Point>(out_angle, out_shift);
}
void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) {
void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const {
//add overlap & call fill_surface
Polylines polylines = this->fill_surface(surface, params);
if (polylines.empty())
@ -163,14 +164,6 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
double poylineVolume = 0;
for (auto poly = this->no_overlap_expolygons.begin(); poly != this->no_overlap_expolygons.end(); ++poly) {
poylineVolume += params.flow->height*unscaled(unscaled(poly->area()));
// add external "perimeter gap"
double perimeterRoundGap = unscaled(poly->contour.length()) * params.flow->height * (1 - 0.25*PI) * 0.5;
// add holes "perimeter gaps"
double holesGaps = 0;
for (auto hole = poly->holes.begin(); hole != poly->holes.end(); ++hole) {
holesGaps += unscaled(hole->length()) * params.flow->height * (1 - 0.25*PI) * 0.5;
}
poylineVolume += perimeterRoundGap + holesGaps;
}
//printf("process want %f mm3 extruded for a volume of %f space : we mult by %f %i\n",
// extrudedVolume,
@ -203,6 +196,10 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
coord_t Fill::_line_spacing_for_density(float density) const
{
return coord_t(scale_(this->spacing) / density);
}
/// cut poly between poly.point[idx_1] & poly.point[idx_1+1]
/// add p1+-width to one part and p2+-width to the other one.
@ -461,7 +458,8 @@ Points getFrontier(Polylines &polylines, const Point& p1, const Point& p2, const
/// return the connected polylines in polylines_out. Can output polygons (stored as polylines with first_point = last_point).
/// complexity: worst: N(infill_ordered.points) x N(boundary.points)
/// typical: N(infill_ordered) x ( N(boundary.points) + N(infill_ordered.points) )
void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams &params) {
void
Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams &params) const {
//TODO: fallback to the quick & dirty old algorithm when n(points) is too high.
Polylines polylines_frontier = to_polylines(((Polygons)boundary));
@ -573,4 +571,56 @@ void Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boun
}
}
void
Fill::do_gap_fill(const ExPolygons &gapfill_areas, const FillParams &params, ExtrusionEntitiesPtr &coll_out) const {
ThickPolylines polylines_gapfill;
double min = 0.4 * scale_(params.flow->nozzle_diameter) * (1 - INSET_OVERLAP_TOLERANCE);
double max = 2. * params.flow->scaled_width();
// collapse
//be sure we don't gapfill where the perimeters are already touching each other (negative spacing).
min = std::max(min, double(Flow::new_from_spacing(EPSILON, params.flow->nozzle_diameter, params.flow->height, false).scaled_width()));
//ExPolygons gapfill_areas_collapsed = diff_ex(
// offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)),
// offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)),
// true);
ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2));
for (const ExPolygon &ex : gapfill_areas_collapsed) {
//remove too small gaps that are too hard to fill.
//ie one that are smaller than an extrusion with width of min and a length of max.
if (ex.area() > scale_(params.flow->nozzle_diameter)*scale_(params.flow->nozzle_diameter) * 2) {
MedialAxis{ ex, params.flow->scaled_width() * 2, params.flow->scaled_width() / 5, coord_t(params.flow->height) }.build(polylines_gapfill);
}
}
if (!polylines_gapfill.empty() && params.role != erBridgeInfill) {
//test
#ifdef _DEBUG
for (ThickPolyline poly : polylines_gapfill) {
for (coordf_t width : poly.width) {
if (width > params.flow->scaled_width() * 2.2) {
std::cerr << "ERRROR!!!! gapfill width = " << unscaled(width) << " > max_width = " << (params.flow->width * 2) << "\n";
}
}
}
#endif
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, *params.flow);
//set role if needed
if (params.role != erSolidInfill) {
ExtrusionSetRole set_good_role(params.role);
gap_fill.visit(set_good_role);
}
//move them into the collection
if (!gap_fill.entities.empty()) {
ExtrusionEntityCollection *coll_gapfill = new ExtrusionEntityCollection();
coll_gapfill->no_sort = this->no_sort();
coll_gapfill->append(std::move(gap_fill.entities));
coll_out.push_back(coll_gapfill);
}
}
}
} // namespace Slic3r

View File

@ -73,8 +73,6 @@ public:
size_t layer_id;
// Z coordinate of the top print surface, in unscaled coordinates
coordf_t z;
// in unscaled coordinates
coordf_t spacing;
// infill / perimeter overlap, in unscaled coordinates
coordf_t overlap;
ExPolygons no_overlap_expolygons;
@ -88,6 +86,9 @@ public:
coord_t loop_clipping;
// In scaled coordinates. Bounding box of the 2D projection of the object.
BoundingBox bounding_box;
protected:
// in unscaled coordinates, please use init (after settings all others settings) as some algos want to modify the value
coordf_t spacing;
public:
virtual ~Fill() {}
@ -96,15 +97,17 @@ public:
static Fill* new_from_type(const std::string &type);
void set_bounding_box(const Slic3r::BoundingBox &bbox) { bounding_box = bbox; }
virtual void init_spacing(coordf_t spacing, const FillParams &params) { this->spacing = spacing; }
coordf_t get_spacing() const { return spacing; }
// Do not sort the fill lines to optimize the print head path?
virtual bool no_sort() const { return false; }
// This method have to fill the ExtrusionEntityCollection. It call fill_surface by default
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out);
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const;
// Perform the fill.
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) const;
protected:
Fill() :
@ -127,17 +130,19 @@ protected:
unsigned int /* thickness_layers */,
const std::pair<float, Point> & /* direction */,
ExPolygon & /* expolygon */,
Polylines & /* polylines_out */) {};
Polylines & /* polylines_out */) const {};
virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; }
virtual coord_t _line_spacing_for_density(float density) const;
virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;
void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams &params);
void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams &params) const;
void do_gap_fill(const ExPolygons &gapfill_areas, const FillParams &params, ExtrusionEntitiesPtr &coll_out);
void do_gap_fill(const ExPolygons &gapfill_areas, const FillParams &params, ExtrusionEntitiesPtr &coll_out) const;
ExtrusionRole getRoleFromSurfaceType(const FillParams &params, const Surface *surface){
ExtrusionRole getRoleFromSurfaceType(const FillParams &params, const Surface *surface) const {
if (params.role == erNone || params.role == erCustom) {
return params.flow->bridge ?
erBridgeInfill :
@ -165,7 +170,7 @@ public:
}
static Point _align_to_grid(Point coord, Point spacing)
{ return Point(_align_to_grid(coord(0), spacing(0)), _align_to_grid(coord(1), spacing(1))); }
static coord_t _align_to_grid(coord_t coord, coord_t spacing, coord_t base)
static coord_t _align_to_grid(coord_t coord, coord_t spacing, coord_t base)
{ return base + _align_to_grid(coord - base, spacing); }
static Point _align_to_grid(Point coord, Point spacing, Point base)
{ return Point(_align_to_grid(coord(0), spacing(0), base(0)), _align_to_grid(coord(1), spacing(1), base(1))); }

View File

@ -8,30 +8,37 @@
#include "FillConcentric.hpp"
namespace Slic3r {
void FillConcentric::_fill_surface_single(
void
FillConcentric::init_spacing(coordf_t spacing, const FillParams &params)
{
Fill::init_spacing(spacing, params);
if (params.density > 0.9999f && !params.dont_adjust) {
this->spacing = unscale<double>(this->_adjust_solid_spacing(bounding_box.size()(0), _line_spacing_for_density(params.density)));
}
}
void
FillConcentric::_fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out)
Polylines &polylines_out) const
{
// no rotation is supported for this infill pattern
BoundingBox bounding_box = expolygon.contour.bounding_box();
coord_t min_spacing = scale_(this->spacing);
coord_t distance = coord_t(min_spacing / params.density);
coord_t distance = _line_spacing_for_density(params.density);
if (params.density > 0.9999f && !params.dont_adjust) {
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
this->spacing = unscale<double>(distance);
//it's == this->_adjust_solid_spacing(bounding_box.size()(0), _line_spacing_for_density(params.density)) because of the init_spacing()
distance = scale_(this->spacing);
}
Polygons loops = (Polygons)expolygon;
Polygons last = loops;
while (! last.empty()) {
last = offset2(last, -(distance + min_spacing/2), +min_spacing/2);
last = offset2(last, -(distance + scale_(this->spacing) /2), +scale_(this->spacing) /2);
loops.insert(loops.end(), last.begin(), last.end());
}
@ -66,7 +73,7 @@ void FillConcentric::_fill_surface_single(
}
void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, const FillParams &params,
ExtrusionEntitiesPtr &out) {
ExtrusionEntitiesPtr &out) const {
// Perform offset.
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, double(scale_(0 - 0.5 * this->spacing)));
@ -86,19 +93,16 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, cons
// no rotation is supported for this infill pattern
BoundingBox bounding_box = expolygon.contour.bounding_box();
coord_t min_spacing = scale_(this->spacing);
coord_t distance = coord_t(min_spacing / params.density);
coord_t distance = _line_spacing_for_density(params.density);
if (params.density > 0.9999f && !params.dont_adjust) {
distance = this->_adjust_solid_spacing(bounding_box.size().x(), distance);
this->spacing = unscaled(distance);
distance = scale_(this->spacing);
}
ExPolygons gaps;
Polygons loops = (Polygons)expolygon;
Polygons last = loops;
while (!last.empty()) {
Polygons next_onion = offset2(last, -(distance + min_spacing / 2), +min_spacing / 2);
Polygons next_onion = offset2(last, -(distance + scale_(this->spacing) / 2), +scale_(this->spacing) / 2);
loops.insert(loops.end(), next_onion.begin(), next_onion.end());
append(gaps, diff_ex(
offset(last, -0.5f * distance),

View File

@ -12,12 +12,13 @@ public:
protected:
virtual Fill* clone() const { return new FillConcentric(*this); };
void init_spacing(coordf_t spacing, const FillParams &params) override;
virtual void _fill_surface_single(
const FillParams &params,
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out);
Polylines &polylines_out) const;
virtual bool no_sort() const { return true; }
};
@ -29,7 +30,7 @@ public:
protected:
virtual Fill* clone() const { return new FillConcentricWGapFill(*this); };
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const override;
virtual bool no_sort() const { return true; }
};

View File

@ -11,7 +11,7 @@ void FillPlanePath::_fill_surface_single(
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out)
Polylines &polylines_out) const
{
expolygon.rotate(- direction.first);
@ -75,7 +75,7 @@ void FillPlanePath::_fill_surface_single(
}
// Follow an Archimedean spiral, in polar coordinates: r=a+b\theta
Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y)
Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) const
{
// Radius to achieve.
coordf_t rmax = std::sqrt(coordf_t(max_x)*coordf_t(max_x)+coordf_t(max_y)*coordf_t(max_y)) * std::sqrt(2.) + 1.5;
@ -145,7 +145,7 @@ static inline Point hilbert_n_to_xy(const size_t n)
return Point(x, y);
}
Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y)
Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) const
{
// Minimum power of two square to fit the domain.
size_t sz = 2;
@ -168,7 +168,7 @@ Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x,
return line;
}
Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y)
Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) const
{
// Radius to achieve.
coordf_t rmax = std::sqrt(coordf_t(max_x)*coordf_t(max_x)+coordf_t(max_y)*coordf_t(max_y)) * std::sqrt(2.) + 1.5;

View File

@ -24,11 +24,11 @@ protected:
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out) override;
Polylines &polylines_out) const override;
virtual float _layer_angle(size_t idx) const { return 0.f; }
virtual bool _centered() const = 0;
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) = 0;
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) const = 0;
};
class FillArchimedeanChords : public FillPlanePath
@ -39,7 +39,7 @@ public:
protected:
virtual bool _centered() const { return true; }
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y);
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) const;
};
class FillHilbertCurve : public FillPlanePath
@ -50,7 +50,7 @@ public:
protected:
virtual bool _centered() const { return false; }
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y);
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) const;
};
class FillOctagramSpiral : public FillPlanePath
@ -61,7 +61,7 @@ public:
protected:
virtual bool _centered() const { return true; }
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y);
virtual Pointfs _generate(coord_t min_x, coord_t min_y, coord_t max_x, coord_t max_y) const;
};
} // namespace Slic3r

View File

@ -865,12 +865,18 @@ std::vector<SegmentedIntersectionLine> FillRectilinear2::_vert_lines_for_polygon
return segs;
}
coord_t FillRectilinear2::_line_spacing_for_density(float density) const
void
FillRectilinear2::init_spacing(coordf_t spacing, const FillParams &params)
{
return coord_t(scale_(this->spacing) / density);
Fill::init_spacing(spacing, params);
//remove this code path becaus it's only really useful for squares at 45° and it override a setting
// define flow spacing according to requested density
//if (params.full_infill() && !params.dont_adjust) {
// this->spacing = unscale<coordf_t>(this->_adjust_solid_spacing(bounding_box.size()(0), _line_spacing_for_density(params.density)));
//}
}
bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out)
bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out) const
{
// At the end, only the new polylines will be rotated back.
size_t n_polylines_out_initial = polylines_out.size();
@ -904,8 +910,8 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
// define flow spacing according to requested density
if (params.full_infill() && !params.dont_adjust) {
line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
this->spacing = unscale<double>(line_spacing);
//it's == this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing) because of the init_spacing
line_spacing = scale_(this->spacing);
} else {
// extend bounding box so that our pattern will be aligned with other layers
// Transform the reference point to the rotated coordinate system.
@ -1441,7 +1447,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
return true;
}
Polylines FillRectilinear2::fill_surface(const Surface *surface, const FillParams &params)
Polylines FillRectilinear2::fill_surface(const Surface *surface, const FillParams &params) const
{
Polylines polylines_out;
if (!fill_surface_by_lines(surface, params, 0.f, 0.f, polylines_out)) {
@ -1450,7 +1456,7 @@ Polylines FillRectilinear2::fill_surface(const Surface *surface, const FillParam
return polylines_out;
}
Polylines FillGrid2::fill_surface(const Surface *surface, const FillParams &params)
Polylines FillGrid2::fill_surface(const Surface *surface, const FillParams &params) const
{
// Each linear fill covers half of the target coverage.
FillParams params2 = params;
@ -1463,7 +1469,7 @@ Polylines FillGrid2::fill_surface(const Surface *surface, const FillParams &para
return polylines_out;
}
Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams &params)
Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams &params) const
{
// Each linear fill covers 1/3 of the target coverage.
FillParams params2 = params;
@ -1479,7 +1485,7 @@ Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams &
return polylines_out;
}
Polylines FillStars::fill_surface(const Surface *surface, const FillParams &params)
Polylines FillStars::fill_surface(const Surface *surface, const FillParams &params) const
{
// Each linear fill covers 1/3 of the target coverage.
FillParams params2 = params;
@ -1495,7 +1501,7 @@ Polylines FillStars::fill_surface(const Surface *surface, const FillParams &para
return polylines_out;
}
Polylines FillCubic::fill_surface(const Surface *surface, const FillParams &params)
Polylines FillCubic::fill_surface(const Surface *surface, const FillParams &params) const
{
// Each linear fill covers 1/3 of the target coverage.
FillParams params2 = params;
@ -1515,7 +1521,7 @@ Polylines FillCubic::fill_surface(const Surface *surface, const FillParams &para
void
FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out)
FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const
{
ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection();
//you don't want to sort the extrusions: big infill first, small second
@ -1623,7 +1629,7 @@ coord_t FillScatteredRectilinear::_line_spacing_for_density(float density) const
return coord_t(scale_(this->spacing) / 1.0);
}
Polylines FillScatteredRectilinear::fill_surface(const Surface *surface, const FillParams &params)
Polylines FillScatteredRectilinear::fill_surface(const Surface *surface, const FillParams &params) const
{
Polylines polylines_out;
@ -1659,7 +1665,7 @@ std::vector<SegmentedIntersectionLine> FillScatteredRectilinear::_vert_lines_for
void
FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) {
FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const {
const coord_t scaled_nozzle_diam = scale_(params.flow->nozzle_diameter);
const coord_t clearance = scaled_nozzle_diam * 2;
const coord_t tooth_spacing_min = scaled_nozzle_diam;
@ -1770,7 +1776,8 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi
}
void FillRectilinear2WGapFill::split_polygon_gap_fill(const Surface &surface, const FillParams &params, ExPolygons &rectilinear, ExPolygons &gapfill) {
void
FillRectilinear2WGapFill::split_polygon_gap_fill(const Surface &surface, const FillParams &params, ExPolygons &rectilinear, ExPolygons &gapfill) {
// remove areas for gapfill
// factor=0.5 : remove area smaller than a spacing. factor=1 : max spacing for the gapfill (but not the width)
@ -1786,7 +1793,7 @@ void FillRectilinear2WGapFill::split_polygon_gap_fill(const Surface &surface, co
}
void
FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) {
FillRectilinear2WGapFill::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
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
@ -1889,55 +1896,5 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
}
void
Fill::do_gap_fill(const ExPolygons &gapfill_areas, const FillParams &params, ExtrusionEntitiesPtr &coll_out) {
ThickPolylines polylines_gapfill;
double min = 0.4 * scale_(params.flow->nozzle_diameter) * (1 - INSET_OVERLAP_TOLERANCE);
double max = 2. * params.flow->scaled_width();
// collapse
//be sure we don't gapfill where the perimeters are already touching each other (negative spacing).
min = std::max(min, double(Flow::new_from_spacing(EPSILON, params.flow->nozzle_diameter, params.flow->height, false).scaled_width()));
//ExPolygons gapfill_areas_collapsed = diff_ex(
// offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2)),
// offset2_ex(gapfill_areas, double(-max / 2), double(+max / 2)),
// true);
ExPolygons gapfill_areas_collapsed = offset2_ex(gapfill_areas, double(-min / 2), double(+min / 2));
for (const ExPolygon &ex : gapfill_areas_collapsed) {
//remove too small gaps that are too hard to fill.
//ie one that are smaller than an extrusion with width of min and a length of max.
if (ex.area() > scale_(params.flow->nozzle_diameter)*scale_(params.flow->nozzle_diameter) * 2) {
MedialAxis{ ex, params.flow->scaled_width() * 2, params.flow->scaled_width() / 5, coord_t(params.flow->height) }.build(polylines_gapfill);
}
}
if (!polylines_gapfill.empty() && params.role != erBridgeInfill) {
//test
#ifdef _DEBUG
for (ThickPolyline poly : polylines_gapfill) {
for (coordf_t width : poly.width) {
if (width > params.flow->scaled_width() * 2.2) {
std::cerr << "ERRROR!!!! recti gapfill width = " << unscaled(width) << " > max_width = " << (params.flow->width * 2) << "\n";
}
}
}
#endif
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, *params.flow);
//set role if needed
if (params.role != erSolidInfill) {
ExtrusionSetRole set_good_role(params.role);
gap_fill.visit(set_good_role);
}
//move them into the collection
if (!gap_fill.entities.empty()) {
ExtrusionEntityCollection *coll_gapfill = new ExtrusionEntityCollection();
coll_gapfill->no_sort = this->no_sort();
coll_gapfill->append(std::move(gap_fill.entities));
coll_out.push_back(coll_gapfill);
}
}
}
} // namespace Slic3r

View File

@ -16,13 +16,13 @@ class FillRectilinear2 : public Fill
public:
virtual Fill* clone() const { return new FillRectilinear2(*this); };
virtual ~FillRectilinear2() {}
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
void init_spacing(coordf_t spacing, const FillParams &params) override;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) const override;
protected:
virtual std::vector<SegmentedIntersectionLine> _vert_lines_for_polygon(const ExPolygonWithOffset &poly_with_offset, const BoundingBox &bounding_box, const FillParams &params, coord_t line_spacing) const;
virtual coord_t _line_spacing_for_density(float density) const;
bool fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out);
bool fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out) const;
};
class FillGrid2 : public FillRectilinear2
@ -30,7 +30,7 @@ class FillGrid2 : public FillRectilinear2
public:
virtual Fill* clone() const { return new FillGrid2(*this); };
virtual ~FillGrid2() {}
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) const override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
@ -42,7 +42,7 @@ class FillTriangles : public FillRectilinear2
public:
virtual Fill* clone() const { return new FillTriangles(*this); };
virtual ~FillTriangles() {}
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) const override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
@ -54,7 +54,7 @@ class FillStars : public FillRectilinear2
public:
virtual Fill* clone() const { return new FillStars(*this); };
virtual ~FillStars() {}
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) const override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
@ -66,7 +66,7 @@ class FillCubic : public FillRectilinear2
public:
virtual Fill* clone() const { return new FillCubic(*this); };
virtual ~FillCubic() {}
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) const override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
@ -80,7 +80,7 @@ public:
virtual Fill* clone() const { return new FillRectilinear2Peri(*this); };
virtual ~FillRectilinear2Peri() {}
//virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const override;
};
@ -90,7 +90,7 @@ class FillScatteredRectilinear : public FillRectilinear2
public:
virtual Fill* clone() const override{ return new FillScatteredRectilinear(*this); };
virtual ~FillScatteredRectilinear() {}
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) const override;
protected:
virtual float _layer_angle(size_t idx) const;
@ -103,7 +103,7 @@ public:
virtual Fill* clone() const { return new FillRectilinearSawtooth(*this); };
virtual ~FillRectilinearSawtooth() {}
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const override;
};
@ -113,7 +113,7 @@ public:
virtual Fill* clone() const { return new FillRectilinear2WGapFill(*this); };
virtual ~FillRectilinear2WGapFill() {}
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const override;
static void split_polygon_gap_fill(const Surface &surface, const FillParams &params, ExPolygons &rectilinear, ExPolygons &gapfill);
};

View File

@ -10,7 +10,7 @@
namespace Slic3r {
Polylines FillSmooth::fill_surface(const Surface *surface, const FillParams &params)
Polylines FillSmooth::fill_surface(const Surface *surface, const FillParams &params) const
{
//ERROR: you shouldn't call that. Default to the rectilinear one.
printf("FillSmooth::fill_surface() : you call the wrong method (fill_surface instead of fill_surface_extrusion).\n");
@ -20,7 +20,7 @@ namespace Slic3r {
/// @idx: the index of the step (0 = first step, 1 = second step, ...) The first lay down the volume and the others smoothen the surface.
void FillSmooth::perform_single_fill(const int idx, ExtrusionEntityCollection &eecroot, const Surface &srf_source,
const FillParams &params, const double volume){
const FillParams &params, const double volume) const {
if (srf_source.expolygon.empty()) return;
// Save into layer smoothing path.
@ -44,7 +44,7 @@ namespace Slic3r {
}
else{
Surface surfaceNoOverlap(srf_source);
for (ExPolygon &poly : this->no_overlap_expolygons) {
for (const ExPolygon &poly : this->no_overlap_expolygons) {
if (poly.empty()) continue;
surfaceNoOverlap.expolygon = poly;
this->fill_expolygon(idx, *eec, surfaceNoOverlap, params_modifided, volume);
@ -56,11 +56,11 @@ namespace Slic3r {
}
void FillSmooth::fill_expolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill,
const FillParams &params, const double volume){
const FillParams &params, const double volume) const {
std::unique_ptr<Fill> f2 = std::unique_ptr<Fill>(Fill::new_from_type(fillPattern[idx]));
f2->bounding_box = this->bounding_box;
f2->spacing = this->spacing;
f2->init_spacing(this->get_spacing(),params);
f2->layer_id = this->layer_id;
f2->z = this->z;
f2->angle = anglePass[idx] + this->angle;
@ -102,7 +102,7 @@ namespace Slic3r {
}
void FillSmooth::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out)
void FillSmooth::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const
{
coordf_t init_spacing = this->spacing;

View File

@ -37,8 +37,8 @@ public:
}
virtual Fill* clone() const{ return new FillSmooth(*this); }
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) const override;
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) const override;
protected:
int nbPass=2;
@ -56,9 +56,9 @@ protected:
InfillPattern fillPattern[3];
void perform_single_fill(const int idx, ExtrusionEntityCollection &eecroot, const Surface &srf_source,
const FillParams &params, const double volume);
const FillParams &params, const double volume) const;
void fill_expolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill,
const FillParams &params, const double volume);
const FillParams &params, const double volume) const;
};

View File

@ -1220,9 +1220,9 @@ void PrintConfigDef::init_fff_params()
def->full_label = L("Ironing flow distribution");
def->category = OptionCategory::infill;
def->tooltip = L("This is the percentage of the flow that is used for the second ironing pass. Typical 0-20%. "
"Should not be lower than 20%, unless you have your top extrusion width greatly superior to your nozzle width.");
def->min = 0;
def->max = 0.9;
"Should not be higher than 20%, unless you have your top extrusion width greatly superior to your nozzle width.");
//def->min = 0;
//def->max = 0.9;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloatOrPercent(10, true));

View File

@ -2337,7 +2337,8 @@ static inline void fill_expolygons_generate_paths(
Fill *filler,
float density,
ExtrusionRole role,
const Flow &flow)
const Flow &flow,
coordf_t spacing)
{
FillParams fill_params;
fill_params.density = density;
@ -2345,6 +2346,7 @@ static inline void fill_expolygons_generate_paths(
fill_params.dont_adjust = true;
fill_params.flow = &flow;
fill_params.role = role;
filler->init_spacing(spacing, fill_params);
for (ExPolygon &expoly : expolygons) {
Surface surface(stPosInternal | stDensSparse, std::move(expoly));
filler->fill_surface_extrusion(&surface, fill_params, dst);
@ -3059,8 +3061,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// value that guarantees that all layers are correctly aligned.
Fill *filler = filler_support.get();
filler->angle = raft_angle_base;
filler->spacing = m_support_material_flow.spacing();
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_density));
filler->link_max_length = coord_t(scale_(m_support_material_flow.spacing() * link_max_length_factor / support_density));
fill_expolygons_generate_paths(
// Destination
support_layer.support_fills.entities,
@ -3069,7 +3070,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Filler and its parameters
filler, float(support_density),
// Extrusion parameters
erSupportMaterial, flow);
erSupportMaterial, flow, m_support_material_flow.spacing());
}
}
}
@ -3077,6 +3078,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
Fill *filler = filler_interface.get();
Flow flow = m_first_layer_flow;
float density = 0.f;
coordf_t spacing = 0.f;
if (support_layer_id == 0) {
// Base flange.
if (this->m_object_config->support_material_solid_first_layer.value) {
@ -3088,17 +3090,17 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// 70% of density on the 1st layer.
density = 0.7f;
}
filler->spacing = m_first_layer_flow.spacing();
spacing = m_first_layer_flow.spacing();
} else if (support_layer_id >= m_slicing_params.base_raft_layers) {
filler->angle = raft_angle_interface;
// We don't use $base_flow->spacing because we need a constant spacing
// value that guarantees that all layers are correctly aligned.
filler->spacing = m_support_material_flow.spacing();
spacing = m_support_material_flow.spacing();
flow = Flow(float(m_support_material_interface_flow.width), float(raft_layer.height), m_support_material_flow.nozzle_diameter, raft_layer.bridging);
density = float(interface_density);
} else
continue;
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
filler->link_max_length = coord_t(scale_(spacing * link_max_length_factor / density));
fill_expolygons_generate_paths(
// Destination
support_layer.support_fills.entities,
@ -3107,7 +3109,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Filler and its parameters
filler, density,
// Extrusion parameters
(support_layer_id < m_slicing_params.base_raft_layers) ? erSupportMaterial : erSupportMaterialInterface, flow);
(support_layer_id < m_slicing_params.base_raft_layers) ? erSupportMaterial : erSupportMaterialInterface, flow, spacing);
}
});
@ -3214,21 +3216,22 @@ void PrintObjectSupportMaterial::generate_toolpaths(
layer_ex.layer->bridging);
Fill *filler = i == 2 ? filler_intermediate_interface.get() : filler_interface.get();
float density = interface_density;
coordf_t spacing;
//if first layer and solid first layer : draw concentric with 100% density
if (support_layer.id() == 0 && this->m_object_config->support_material_solid_first_layer.value) {
filler = filler_solid.get();
density = 1.f;
interface_flow = m_first_layer_flow;
filler->angle = 0;
filler->spacing = interface_flow.spacing();
spacing = interface_flow.spacing();
} else {
filler->angle = interface_as_base ?
// If zero interface layers are configured, use the same angle as for the base layers.
angles[support_layer_id % angles.size()] :
// Use interface angle for the interface layers.
interface_angle;
filler->spacing = m_support_material_interface_flow.spacing();
filler->link_max_length = coord_t(scale_(filler_interface->spacing * link_max_length_factor / density));
spacing = m_support_material_interface_flow.spacing();
filler->link_max_length = coord_t(scale_(spacing * link_max_length_factor / density));
}
fill_expolygons_generate_paths(
// Destination
@ -3238,7 +3241,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Filler and its parameters
filler, float(density),
// Extrusion parameters
erSupportMaterialInterface, interface_flow);
erSupportMaterialInterface, interface_flow, spacing);
}
// Base support or flange.
@ -3253,8 +3256,8 @@ void PrintObjectSupportMaterial::generate_toolpaths(
float(base_layer.layer->height),
m_support_material_flow.nozzle_diameter,
base_layer.layer->bridging);
filler->spacing = m_support_material_flow.spacing();
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / support_density));
coordf_t spacing = m_support_material_flow.spacing();
filler->link_max_length = coord_t(scale_(spacing * link_max_length_factor / support_density));
float density = float(support_density);
// find centerline of the external loop/extrusions
ExPolygons to_infill = (support_layer_id == 0 || ! with_sheath) ?
@ -3271,12 +3274,12 @@ void PrintObjectSupportMaterial::generate_toolpaths(
filler = filler_interface.get();
filler->angle = Geometry::deg2rad(float(m_object_config->support_material_angle.value + 90.));
density = 0.5f;
filler->link_max_length = coord_t(scale_(filler->spacing * link_max_length_factor / density));
filler->link_max_length = coord_t(scale_(spacing * link_max_length_factor / density));
}
// use the proper spacing for first layer as we don't need to align
// its pattern to the other layers
flow = m_first_layer_flow;
filler->spacing = flow.spacing();
spacing = flow.spacing();
} else if (with_sheath) {
// Draw a perimeter all around the support infill. This makes the support stable, but difficult to remove.
// TODO: use brim ordering algorithm
@ -3296,7 +3299,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
// Filler and its parameters
filler, density,
// Extrusion parameters
erSupportMaterial, flow);
erSupportMaterial, flow, spacing);
}
layer_cache.overlaps.reserve(4);

View File

@ -56,7 +56,6 @@ class Surface
public:
SurfaceType surface_type;
ExPolygon expolygon;
ExPolygons notOverlaps;
double thickness; // in mm
unsigned short thickness_layers; // in layers
double bridge_angle; // in radians, ccw, 0 = East, only 0+ (negative means undefined)

View File

@ -9,9 +9,11 @@
#include "../../libslic3r/Flow.hpp"
#include "../../libslic3r/ClipperUtils.hpp"
#include "../../libslic3r/SVG.hpp"
#include "../test_data.hpp" // get access to init_print, etc
using namespace Slic3r;
using namespace Slic3r::Geometry;
using namespace Slic3r::Test;
bool test_if_solid_surface_filled(const ExPolygon& expolygon, double flow_spacing, double angle = 0, double density = 1.0);
@ -32,10 +34,11 @@ Polylines test(const ExPolygon& poly, Fill &filler, const FillParams &params){
TEST_CASE("Fill: Pattern Path Length") {
Fill* filler {Slic3r::Fill::new_from_type("rectilinear")};
filler->angle = -(PI) / 2.0;
filler->spacing = 5;
FillParams params{};
params.dont_adjust = true;
params.density = filler->spacing / 50.0;
FillParams params{};
params.dont_adjust = true;
params.density = 0.1; // 5/50
filler->set_bounding_box(BoundingBox(Point(0, 0), Point::new_scale(Point(100, 100))));
filler->init_spacing(5, params);
//params.endpoints_overlap = false;
@ -85,7 +88,7 @@ TEST_CASE("Fill: Pattern Path Length") {
for (double angle : {-(PI/2.0), -(PI/4.0), -(PI), PI/2.0, PI}) {
for (double spacing : {25.0, 5.0, 7.5, 8.5}) {
FillParams params_local = params;
params_local.density = filler->spacing / spacing;
params_local.density = filler->get_spacing() / spacing;
filler->angle = angle;
Slic3r::ExPolygon e{};
e.contour = Slic3r::Polygon(test_square);
@ -110,14 +113,15 @@ TEST_CASE("Fill: Pattern Path Length") {
}
SECTION("Regression: Missing infill segments in some rare circumstances") {
FillParams params_local = params;
params_local.density = 1;
params_local.dont_adjust = false;
Fill* filler_local = { Slic3r::Fill::new_from_type("rectilinear") };
filler_local->angle = (PI/4.0);
params_local.dont_adjust = false;
filler_local->spacing = 0.654498;
filler_local->set_bounding_box(BoundingBox(Point(0, 0), Point(2512749, 2512749)));
filler_local->init_spacing(0.654498, params_local);
//filler_local->endpoints_overlap = unscale(359974);
params_local.density = 1;
filler_local->layer_id = 66;
filler_local->z = 20.15;
filler_local->layer_id = 66;
filler_local->z = 20.15;
Points points {Point{25771516,14142125},Point{14142138,25771515},Point{2512749,14142131},Point{14142125,2512749}};
Slic3r::ExPolygon expoly{};
@ -142,8 +146,8 @@ TEST_CASE("Fill: Pattern Path Length") {
Surface surface {(stPosTop|stDensSolid), expolygon};
Flow flow {0.69f, 0.4f, 0.50f};
filler->spacing = flow.spacing();
params.density = 1.0;
params.density = 1.0;
filler->init_spacing(flow.spacing(), params);
for (auto angle : { 0.0, 45.0}) {
surface.expolygon.rotate(angle, Point{0,0});
@ -204,6 +208,219 @@ TEST_CASE("Fill: Pattern Path Length") {
}
class ExtrusionGetVolume : public ExtrusionVisitor {
double volume = 0;
public:
ExtrusionGetVolume() {}
void use(ExtrusionPath &path) override {
volume += unscaled(path.length()) * path.mm3_per_mm; }
void use(ExtrusionPath3D &path3D) override { volume += unscaled(path3D.length()) * path3D.mm3_per_mm; }
void use(ExtrusionMultiPath &multipath) override { for (ExtrusionPath path : multipath.paths) path.visit(*this); }
void use(ExtrusionMultiPath3D &multipath) override { for (ExtrusionPath path : multipath.paths) path.visit(*this); }
void use(ExtrusionLoop &loop) override { for (ExtrusionPath path : loop.paths) path.visit(*this); }
void use(ExtrusionEntityCollection &collection) override { for (ExtrusionEntity *entity : collection.entities) entity->visit(*this); }
double get(ExtrusionEntityCollection &coll) {
for (ExtrusionEntity *entity : coll.entities) entity->visit(*this);
return volume;
}
};
#include "../../libslic3r/GCodeReader.hpp"
TEST_CASE("Fill: extrude gcode and check it")
{
SECTION("simple square") {
Model model{};
TriangleMesh sample_mesh = make_cube(5, 5, 0.2);
double volume = (5 * 5 * 0.2);
sample_mesh.repair();
DynamicPrintConfig *config = Slic3r::DynamicPrintConfig::new_from_defaults();
config->set_key_value("perimeters", new ConfigOptionInt(1));
config->set_key_value("top_solid_layers", new ConfigOptionInt(1));
config->set_key_value("bottom_solid_layers", new ConfigOptionInt(1));
config->set_key_value("enforce_full_fill_volume", new ConfigOptionBool(true));
config->set_key_value("infill_overlap", new ConfigOptionFloatOrPercent(0.1, true));
config->set_key_value("skirts", new ConfigOptionInt(0));
config->set_key_value("layer_height", new ConfigOptionFloat(0.2)); // get a known number of layers
config->set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.2, false));
config->set_key_value("extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("infill_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("perimeter_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("first_layer_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("external_perimeter_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("solid_infill_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("top_infill_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
auto event_counter{ 0U };
std::string stage;
Print print{};
Slic3r::Test::init_print(print, { sample_mesh }, model, config);
print.process();
std::string gcode_filepath{ "" };
Slic3r::Test::gcode(gcode_filepath, print);
//std::cout << "gcode generation done\n";
std::string gcode_from_file = read_to_string(gcode_filepath);
//string[] lineArray = gcode_from_file
GCodeReader parser;
double volume_extruded = 0;
int idx = 0;
double volume_perimeter_extruded = 0;
double volume_infill_extruded = 0;
// add remaining time lines where needed
parser.parse_buffer(gcode_from_file,
[&](GCodeReader& reader, const GCodeReader::GCodeLine& line)
{
if (line.cmd_is("G1"))
{
if (line.dist_E(reader) > 0 && line.dist_XY(reader) > 0) {
//std::cout << "add " << line.dist_E(reader)<<" now "<< volume_extruded<<"=>";
volume_extruded += line.dist_E(reader)*(PI*1.75*1.75 / 4.);
//std::cout << volume_extruded << "\n";
if (idx<4)volume_perimeter_extruded += line.dist_E(reader)*(PI*1.75*1.75 / 4.);
else volume_infill_extruded += line.dist_E(reader)*(PI*1.75*1.75 / 4.);
idx++;
}
}
});
double perimeterRoundGapRemove = unscaled(print.objects()[0]->layers()[0]->slices.expolygons[0].contour.length()) * 0.1*0.1 * (2 - (PI / 2));
double perimeterRoundGapAdd = unscaled(print.objects()[0]->layers()[0]->slices.expolygons[0].contour.length()) * 0.1*0.1 * ((PI / 2));
//for (Line &l : print.objects()[0]->layers()[0]->slices.expolygons[0].contour.lines()) {
//}
//std::cout << "flow mm3permm: " << Flow{ 0.5f,0.2f,0.4f,false }.mm3_per_mm() << "\n";
//std::cout << "perimeter : " << unscaled(print.objects()[0]->layers()[0]->slices.expolygons[0].contour.length()) << " != " << (PI * 10) << "\n";
//std::cout << "created a mesh of volume " << volume << " and i have extruded " << volume_extruded << " mm3.\n";
//std::cout << "Note that if we remove the bits of the external extrusion, it's only a volume of " << (volume - perimeterRoundGapRemove) << " that needs to be filled\n";
//std::cout << "Note that if we add the bits of the external extrusion, it's a volume of " << (volume + perimeterRoundGapAdd) << " that needs to be filled\n";
double volumeExtrPerimeter = ExtrusionGetVolume{}.get(print.objects()[0]->layers()[0]->regions()[0]->perimeters);
double volumeExtrInfill = ExtrusionGetVolume{}.get(print.objects()[0]->layers()[0]->regions()[0]->fills);
double volumeInfill = 0;
for (const ExPolygon & p : print.objects()[0]->layers()[0]->regions()[0]->fill_no_overlap_expolygons) {
volumeInfill += unscaled(unscaled(p.area()));
}
volumeInfill *= 0.2;/*
std::cout << "volumeRealr=" << (volume_perimeter_extruded + volume_infill_extruded) << " volumeRealPerimeter= " << volume_perimeter_extruded << " and volumeRealInfill=" << volume_infill_extruded << " mm3." << "\n";
std::cout << "volumeExtr=" << (volumeExtrPerimeter + volumeExtrInfill) << " volumeExtrPerimeter= " << volumeExtrPerimeter << " and volumeExtrInfill=" << volumeExtrInfill << " mm3." << "\n";
std::cout << "volumePerimeter= " << (volume - volumeInfill) << " volumePerimeter(wo/bits)= " << (volume - volumeInfill- perimeterRoundGapRemove) << " and volumeInfill=" << volumeInfill << " mm3." << "\n";*/
//Flow fl{0.5f, 0.2f, 0.4f, false};
//{
// std::stringstream stri;
// stri << "extrusion_width_learning" << ".svg";
// SVG svg(stri.str());
// //svg.draw(bounds);
// svg.draw(print.objects()[0]->layers()[0]->slices.expolygons[0].contour, "green");
// svg.draw(print.objects()[0]->layers()[0]->regions()[0]->fill_no_overlap_expolygons, "black", scale_(0.01));
// svg.draw(print.objects()[0]->layers()[0]->regions()[0]->perimeters.as_polylines(), "orange", fl.scaled_width());
// svg.draw(print.objects()[0]->layers()[0]->regions()[0]->perimeters.as_polylines(), "red", fl.scaled_spacing());
// svg.draw(print.objects()[0]->layers()[0]->regions()[0]->fills.as_polylines(), "cyan", fl.scaled_width());
// svg.draw(print.objects()[0]->layers()[0]->regions()[0]->fills.as_polylines(), "blue", fl.scaled_spacing());
// svg.Close();
//}
//std::cout << gcode_from_file;
REQUIRE(abs(volumeInfill - volumeExtrInfill) < EPSILON);
REQUIRE(abs(volumeInfill - volume_infill_extruded) < 0.01);
REQUIRE(abs((volume - volumeInfill - perimeterRoundGapRemove) - volumeExtrPerimeter) < 0.01);
REQUIRE(abs((volume - volumeInfill - perimeterRoundGapRemove) - volume_perimeter_extruded) < 0.1); //there are a bit less for seam mitigation
clean_file(gcode_filepath, "gcode");
}
SECTION("simple disk") {
Model model{};
TriangleMesh sample_mesh = make_cylinder(5, 0.2);
double volume = (PI * 25 * 0.2);
sample_mesh.repair();
DynamicPrintConfig *config = Slic3r::DynamicPrintConfig::new_from_defaults();
config->set_key_value("perimeters", new ConfigOptionInt(1));
config->set_key_value("top_solid_layers", new ConfigOptionInt(1));
config->set_key_value("bottom_solid_layers", new ConfigOptionInt(1));
config->set_key_value("enforce_full_fill_volume", new ConfigOptionBool(true));
config->set_key_value("infill_overlap", new ConfigOptionFloatOrPercent(0.1, true));
config->set_key_value("skirts", new ConfigOptionInt(0));
config->set_key_value("layer_height", new ConfigOptionFloat(0.2)); // get a known number of layers
config->set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.2, false));
config->set_key_value("extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("infill_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("perimeter_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("first_layer_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("external_perimeter_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("solid_infill_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("top_infill_extrusion_width", new ConfigOptionFloatOrPercent(0.5, false));
auto event_counter{ 0U };
std::string stage;
Print print{};
Slic3r::Test::init_print(print, { sample_mesh }, model, config);
print.process();
std::string gcode_filepath{ "" };
Slic3r::Test::gcode(gcode_filepath, print);
//std::cout << "gcode generation done\n";
std::string gcode_from_file = read_to_string(gcode_filepath);
//string[] lineArray = gcode_from_file
GCodeReader parser;
double volume_extruded = 0;
int idx = 0;
double volume_perimeter_extruded = 0;
double volume_infill_extruded = 0;
// add remaining time lines where needed
parser.parse_buffer(gcode_from_file,
[&](GCodeReader& reader, const GCodeReader::GCodeLine& line)
{
if (line.cmd_is("G1"))
{
if (line.dist_E(reader) > 0 && line.dist_XY(reader) > 0) {
//std::cout << "add " << line.dist_E(reader)<<" now "<< volume_extruded<<"=>";
volume_extruded += line.dist_E(reader)*(PI*1.75*1.75 / 4.);
//std::cout << volume_extruded << "\n";
if (idx<36)volume_perimeter_extruded += line.dist_E(reader)*(PI*1.75*1.75 / 4.);
else volume_infill_extruded += line.dist_E(reader)*(PI*1.75*1.75 / 4.);
idx++;
}
}
});
double perimeterRoundGapRemove = unscaled(print.objects()[0]->layers()[0]->slices.expolygons[0].contour.length()) * 0.1*0.1 * (2 - (PI / 2));
double perimeterRoundGapAdd = unscaled(print.objects()[0]->layers()[0]->slices.expolygons[0].contour.length()) * 0.1*0.1 * ((PI / 2));
double volumeExtrPerimeter = ExtrusionGetVolume{}.get(print.objects()[0]->layers()[0]->regions()[0]->perimeters);
double volumeExtrInfill = ExtrusionGetVolume{}.get(print.objects()[0]->layers()[0]->regions()[0]->fills);
double volumeInfill = 0;
for (const ExPolygon & p : print.objects()[0]->layers()[0]->regions()[0]->fill_no_overlap_expolygons) {
volumeInfill += unscaled(unscaled(p.area()));
}
volumeInfill *= 0.2;
std::cout << "volumeRealr=" << (volume_perimeter_extruded + volume_infill_extruded) << " volumeRealPerimeter= " << volume_perimeter_extruded << " and volumeRealInfill=" << volume_infill_extruded << " mm3." << "\n";
std::cout << "volumeExtr=" << (volumeExtrPerimeter + volumeExtrInfill) << " volumeExtrPerimeter= " << volumeExtrPerimeter << " and volumeExtrInfill=" << volumeExtrInfill << " mm3." << "\n";
std::cout << "volumePerimeter= " << (volume - volumeInfill) << " volumePerimeter(wo/bits)= " << (volume - volumeInfill - perimeterRoundGapRemove) << " and volumeInfill=" << volumeInfill << " mm3." << "\n";
REQUIRE(abs(volumeInfill - volumeExtrInfill) < EPSILON);
REQUIRE(abs(volumeInfill - volume_infill_extruded) < 0.01);
REQUIRE(abs((volume - volumeInfill - perimeterRoundGapRemove) - volumeExtrPerimeter) < EPSILON);
REQUIRE(abs((volume - volumeInfill - perimeterRoundGapRemove) - volume_perimeter_extruded) < 0.1); //there are a bit less for seam mitigation
clean_file(gcode_filepath, "gcode");
}
}
/*
{
@ -458,8 +675,8 @@ bool test_if_solid_surface_filled(const ExPolygon& expolygon, double flow_width,
//note: here we do flow.width = flow_width , flow.gheight = 0.4, flow.nozzle_size = flow_width;
Flow flow(flow_width, 0.4, flow_width);
filler->spacing = flow.spacing();
params.density = density;
params.density = density;
filler->init_spacing(flow.spacing(), params);
Polylines paths {filler->fill_surface(&surface, params)};
@ -469,7 +686,7 @@ bool test_if_solid_surface_filled(const ExPolygon& expolygon, double flow_width,
// figure out what is actually going on here re: data types
std::for_each(paths.begin(), paths.end(), [filler, &grown_paths] (const Slic3r::Polyline& p) {
polygons_append(grown_paths, offset(p, scale_(filler->spacing / 2.0)));
polygons_append(grown_paths, offset(p, scale_(filler->get_spacing() / 2.0)));
});
ExPolygons uncovered = diff_ex(expolygon, grown_paths, true);

View File

@ -88,7 +88,8 @@ SCENARIO("Print: Changing number of solid surfaces does not cause all surfaces t
config->set_key_value("top_solid_layers", new ConfigOptionInt(2));
config->set_key_value("bottom_solid_layers", new ConfigOptionInt(1));
config->set_key_value("layer_height", new ConfigOptionFloat(0.5)); // get a known number of layers
config->set_key_value("first_layer_height", new ConfigOptionFloat(0.5));
config->set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(0.5, false));
config->set_key_value("enforce_full_fill_volume", new ConfigOptionBool(true));
Slic3r::Model model;
auto event_counter {0U};
std::string stage;

View File

@ -301,11 +301,11 @@ void init_print(Print& print, std::initializer_list<TriangleMesh> meshes, Slic3r
DynamicPrintConfig* config {Slic3r::DynamicPrintConfig::new_from_defaults()};
config->apply(*_config);
const std::string v {std::getenv("SLIC3R_TESTS_GCODE")};
std::string tests_gcode {(v == "" ? "" : v)};
//const std::string v {std::getenv("SLIC3R_TESTS_GCODE")};
//std::string tests_gcode {(v == "" ? "" : v)};
if (tests_gcode != ""s)
config->set_key_value("gcode_comments", new ConfigOptionBool(true));
//if (tests_gcode != ""s)
//config->set_key_value("gcode_comments", new ConfigOptionBool(true));
for (const TriangleMesh& t : meshes) {
ModelObject* object {model.add_object()};