mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 11:56:06 +08:00
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:
parent
9ae142ef3e
commit
9c6008e5e0
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 ¶ms)
|
||||
Polylines Fill::fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms, ExtrusionEntitiesPtr &out) {
|
||||
void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, 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 ¶
|
||||
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 ¶
|
||||
|
||||
|
||||
|
||||
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 ¶ms) {
|
||||
void
|
||||
Fill::connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams ¶ms) 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 ¶ms, 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
|
||||
|
@ -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 ¶ms) { 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 ¶ms, ExtrusionEntitiesPtr &out);
|
||||
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const;
|
||||
|
||||
// Perform the fill.
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms);
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms);
|
||||
void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const FillParams ¶ms) const;
|
||||
|
||||
void do_gap_fill(const ExPolygons &gapfill_areas, const FillParams ¶ms, ExtrusionEntitiesPtr &coll_out);
|
||||
void do_gap_fill(const ExPolygons &gapfill_areas, const FillParams ¶ms, ExtrusionEntitiesPtr &coll_out) const;
|
||||
|
||||
ExtrusionRole getRoleFromSurfaceType(const FillParams ¶ms, const Surface *surface){
|
||||
ExtrusionRole getRoleFromSurfaceType(const FillParams ¶ms, 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))); }
|
||||
|
@ -8,30 +8,37 @@
|
||||
#include "FillConcentric.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
void FillConcentric::_fill_surface_single(
|
||||
void
|
||||
FillConcentric::init_spacing(coordf_t spacing, const FillParams ¶ms)
|
||||
{
|
||||
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 ¶ms,
|
||||
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 ¶ms,
|
||||
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),
|
||||
|
@ -12,12 +12,13 @@ public:
|
||||
|
||||
protected:
|
||||
virtual Fill* clone() const { return new FillConcentric(*this); };
|
||||
void init_spacing(coordf_t spacing, const FillParams ¶ms) override;
|
||||
virtual void _fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
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 ¶ms, ExtrusionEntitiesPtr &out) override;
|
||||
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const override;
|
||||
|
||||
virtual bool no_sort() const { return true; }
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 ¶ms)
|
||||
{
|
||||
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 ¶ms, float angleBase, float pattern_shift, Polylines &polylines_out)
|
||||
bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, 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 ¶ms)
|
||||
Polylines FillRectilinear2::fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms)
|
||||
Polylines FillGrid2::fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶
|
||||
return polylines_out;
|
||||
}
|
||||
|
||||
Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||
Polylines FillTriangles::fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms)
|
||||
Polylines FillStars::fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶
|
||||
return polylines_out;
|
||||
}
|
||||
|
||||
Polylines FillCubic::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||
Polylines FillCubic::fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶
|
||||
|
||||
|
||||
void
|
||||
FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out)
|
||||
FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, 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 ¶ms)
|
||||
Polylines FillScatteredRectilinear::fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms, ExtrusionEntitiesPtr &out) {
|
||||
FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, 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 ¶ms, ExPolygons &rectilinear, ExPolygons &gapfill) {
|
||||
void
|
||||
FillRectilinear2WGapFill::split_polygon_gap_fill(const Surface &surface, const FillParams ¶ms, 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 ¶ms, ExtrusionEntitiesPtr &out) {
|
||||
FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, 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 ¶ms, 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
|
||||
|
@ -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 ¶ms) override;
|
||||
void init_spacing(coordf_t spacing, const FillParams ¶ms) override;
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) const override;
|
||||
|
||||
protected:
|
||||
virtual std::vector<SegmentedIntersectionLine> _vert_lines_for_polygon(const ExPolygonWithOffset &poly_with_offset, const BoundingBox &bounding_box, const FillParams ¶ms, 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 ¶ms, float angleBase, float pattern_shift, Polylines &polylines_out);
|
||||
bool fill_surface_by_lines(const Surface *surface, const FillParams ¶ms, 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 ¶ms) override;
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms) override;
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms) override;
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms) override;
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms);
|
||||
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) override;
|
||||
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, 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 ¶ms) override;
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms, ExtrusionEntitiesPtr &out) override;
|
||||
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, 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 ¶ms, ExtrusionEntitiesPtr &out) override;
|
||||
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const override;
|
||||
static void split_polygon_gap_fill(const Surface &surface, const FillParams ¶ms, ExPolygons &rectilinear, ExPolygons &gapfill);
|
||||
};
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
Polylines FillSmooth::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||
Polylines FillSmooth::fill_surface(const Surface *surface, const FillParams ¶ms) 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 ¶ms, const double volume){
|
||||
const FillParams ¶ms, 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 ¶ms, const double volume){
|
||||
const FillParams ¶ms, 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 ¶ms, ExtrusionEntitiesPtr &out)
|
||||
void FillSmooth::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const
|
||||
{
|
||||
coordf_t init_spacing = this->spacing;
|
||||
|
||||
|
@ -37,8 +37,8 @@ public:
|
||||
}
|
||||
virtual Fill* clone() const{ return new FillSmooth(*this); }
|
||||
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) override;
|
||||
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) override;
|
||||
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) const override;
|
||||
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, 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 ¶ms, const double volume);
|
||||
const FillParams ¶ms, const double volume) const;
|
||||
void fill_expolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill,
|
||||
const FillParams ¶ms, const double volume);
|
||||
const FillParams ¶ms, const double volume) const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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 ¶ms){
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -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()};
|
||||
|
Loading…
x
Reference in New Issue
Block a user