ironing: cleaning code (remove duplication), streamline arguments & config struct for fill_surface_extrusion.

This commit is contained in:
supermerill 2019-02-11 14:42:25 +01:00
parent 7d4f090786
commit fb0fe3ac39
11 changed files with 311 additions and 411 deletions

View File

@ -304,7 +304,8 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
//params.flow_mult = layerm.region()->config().over_bridge_flow_ratio;
}
f->fill_surface_extrusion(&surface, params, flow, erNone, out.entities);
params.flow = &flow;
f->fill_surface_extrusion(&surface, params, out.entities);
}
// add thin fill regions

View File

@ -138,14 +138,14 @@ 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, const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out) {
void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) {
//add overlap & call fill_surface
Polylines polylines = this->fill_surface(surface, params);
if (polylines.empty())
return;
// ensure it doesn't over or under-extrude
double multFlow = 1;
if (!params.dont_adjust && params.full_infill() && !flow.bridge && params.fill_exactly){
if (!params.dont_adjust && params.full_infill() && !params.flow->bridge && params.fill_exactly){
// compute the path of the nozzle -> extruded volume
double lengthTot = 0;
int nbLines = 0;
@ -156,17 +156,17 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
nbLines++;
}
}
double extrudedVolume = flow.mm3_per_mm() * lengthTot;
double extrudedVolume = params.flow->mm3_per_mm() * lengthTot;
// compute real volume
double poylineVolume = 0;
for (auto poly = this->no_overlap_expolygons.begin(); poly != this->no_overlap_expolygons.end(); ++poly) {
poylineVolume += flow.height*unscaled(unscaled(poly->area()));
poylineVolume += params.flow->height*unscaled(unscaled(poly->area()));
// add external "perimeter gap"
double perimeterRoundGap = unscaled(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5;
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()) * flow.height * (1 - 0.25*PI) * 0.5;
holesGaps += unscaled(hole->length()) * params.flow->height * (1 - 0.25*PI) * 0.5;
}
poylineVolume += perimeterRoundGap + holesGaps;
}
@ -188,9 +188,9 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
/// add it into the collection
out.push_back(eec);
//get the role
ExtrusionRole good_role = role;
ExtrusionRole good_role = params.role;
if (good_role == erNone || good_role == erCustom) {
good_role = (flow.bridge ? erBridgeInfill :
good_role = (params.flow->bridge ? erBridgeInfill :
(surface->is_solid() ?
((surface->is_top()) ? erTopSolidInfill : erSolidInfill) :
erInternalInfill));
@ -199,9 +199,9 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
extrusion_entities_append_paths(
eec->entities, std::move(polylines),
good_role,
flow.mm3_per_mm() * params.flow_mult * multFlow,
flow.width * params.flow_mult * multFlow,
flow.height);
params.flow->mm3_per_mm() * params.flow_mult * multFlow,
params.flow->width * params.flow_mult * multFlow,
params.flow->height);
}

View File

@ -24,17 +24,19 @@ struct FillParams
memset(this, 0, sizeof(FillParams));
// Adjustment does not work.
dont_adjust = true;
flow_mult = 1.f;
flow_mult = 1.f;
fill_exactly = false;
role = erNone;
flow = NULL;
}
bool full_infill() const { return density > 0.9999f && density < 1.0001f; }
// Fill density, fraction in <0, 1>
float density;
// Fill density, fraction in <0, 1>
float density;
// Fill extruding flow multiplier, fraction in <0, 1>. Used by "over bridge compensation"
float flow_mult;
// Fill extruding flow multiplier, fraction in <0, 1>. Used by "over bridge compensation"
float flow_mult;
// Don't connect the fill lines around the inner perimeter.
bool dont_connect;
@ -49,6 +51,12 @@ struct FillParams
// we were requested to complete each loop;
// in this case we don't try to make more continuous paths
bool complete;
// if role == erNone or ERCustom, this method have to choose the best role itself, else it must use the argument's role.
ExtrusionRole role;
//flow to use
Flow const *flow;
};
static_assert(IsTriviallyCopyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");
@ -90,9 +98,7 @@ public:
virtual bool no_sort() const { return false; }
// This method have to fill the ExtrusionEntityCollection. It call fill_surface by default
// if role == erNone or ERCustom, this method have to choose the best role itself, else it must use the argument's role.
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params,
const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out);
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out);
// Perform the fill.
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
@ -136,8 +142,8 @@ public:
// for both positive and negative numbers. Here we want to round down for negative
// numbers as well.
coord_t aligned = (coord < 0) ?
((coord - spacing + 1) / spacing) * spacing :
(coord / spacing) * spacing;
((coord - spacing + 1) / spacing) * spacing :
(coord / spacing) * spacing;
assert(aligned <= coord);
return aligned;
}

View File

@ -65,7 +65,7 @@ void FillConcentric::_fill_surface_single(
}
void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, const FillParams &params,
const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out) {
ExtrusionEntitiesPtr &out) {
// Perform offset.
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(0 - 0.5 * this->spacing)));
@ -112,9 +112,9 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, cons
//get the role
ExtrusionRole good_role = role;
ExtrusionRole good_role = params.role;
if (good_role == erNone || good_role == erCustom) {
good_role = (flow.bridge ? erBridgeInfill :
good_role = (params.flow->bridge ? erBridgeInfill :
(surface->is_solid() ?
((surface->is_top()) ? erTopSolidInfill : erSolidInfill) :
erInternalInfill));
@ -125,9 +125,9 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, cons
extrusion_entities_append_loops(
coll_nosort->entities, loops,
good_role,
flow.mm3_per_mm() * params.flow_mult,
flow.width * params.flow_mult,
flow.height);
params.flow->mm3_per_mm() * params.flow_mult,
params.flow->width * params.flow_mult,
params.flow->height);
//add gapfills
if (!gaps.empty() && params.density >= 1) {
@ -143,11 +143,11 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, cons
//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() > min*max) {
ex.medial_axis(ex, max, min, &polylines, flow.height);
ex.medial_axis(ex, max, min, &polylines, params.flow->height);
}
}
if (!polylines.empty()) {
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines, erGapFill, flow);
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines, erGapFill, *params.flow);
coll_nosort->append(gap_fill.entities);
}
}

View File

@ -29,8 +29,7 @@ public:
protected:
virtual Fill* clone() const { return new FillConcentricWGapFill(*this); };
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params,
const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out);
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
virtual bool no_sort() const { return true; }
};

View File

@ -24,7 +24,7 @@ protected:
unsigned int thickness_layers,
const std::pair<float, Point> &direction,
ExPolygon &expolygon,
Polylines &polylines_out);
Polylines &polylines_out) override;
virtual float _layer_angle(size_t idx) const { return 0.f; }
virtual bool _centered() const = 0;

View File

@ -299,13 +299,13 @@ public:
polygons_inner = offset(polygons_outer, aoffset2 - aoffset1,
ClipperLib::jtMiter,
mitterLimit);
// Filter out contours with zero area or small area, contours with 2 points only.
// Filter out contours with zero area or small area, contours with 2 points only.
const double min_area_threshold = 0.01 * aoffset2 * aoffset2;
remove_small(polygons_outer, min_area_threshold);
remove_small(polygons_inner, min_area_threshold);
remove_sticks(polygons_outer);
remove_sticks(polygons_inner);
n_contours_outer = polygons_outer.size();
n_contours_outer = polygons_outer.size();
n_contours_inner = polygons_inner.size();
n_contours = n_contours_outer + n_contours_inner;
polygons_ccw.assign(n_contours, false);
@ -660,32 +660,32 @@ static inline coordf_t measure_perimeter_segment_on_vertical_line_length(
// The first point (the point of iIntersection) will not be inserted,
// the last point will be inserted.
static inline void emit_perimeter_segment_on_vertical_line(
const ExPolygonWithOffset &poly_with_offset,
const std::vector<SegmentedIntersectionLine> &segs,
size_t iVerticalLine,
size_t iInnerContour,
size_t iIntersection,
size_t iIntersection2,
Polyline &out,
bool forward)
const ExPolygonWithOffset &poly_with_offset,
const std::vector<SegmentedIntersectionLine> &segs,
size_t iVerticalLine,
size_t iInnerContour,
size_t iIntersection,
size_t iIntersection2,
Polyline &out,
bool forward)
{
const SegmentedIntersectionLine &il = segs[iVerticalLine];
const SegmentIntersection &itsct = il.intersections[iIntersection];
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
const Polygon &poly = poly_with_offset.contour(iInnerContour);
assert(itsct.is_inner());
assert(itsct2.is_inner());
assert(itsct.type != itsct2.type);
const SegmentedIntersectionLine &il = segs[iVerticalLine];
const SegmentIntersection &itsct = il.intersections[iIntersection];
const SegmentIntersection &itsct2 = il.intersections[iIntersection2];
const Polygon &poly = poly_with_offset.contour(iInnerContour);
assert(itsct.is_inner());
assert(itsct2.is_inner());
assert(itsct.type != itsct2.type);
assert(itsct.iContour == iInnerContour);
assert(itsct.iContour == itsct2.iContour);
// Do not append the first point.
// out.points.push_back(Point(il.pos, itsct.pos));
if (forward)
polygon_segment_append(out.points, poly, itsct.iSegment, itsct2.iSegment);
else
polygon_segment_append_reversed(out.points, poly, itsct.iSegment, itsct2.iSegment);
// Append the last point.
out.points.push_back(Point(il.pos, itsct2.pos()));
assert(itsct.iContour == itsct2.iContour);
// Do not append the first point.
// out.points.push_back(Point(il.pos, itsct.pos));
if (forward)
polygon_segment_append(out.points, poly, itsct.iSegment, itsct2.iSegment);
else
polygon_segment_append_reversed(out.points, poly, itsct.iSegment, itsct2.iSegment);
// Append the last point.
out.points.push_back(Point(il.pos, itsct2.pos()));
}
//TBD: For precise infill, measure the area of a slab spanned by an infill line.
@ -767,9 +767,9 @@ std::vector<SegmentedIntersectionLine> FillRectilinear2::_vert_lines_for_polygon
{
// n_vlines = ceil(bbox_width / line_spacing)
size_t n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing;
coord_t x0 = bounding_box.min(0);
if (params.full_infill())
x0 += (line_spacing + SCALED_EPSILON) / 2;
coord_t x0 = bounding_box.min(0);
if (params.full_infill())
x0 += (line_spacing + SCALED_EPSILON) / 2;
#ifdef SLIC3R_DEBUG
static int iRun = 0;
@ -820,7 +820,7 @@ std::vector<SegmentedIntersectionLine> FillRectilinear2::_vert_lines_for_polygon
assert(ir >= 0 && ir < segs.size());
for (int i = il; i <= ir; ++ i) {
coord_t this_x = segs[i].pos;
assert(this_x == i * line_spacing + x0);
assert(this_x == i * line_spacing + x0);
SegmentIntersection is;
is.iContour = iContour;
is.iSegment = iSegment;
@ -1198,7 +1198,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
// 3) Sort the intersection points, clear iPrev / iNext / iSegBelow / iSegAbove,
// if it is preceded by any other intersection point along the contour.
unsigned int vert_seg_dir_valid_mask =
unsigned int vert_seg_dir_valid_mask =
(going_up ?
(iSegAbove != -1 && seg.intersections[iAbove].type == SegmentIntersection::INNER_LOW) :
(iSegBelow != -1 && seg.intersections[iBelow].type == SegmentIntersection::INNER_HIGH)) ?
@ -1287,23 +1287,23 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
if (vert_seg_dir_valid_mask) {
bool valid = true;
// Verify, that there is no intersection with the inner contour up to the end of the contour segment.
// Verify, that the successive segment has not been consumed yet.
if (going_up) {
if (seg.intersections[iAbove].consumed_vertical_up) {
valid = false;
} else {
for (int i = (int)i_intersection + 1; i < iAbove && valid; ++i)
if (seg.intersections[i].is_inner())
valid = false;
}
// Verify, that the successive segment has not been consumed yet.
if (going_up) {
if (seg.intersections[iAbove].consumed_vertical_up) {
valid = false;
} else {
for (int i = (int)i_intersection + 1; i < iAbove && valid; ++i)
if (seg.intersections[i].is_inner())
valid = false;
}
} else {
if (seg.intersections[iBelow-1].consumed_vertical_up) {
valid = false;
} else {
for (int i = iBelow + 1; i < (int)i_intersection && valid; ++i)
if (seg.intersections[i].is_inner())
valid = false;
}
if (seg.intersections[iBelow-1].consumed_vertical_up) {
valid = false;
} else {
for (int i = iBelow + 1; i < (int)i_intersection && valid; ++i)
if (seg.intersections[i].is_inner())
valid = false;
}
}
if (valid) {
const Polygon &poly = poly_with_offset.contour(intrsctn->iContour);
@ -1372,9 +1372,9 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
assert(! polyline_current->has_duplicate_points());
// Handle nearly zero length edges.
if (polyline_current->points.size() <= 1 ||
(polyline_current->points.size() == 2 &&
std::abs(polyline_current->points.front()(0) - polyline_current->points.back()(0)) < SCALED_EPSILON &&
std::abs(polyline_current->points.front()(1) - polyline_current->points.back()(1)) < SCALED_EPSILON))
(polyline_current->points.size() == 2 &&
std::abs(polyline_current->points.front()(0) - polyline_current->points.back()(0)) < SCALED_EPSILON &&
std::abs(polyline_current->points.front()(1) - polyline_current->points.back()(1)) < SCALED_EPSILON))
polylines_out.pop_back();
intrsctn = NULL;
i_intersection = -1;
@ -1491,8 +1491,7 @@ Polylines FillCubic::fill_surface(const Surface *surface, const FillParams &para
void
FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillParams &params,
const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out)
FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out)
{
ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection();
//you don't want to sort the extrusions: big infill first, small second
@ -1519,9 +1518,9 @@ FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillP
/// add it into the collection
eecroot->entities.push_back(eec);
//get the role
ExtrusionRole good_role = role;
ExtrusionRole good_role = params.role;
if (good_role == erNone || good_role == erCustom) {
good_role = flow.bridge ?
good_role = params.flow->bridge ?
erBridgeInfill :
(surface->is_solid() ?
((surface->is_top()) ? erTopSolidInfill : erSolidInfill) :
@ -1532,9 +1531,9 @@ FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillP
eec->entities,
polylines_1,
good_role,
flow.mm3_per_mm() * params.flow_mult,
flow.width * params.flow_mult,
flow.height);
params.flow->mm3_per_mm() * params.flow_mult,
params.flow->width * params.flow_mult,
params.flow->height);
}
@ -1558,9 +1557,9 @@ FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillP
/// add it into the collection
eecroot->entities.push_back(eec);
//get the role
ExtrusionRole good_role = role;
ExtrusionRole good_role = params.role;
if (good_role == erNone || good_role == erCustom) {
good_role = flow.bridge ?
good_role = params.flow->bridge ?
erBridgeInfill :
(surface->is_solid() ?
((surface->is_top()) ? erTopSolidInfill : erSolidInfill) :
@ -1571,9 +1570,9 @@ FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillP
eec->entities,
polylines_2,
good_role,
flow.mm3_per_mm() * params.flow_mult,
flow.width * params.flow_mult,
flow.height);
params.flow->mm3_per_mm() * params.flow_mult,
params.flow->width * params.flow_mult,
params.flow->height);
}
// === end ===

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);
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) 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);
};
class FillGrid2 : public FillRectilinear2
@ -30,10 +30,10 @@ 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);
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
@ -42,10 +42,10 @@ 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);
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
@ -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);
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
@ -66,14 +66,15 @@ 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);
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected:
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
// The grid fill will keep the angle constant between the layers, see the implementation of Slic3r::Fill.
virtual float _layer_angle(size_t idx) const { return 0.f; }
};
class FillRectilinear2Peri : public FillRectilinear2 {
class FillRectilinear2Peri : public FillRectilinear2
{
public:
// require bridge flow since it's a pre-bridge over very sparse infill
virtual bool use_bridge_flow() const { return true; }
@ -81,8 +82,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,
const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out);
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out) override;
};
@ -90,9 +90,9 @@ public:
class FillScatteredRectilinear : public FillRectilinear2
{
public:
virtual Fill* clone() const { return new FillScatteredRectilinear(*this); };
virtual Fill* clone() const override{ return new FillScatteredRectilinear(*this); };
virtual ~FillScatteredRectilinear() {}
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
virtual Polylines fill_surface(const Surface *surface, const FillParams &params) override;
protected:
virtual float _layer_angle(size_t idx) const;

View File

@ -18,31 +18,100 @@ namespace Slic3r {
return polylines_out;
}
void FillSmooth::performSingleFill(const int idx, ExtrusionEntityCollection &eecroot, const Surface &srf_source,
const FillParams &params, const double volume){
if (srf_source.expolygon.empty()) return;
void FillSmooth::fill_surface_extrusion(const Surface *surface, const FillParams &params,
const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out)
// Save into layer smoothing path.
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
eec->no_sort = false;
FillParams params_modifided = params;
params_modifided.density *= percentWidth[idx];
if ((params.flow->bridge && idx == 0) || has_overlap[idx]){
this->fillExPolygon(idx, *eec, srf_source, params_modifided, volume);
}
else{
Surface surfaceNoOverlap(srf_source);
for (ExPolygon &poly : this->no_overlap_expolygons) {
if (poly.empty()) continue;
surfaceNoOverlap.expolygon = poly;
this->fillExPolygon(idx, *eec, surfaceNoOverlap, params_modifided, volume);
}
}
if (eec->entities.empty()) delete eec;
else eecroot.entities.push_back(eec);
}
void FillSmooth::fillExPolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill,
const FillParams &params, const double volume){
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->layer_id = this->layer_id;
f2->z = this->z;
f2->angle = anglePass[idx] + this->angle;
// Maximum length of the perimeter segment linking two infill lines.
f2->link_max_length = this->link_max_length;
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
f2->loop_clipping = this->loop_clipping;
Polylines polylines_layer = f2->fill_surface(&srf_to_fill, params);
if (!polylines_layer.empty()){
/*if (fillPattern[idx] == InfillPattern::ipRectilinear && polylines_layer[0].points.size() > 3){
polylines_layer[0].points.erase(polylines_layer[0].points.begin());
polylines_layer[polylines_layer.size() - 1].points.pop_back();
}*/
//compute the path of the nozzle
double lengthTot = 0;
int nbLines = 0;
for (Polyline &pline : polylines_layer){
Lines lines = pline.lines();
for (Line &line : lines){
lengthTot += unscaled(line.length());
nbLines++;
}
}
double extrudedVolume = params.flow->mm3_per_mm() * lengthTot;
if (extrudedVolume == 0) extrudedVolume = volume;
//get the role
ExtrusionRole good_role = params.role;
if (good_role == erNone || good_role == erCustom) {
good_role = params.flow->bridge && idx==0 ? erBridgeInfill : rolePass[idx];
}
// print thin
extrusion_entities_append_paths(
eec.entities, std::move(polylines_layer),
good_role,
params.flow_mult * params.flow->mm3_per_mm() * percentFlow[idx] *
(params.fill_exactly ? std::min(2., volume / extrudedVolume) : 1),
//min-reduced flow width for a better view (it's only a gui thing)
(float)(params.flow->width*(percentFlow[idx] < 0.1 ? 0.1 : percentFlow[idx])), (float)params.flow->height);
}
else{
return;
}
}
void FillSmooth::fill_surface_extrusion(const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out)
{
coordf_t init_spacing = this->spacing;
//printf("FillSmooth::fill_surface() : you call the right method (fill_surface instead of fill_surface_extrusion).\n");
//second pass with half layer width
FillParams params1 = params;
FillParams params2 = params;
FillParams params3 = params;
params1.density *= percentWidth[0];
params2.density *= percentWidth[1];
params3.density *= percentWidth[2];
// compute the volume to extrude
double volumeToOccupy = 0;
for (auto poly = this->no_overlap_expolygons.begin(); poly != this->no_overlap_expolygons.end(); ++poly) {
// add external "perimeter gap"
double poylineVolume = flow.height*unscaled(unscaled(poly->area()));
double perimeterRoundGap = unscaled(poly->contour.length()) * flow.height * (1 - 0.25*PI) * 0.5;
double poylineVolume = params.flow->height*unscaled(unscaled(poly->area()));
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()) * flow.height * (1 - 0.25*PI) * 0.5;
holesGaps += unscaled(hole->length()) * params.flow->height * (1 - 0.25*PI) * 0.5;
}
poylineVolume += perimeterRoundGap + holesGaps;
@ -61,212 +130,16 @@ namespace Slic3r {
// first infill
std::unique_ptr<Fill> f1 = std::unique_ptr<Fill>(Fill::new_from_type(fillPattern[0]));
f1->bounding_box = this->bounding_box;
f1->spacing = init_spacing;
f1->layer_id = this->layer_id;
f1->z = this->z;
f1->angle = anglePass[0];
// Maximum length of the perimeter segment linking two infill lines.
f1->link_max_length = this->link_max_length;
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
f1->loop_clipping = this->loop_clipping;
Surface surfaceNoOverlap(*surface);
if (flow.bridge) {
Polylines polylines_layer1 = f1->fill_surface(surface, params1);
if (!polylines_layer1.empty()) {
if (fillPattern[2] == InfillPattern::ipRectilinear && polylines_layer1[0].points.size() > 3) {
polylines_layer1[0].points.erase(polylines_layer1[0].points.begin());
polylines_layer1[polylines_layer1.size() - 1].points.pop_back();
}
//compute the path of the nozzle
double lengthTot = 0;
int nbLines = 0;
for (auto pline = polylines_layer1.begin(); pline != polylines_layer1.end(); ++pline) {
Lines lines = pline->lines();
for (auto line = lines.begin(); line != lines.end(); ++line) {
lengthTot += unscaled(line->length());
nbLines++;
}
}
double extrudedVolume = flow.mm3_per_mm() * lengthTot;
if (extrudedVolume == 0) extrudedVolume = 1;
// Save into layer smoothing path.
// print thin
eec = new ExtrusionEntityCollection();
eecroot->entities.push_back(eec);
eec->no_sort = false; //can be sorted inside the pass
extrusion_entities_append_paths(
eec->entities, std::move(polylines_layer1),
flow.bridge ? erBridgeInfill : rolePass[0],
//reduced flow height for a better view (it's only a gui thing)
params.flow_mult * flow.mm3_per_mm() * percentFlow[0] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1),
(float)(flow.width*percentFlow[0] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1)), (float)flow.height*0.8);
} else {
return;
}
} else {
for (auto poly = this->no_overlap_expolygons.begin(); poly != this->no_overlap_expolygons.end(); ++poly) {
surfaceNoOverlap.expolygon = *poly;
Polylines polylines_layer1 = f1->fill_surface(&surfaceNoOverlap, params1);
if (!polylines_layer1.empty()) {
double lengthTot = 0;
int nbLines = 0;
for (auto pline = polylines_layer1.begin(); pline != polylines_layer1.end(); ++pline) {
Lines lines = pline->lines();
for (auto line = lines.begin(); line != lines.end(); ++line) {
lengthTot += unscaled(line->length());
nbLines++;
}
}
// add external "perimeter gap"
double poylineVolume = flow.height*unscaled(unscaled(poly->area()));
double perimeterRoundGap = unscaled(poly->contour.length()) * 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()) * flow.height * (1 - 0.25*PI) * 0.5;
}
poylineVolume += perimeterRoundGap + holesGaps;
//extruded volume: see http://manual.slic3r.org/advanced/flow-math, and we need to remove a circle at an end (as the flow continue)
double extrudedVolume = flow.mm3_per_mm() * lengthTot;
eec = new ExtrusionEntityCollection();
eecroot->entities.push_back(eec);
eec->no_sort = false; //can be sorted inside the pass
//get the role
ExtrusionRole good_role = role;
if (good_role == erNone || good_role == erCustom) {
good_role = flow.bridge ? erBridgeInfill : rolePass[0];
}
extrusion_entities_append_paths(
eec->entities, std::move(polylines_layer1),
good_role,
//reduced flow height for a better view (it's only a gui thing)
params.flow_mult * flow.mm3_per_mm() * percentFlow[0] * (params.fill_exactly ? poylineVolume / extrudedVolume : 1),
(float)(flow.width*percentFlow[0] * (params.fill_exactly ? poylineVolume / extrudedVolume : 1)), (float)flow.height*0.8);
} else {
return;
}
}
}
performSingleFill(0, *eecroot, *surface, params, volumeToOccupy);
//second infill
if (nbPass > 1){
std::unique_ptr<Fill> f2 = std::unique_ptr<Fill>(Fill::new_from_type(fillPattern[1]));
f2->bounding_box = this->bounding_box;
f2->spacing = init_spacing;
f2->layer_id = this->layer_id;
f2->z = this->z;
f2->angle = anglePass[1];
// Maximum length of the perimeter segment linking two infill lines.
f2->link_max_length = this->link_max_length;
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
f2->loop_clipping = this->loop_clipping;
Polylines polylines_layer2 = f2->fill_surface(surface, params2);
if (!polylines_layer2.empty()){
if (fillPattern[2] == InfillPattern::ipRectilinear && polylines_layer2[0].points.size() > 3){
polylines_layer2[0].points.erase(polylines_layer2[0].points.begin());
polylines_layer2[polylines_layer2.size() - 1].points.pop_back();
}
//compute the path of the nozzle
double lengthTot = 0;
int nbLines = 0;
for (auto pline = polylines_layer2.begin(); pline != polylines_layer2.end(); ++pline){
Lines lines = pline->lines();
for (auto line = lines.begin(); line != lines.end(); ++line){
lengthTot += unscaled(line->length());
nbLines++;
}
}
double extrudedVolume = flow.mm3_per_mm() * lengthTot;
if (extrudedVolume == 0) extrudedVolume = 1;
// Save into layer smoothing path.
eec = new ExtrusionEntityCollection();
eecroot->entities.push_back(eec);
eec->no_sort = false;
//get the role
ExtrusionRole good_role = role;
if (good_role == erNone || good_role == erCustom) {
good_role = rolePass[1];
}
// print thin
extrusion_entities_append_paths(
eec->entities, std::move(polylines_layer2),
good_role,
params.flow_mult * flow.mm3_per_mm() * percentFlow[1] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1),
//min-reduced flow width for a better view (it's only a gui thing)
(float)(flow.width*(percentFlow[1] < 0.1 ? 0.1 : percentFlow[1])), (float)flow.height);
}
else{
return;
}
performSingleFill(1, *eecroot, *surface, params, volumeToOccupy);
}
// third infill
if (nbPass > 2){
std::unique_ptr<Fill> f3 = std::unique_ptr<Fill>(Fill::new_from_type(fillPattern[0]));
f3->bounding_box = this->bounding_box;
f3->spacing = init_spacing;
f3->layer_id = this->layer_id;
f3->z = this->z;
f3->angle = anglePass[2];
// Maximum length of the perimeter segment linking two infill lines.
f3->link_max_length = this->link_max_length;
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
f3->loop_clipping = this->loop_clipping;
Polylines polylines_layer3 = f3->fill_surface(surface, params1);
if (!polylines_layer3.empty()){
//remove some points that are not inside the area
if (fillPattern[2] == InfillPattern::ipRectilinear && polylines_layer3[0].points.size() > 3){
polylines_layer3[0].points.erase(polylines_layer3[0].points.begin());
polylines_layer3[polylines_layer3.size() - 1].points.pop_back();
}
//compute the path of the nozzle
double lengthTot = 0;
int nbLines = 0;
for (auto pline = polylines_layer3.begin(); pline != polylines_layer3.end(); ++pline){
Lines lines = pline->lines();
for (auto line = lines.begin(); line != lines.end(); ++line){
lengthTot += unscaled(line->length());
nbLines++;
}
}
double extrudedVolume = flow.mm3_per_mm() * lengthTot;
// Save into layer smoothing path. layer 3
eec = new ExtrusionEntityCollection();
eecroot->entities.push_back(eec);
eec->no_sort = false;
//get the role
ExtrusionRole good_role = role;
if (good_role == erNone || good_role == erCustom) {
good_role = rolePass[2];
}
// print thin
extrusion_entities_append_paths(
eec->entities, std::move(polylines_layer3),
good_role, //slow (if last)
//reduced flow width for a better view (it's only a gui thing)
params.flow_mult * flow.mm3_per_mm() * percentFlow[2] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1),
(float)(flow.width*(percentFlow[2] < 0.1 ? 0.1 : percentFlow[2])), (float)flow.height);
}
performSingleFill(2, *eecroot, *surface, params, volumeToOccupy);
}
if (!eecroot->entities.empty())

View File

@ -11,98 +11,114 @@ class FillSmooth : public Fill
{
public:
FillSmooth() {
nbPass = 2;
anglePass[0] = float(M_PI/4);
anglePass[1] = -float(M_PI/4);
anglePass[2] = 0;
fillPattern[0] = InfillPattern::ipRectilinear;
fillPattern[1] = InfillPattern::ipRectilinear;
fillPattern[2] = InfillPattern::ipRectilinear;
rolePass[0] = erSolidInfill;
rolePass[1] = erTopSolidInfill;
rolePass[2] = erSolidInfill;
percentWidth[0] = 0.9;
percentWidth[1] = 2;
percentWidth[2] = 1.0;
percentFlow[0] = 0.7;
percentFlow[1] = 0.3;
percentFlow[2] = 0.0;
double extrusionMult = 1.0;
percentFlow[0] *= extrusionMult;
percentFlow[1] *= extrusionMult;
percentFlow[2] *= extrusionMult;
}
virtual Fill* clone() const { return new FillSmooth(*this); }
nbPass = 2;
anglePass[0] = 0;
anglePass[1] = float(M_PI/2);
anglePass[2] = 0;
fillPattern[0] = InfillPattern::ipRectilinear;
fillPattern[1] = InfillPattern::ipRectilinear;
fillPattern[2] = InfillPattern::ipRectilinear;
rolePass[0] = erSolidInfill;
rolePass[1] = erTopSolidInfill;
rolePass[2] = erSolidInfill;
percentWidth[0] = 0.9;
percentWidth[1] = 2;
percentWidth[2] = 1.0;
percentFlow[0] = 0.7;
percentFlow[1] = 0.3;
percentFlow[2] = 0.0;
double extrusionMult = 1.0;
percentFlow[0] *= extrusionMult;
percentFlow[1] *= extrusionMult;
percentFlow[2] *= extrusionMult;
has_overlap[0] = false;
has_overlap[1] = true;
has_overlap[2] = false;
}
virtual Fill* clone() const{ return new FillSmooth(*this); }
virtual Polylines fill_surface(const Surface *surface, const FillParams &params);
virtual void fill_surface_extrusion(const Surface *surface, const FillParams &params,
const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out);
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;
protected:
int nbPass=2;
double percentWidth[3];
double percentFlow[3];
float anglePass[3];
ExtrusionRole rolePass[3];
InfillPattern fillPattern[3];
int nbPass=2;
double percentWidth[3];
double percentFlow[3];
float anglePass[3];
bool has_overlap[3];
ExtrusionRole rolePass[3];
InfillPattern fillPattern[3];
void FillSmooth::performSingleFill(const int idx, ExtrusionEntityCollection &eecroot, const Surface &srf_source,
const FillParams &params, const double volume);
void FillSmooth::fillExPolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill,
const FillParams &params, const double volume);
};
class FillSmoothTriple : public FillSmooth
{
public:
FillSmoothTriple() {
nbPass = 3;
anglePass[0] = float(M_PI / 4);
anglePass[1] = -float(M_PI / 4);
anglePass[2] = float(M_PI / 12); //align with nothing
fillPattern[0] = InfillPattern::ipRectilinear;
fillPattern[1] = InfillPattern::ipConcentric;
fillPattern[2] = InfillPattern::ipRectilinear;
rolePass[0] = erSolidInfill;
rolePass[1] = erSolidInfill;
rolePass[2] = erTopSolidInfill;
percentWidth[0] = 0.8;
percentWidth[1] = 1.5;
percentWidth[2] = 2.8;
percentFlow[0] = 0.7;
percentFlow[1] = 0.2;
percentFlow[2] = 0.1;
double extrusionMult = 1.0;
percentFlow[0] *= extrusionMult;
percentFlow[1] *= extrusionMult;
percentFlow[2] *= extrusionMult;
}
virtual Fill* clone() const { return new FillSmoothTriple(*this); }
FillSmoothTriple() {
nbPass = 1; //3
anglePass[0] = 0;
anglePass[1] = float(M_PI / 2);
anglePass[2] = float(M_PI / 12); //align with nothing
fillPattern[0] = InfillPattern::ipHilbertCurve; //ipRectilinear
fillPattern[1] = InfillPattern::ipConcentric;
fillPattern[2] = InfillPattern::ipRectilinear;
rolePass[0] = erTopSolidInfill;//erSolidInfill
rolePass[1] = erSolidInfill;
rolePass[2] = erTopSolidInfill;
percentWidth[0] = 1.4; //0.8
percentWidth[1] = 1.5;
percentWidth[2] = 2.8;
percentFlow[0] = 1; //0.7
percentFlow[1] = 0.25;
percentFlow[2] = 0.15;
double extrusionMult = 1.0; //slight over-extrusion
percentFlow[0] *= extrusionMult;
percentFlow[1] *= extrusionMult;
percentFlow[2] *= extrusionMult;
has_overlap[0] = true;
has_overlap[1] = true;
has_overlap[2] = true;
}
virtual Fill* clone() const { return new FillSmoothTriple(*this); }
};
class FillSmoothHilbert : public FillSmooth
{
public:
FillSmoothHilbert() {
nbPass = 2;
anglePass[0] = 0;
anglePass[1] = -float(M_PI / 4);
anglePass[2] = float(M_PI / 4);
fillPattern[0] = InfillPattern::ipHilbertCurve; //ipHilbertCurve
fillPattern[1] = InfillPattern::ipRectilinear;
fillPattern[2] = InfillPattern::ipRectilinear;
rolePass[0] = erSolidInfill;
rolePass[1] = erSolidInfill;
rolePass[2] = erTopSolidInfill;
percentWidth[0] = 1.0;
percentWidth[1] = 1.0;
percentWidth[2] = 1.0;
percentFlow[0] = 0.8;
percentFlow[1] = 0.1;
percentFlow[2] = 0.1;
double extrusionMult = 1.0;
percentFlow[0] *= extrusionMult;
percentFlow[1] *= extrusionMult;
percentFlow[2] *= extrusionMult;
}
virtual Fill* clone() const { return new FillSmoothHilbert(*this); }
FillSmoothHilbert() {
nbPass = 2;
anglePass[0] = 0;
anglePass[1] = float(M_PI / 4);
anglePass[2] = float(M_PI / 4);
fillPattern[0] = InfillPattern::ipHilbertCurve; //ipHilbertCurve
fillPattern[1] = InfillPattern::ipHilbertCurve;
fillPattern[2] = InfillPattern::ipRectilinear;
rolePass[0] = erSolidInfill;
rolePass[1] = erTopSolidInfill;
rolePass[2] = erTopSolidInfill;
percentWidth[0] = 1;
percentWidth[1] = 1.5;
percentWidth[2] = 1.0;
percentFlow[0] = 1;
percentFlow[1] = 0.0;
percentFlow[2] = 0.0;
double extrusionMult = 1.0;
percentFlow[0] *= extrusionMult;
percentFlow[1] *= extrusionMult;
percentFlow[2] *= extrusionMult;
has_overlap[0] = true;
has_overlap[1] = false;
has_overlap[2] = true;
}
virtual Fill* clone() const { return new FillSmoothHilbert(*this); }
};

View File

@ -629,7 +629,7 @@ public:
}
// Deserialization constructor
bool deserialize_(const std::string &path, int which = -1)
bool deserialize_(const std::string &path, int which = -1)
{
FILE *file = ::fopen(path.c_str(), "rb");
if (file == nullptr)
@ -793,8 +793,9 @@ namespace SupportMaterialInternal {
{
for (const ExtrusionEntity *ee : perimeters.entities) {
if (ee->is_collection()) {
const ExtrusionEntityCollection * eec = static_cast<const ExtrusionEntityCollection*>(ee);
for (const ExtrusionEntity *ee2 : static_cast<const ExtrusionEntityCollection*>(ee)->entities) {
assert(! ee2->is_collection());
//assert(! ee2->is_collection()); // there are loops for perimeters and collections for thin walls !!
if (ee2->is_loop())
if (has_bridging_perimeters(*static_cast<const ExtrusionLoop*>(ee2)))
return true;
@ -807,11 +808,12 @@ namespace SupportMaterialInternal {
static bool has_bridging_fills(const ExtrusionEntityCollection &fills)
{
for (const ExtrusionEntity *ee : fills.entities) {
assert(ee->is_collection());
for (const ExtrusionEntity *ee2 : static_cast<const ExtrusionEntityCollection*>(ee)->entities) {
assert(! ee2->is_collection());
assert(! ee2->is_loop());
if (ee2->role() == erBridgeInfill)
if (ee->is_collection()) {
if(has_bridging_fills(*static_cast<const ExtrusionEntityCollection*>(ee)))
return true;
} else {
assert(! ee->is_loop());
if (ee->role() == erBridgeInfill)
return true;
}
}
@ -2330,9 +2332,11 @@ static inline void fill_expolygons_generate_paths(
fill_params.density = density;
fill_params.complete = true;
fill_params.dont_adjust = true;
fill_params.flow = &flow;
fill_params.role = role;
for (const ExPolygon &expoly : expolygons) {
Surface surface(stInternal, expoly);
filler->fill_surface_extrusion(&surface, fill_params, flow, role, dst);
filler->fill_surface_extrusion(&surface, fill_params, dst);
}
}
@ -2348,9 +2352,11 @@ static inline void fill_expolygons_generate_paths(
fill_params.density = density;
fill_params.complete = true;
fill_params.dont_adjust = true;
fill_params.flow = &flow;
fill_params.role = role;
for (ExPolygon &expoly : expolygons) {
Surface surface(stInternal, std::move(expoly));
filler->fill_surface_extrusion(&surface, fill_params, flow, role, dst);
filler->fill_surface_extrusion(&surface, fill_params, dst);
}
}