overlap: now perimetergenerator store the not-overlap polygons in the layer region.

fill smooth use it for the first layer
fill_exactly use it, it's much more reliable now.
This commit is contained in:
supermerill 2018-08-03 16:53:48 +02:00
parent 7340b91732
commit 05414e0e56
9 changed files with 175 additions and 101 deletions

View File

@ -34,10 +34,11 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
{
// Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id;
double fill_density = layerm.region()->config.fill_density;
Flow infill_flow = layerm.flow(frInfill);
Flow solid_infill_flow = layerm.flow(frSolidInfill);
Flow top_solid_infill_flow = layerm.flow(frTopSolidInfill);
double fill_density = layerm.region()->config.fill_density;
Flow infill_flow = layerm.flow(frInfill);
Flow solid_infill_flow = layerm.flow(frSolidInfill);
Flow top_solid_infill_flow = layerm.flow(frTopSolidInfill);
const float perimeter_spacing = layerm.flow(frPerimeter).spacing();
Surfaces surfaces;
@ -258,8 +259,20 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
f->link_max_length = scale_(link_max_length);
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
f->loop_clipping = scale_(flow.nozzle_diameter) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER;
//give the overlap size, it's not the real value (it can depend of the external_perimeter_extrusion_width)
f->overlap = layerm.region()->config.infill_overlap.get_abs_value(flow.nozzle_diameter);
//give the overlap size to let the infill do his overlap
//add overlap if at least one perimeter
if (layerm.region()->config.perimeters.getInt() > 0) {
f->overlap = layerm.region()->config.get_abs_value("infill_overlap", (perimeter_spacing + (f->spacing)) / 2);
if (f->overlap!=0) {
f->no_overlap_expolygons = intersection_ex(layerm.fill_no_overlap_expolygons, ExPolygons() = { surface.expolygon });
} else {
f->no_overlap_expolygons.push_back(surface.expolygon);
}
} else {
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 = 0.01 * density;

View File

@ -35,10 +35,10 @@ Fill* Fill::new_from_type(const InfillPattern type)
// case ipGrid: return new FillGrid();
case ipArchimedeanChords: return new FillArchimedeanChords();
case ipHilbertCurve: return new FillHilbertCurve();
case ipOctagramSpiral: return new FillOctagramSpiral();
case ipSmooth: return new FillSmooth();
case ipSmoothTriple: return new FillSmoothTriple();
case ipSmoothHilbert: return new FillSmoothHilbert();
case ipOctagramSpiral: return new FillOctagramSpiral();
case ipSmooth: return new FillSmooth();
case ipSmoothTriple: return new FillSmoothTriple();
case ipSmoothHilbert: return new FillSmoothHilbert();
default: CONFESS("unknown type"); return nullptr;
}
}
@ -76,10 +76,10 @@ coord_t Fill::_adjust_solid_spacing(const coord_t width, const coord_t distance)
assert(width >= 0);
assert(distance > 0);
// floor(width / distance)
coord_t number_of_intervals = (width - EPSILON) / distance;
coord_t number_of_intervals = (coord_t)((width - EPSILON) / distance);
coord_t distance_new = (number_of_intervals == 0) ?
distance :
((width - EPSILON) / number_of_intervals);
(coord_t)(((width - EPSILON) / number_of_intervals));
const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
assert(factor > 1. - 1e-5);
// How much could the extrusion width be increased? By 20%.
@ -96,8 +96,8 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
// set infill angle
float out_angle = this->angle;
if (out_angle == FLT_MAX) {
//FIXME Vojtech: Add a warning?
if (out_angle == FLT_MAX) {
//FIXME Vojtech: Add a warning?
printf("Using undefined infill angle\n");
out_angle = 0.f;
}
@ -105,7 +105,7 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
// Bounding box is the bounding box of a perl object Slic3r::Print::Object (c++ object Slic3r::PrintObject)
// The bounding box is only undefined in unit tests.
Point out_shift = empty(this->bounding_box) ?
surface->expolygon.contour.bounding_box().center() :
surface->expolygon.contour.bounding_box().center() :
this->bounding_box.center();
#if 0
@ -117,73 +117,71 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
#endif
if (surface->bridge_angle >= 0) {
// use bridge angle
//FIXME Vojtech: Add a debugf?
// use bridge angle
//FIXME Vojtech: Add a debugf?
// Slic3r::debugf "Filling bridge with angle %d\n", rad2deg($surface->bridge_angle);
#ifdef SLIC3R_DEBUG
printf("Filling bridge with angle %f\n", surface->bridge_angle);
#endif /* SLIC3R_DEBUG */
out_angle = surface->bridge_angle;
out_angle = (float)(surface->bridge_angle);
} else if (this->layer_id != size_t(-1)) {
// alternate fill direction
out_angle += this->_layer_angle(this->layer_id / surface->thickness_layers);
} else {
// printf("Layer_ID undefined!\n");
// printf("Layer_ID undefined!\n");
}
out_angle += float(M_PI/2.);
return std::pair<float, Point>(out_angle, out_shift);
}
void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &params, const Flow &flow, ExtrusionEntityCollection &out ){
void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &params, const Flow &flow, ExtrusionEntityCollection &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;
// ensure it doesn't over or under-extrude
double multFlow = 1;
if (!params.dont_adjust && params.full_infill() && !flow.bridge && params.fill_exactly){
// compute the path of the nozzle -> extruded volume
double lengthTot = 0;
int nbLines = 0;
for (auto pline = polylines.begin(); pline != polylines.end(); ++pline){
Lines lines = pline->lines();
for (auto line = lines.begin(); line != lines.end(); ++line){
lengthTot += unscale(line->length());
nbLines++;
}
}
double extrudedVolume = flow.mm3_per_mm() * lengthTot;
// compute real volume
double poylineVolume = 0;
/// un-overlap the surface (it's done in perimeterGenerator, it just pass the surface polys a bit bigger to us,
/// so we have to shrink it, it's silly, it should be here we should decide how to use the overlap setting!)
ExPolygons noOffsetPolys = offset_ex(surface->expolygon, -scale_(this->overlap));
for (auto poly = noOffsetPolys.begin(); poly != noOffsetPolys.end(); ++poly){
poylineVolume += flow.height*unscale(unscale(poly->area()));
// add external "perimeter gap"
double perimeterRoundGap = unscale(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 += unscale(hole->length()) * flow.height * (1 - 0.25*PI) * 0.5;
}
/*printf("process want %f mm3 extruded for a volume of %f (%f + %f + %f) space : we mult by %f \n",
extrudedVolume,
(poylineVolume + perimeterRoundGap + holesGaps),
poylineVolume, perimeterRoundGap, holesGaps,
(poylineVolume + perimeterRoundGap + holesGaps) / extrudedVolume);*/
poylineVolume += perimeterRoundGap + holesGaps;
}
if (extrudedVolume != 0) multFlow = poylineVolume / extrudedVolume;
}
// compute the path of the nozzle -> extruded volume
double lengthTot = 0;
int nbLines = 0;
for (auto pline = polylines.begin(); pline != polylines.end(); ++pline){
Lines lines = pline->lines();
for (auto line = lines.begin(); line != lines.end(); ++line){
lengthTot += unscale(line->length());
nbLines++;
}
}
double extrudedVolume = 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*unscale(unscale(poly->area()));
// add external "perimeter gap"
double perimeterRoundGap = unscale(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 += unscale(hole->length()) * 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,
// (poylineVolume),
// (poylineVolume) / extrudedVolume,
// this->no_overlap_expolygons.size());
if (extrudedVolume != 0 && poylineVolume != 0) multFlow = poylineVolume / extrudedVolume;
}
// Save into layer.
auto *eec = new ExtrusionEntityCollection();
/// pass the no_sort attribute to the extrusion path
eec->no_sort = this->no_sort();
/// add it into the collection
out.entities.push_back(eec);
/// push the path
/// add it into the collection
out.entities.push_back(eec);
/// push the path
extrusion_entities_append_paths(
eec->entities, STDMOVE(polylines),
flow.bridge ?
@ -191,7 +189,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
(surface->is_solid() ?
((surface->is_top()) ? erTopSolidInfill : erSolidInfill) :
erInternalInfill),
flow.mm3_per_mm() * params.flow_mult * multFlow, flow.width * params.flow_mult, flow.height);
flow.mm3_per_mm() * params.flow_mult * multFlow, flow.width * params.flow_mult * multFlow, flow.height);
}

View File

@ -59,6 +59,7 @@ public:
coordf_t spacing;
// infill / perimeter overlap, in unscaled coordinates
coordf_t overlap;
ExPolygons no_overlap_expolygons;
// in radians, ccw, 0 = East
float angle;
// In scaled coordinates. Maximum lenght of a perimeter segment connecting two infill lines.

View File

@ -32,18 +32,22 @@ namespace Slic3r {
params2.density *= percentWidth[1];
params3.density *= percentWidth[2];
//a small under-overlap to prevent over-extrudion on thin surfaces (i.e. remove the overlap)
Surface surfaceNoOverlap(*surface);
//remove the overlap (prevent over-extruding) if possible
ExPolygons noOffsetPolys = offset_ex(surfaceNoOverlap.expolygon, -scale_(this->overlap) * (flow.bridge?0:1));
//printf("FillSmooth::fill_surface() : overlap=%f->%f.\n", overlap, -scale_(this->overlap));
//printf("FillSmooth::polys : 1->%i.\n", noOffsetPolys.size());
//printf("FillSmooth::polys : %f %f->%f.\n", surface->expolygon.area(), surfaceNoOverlap.expolygon.area(), noOffsetPolys[0].area());
//if (offsetPolys.size() == 1) surfaceNoOverlap.expolygon = offsetPolys[0];
//TODO: recursive if multiple polys instead of failing
// 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*unscale(unscale(poly->area()));
double perimeterRoundGap = unscale(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 += unscale(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)
volumeToOccupy += poylineVolume;
}
//if (polylines_layer1.empty() && polylines_layer2.empty() && polylines_layer3.empty())
// return;
@ -54,7 +58,6 @@ namespace Slic3r {
ExtrusionEntityCollection *eec;
double volumeToOccupy = 0;
// first infill
std::unique_ptr<Fill> f1 = std::unique_ptr<Fill>(Fill::new_from_type(fillPattern[0]));
@ -67,34 +70,35 @@ namespace Slic3r {
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;
for (auto poly = noOffsetPolys.begin(); poly != noOffsetPolys.end(); ++poly){
surfaceNoOverlap.expolygon = *poly;
Polylines polylines_layer1 = f1->fill_surface(&surfaceNoOverlap, params1);
if (!polylines_layer1.empty()){
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){
for (auto pline = polylines_layer1.begin(); pline != polylines_layer1.end(); ++pline) {
Lines lines = pline->lines();
for (auto line = lines.begin(); line != lines.end(); ++line){
for (auto line = lines.begin(); line != lines.end(); ++line) {
lengthTot += unscale(line->length());
nbLines++;
}
}
// add external "perimeter gap"
double poylineVolume = flow.height*unscale(unscale(poly->area()));
double perimeterRoundGap = unscale(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 += unscale(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;
volumeToOccupy += poylineVolume;
if (extrudedVolume == 0) extrudedVolume = 1;
// Save into layer smoothing path.
eec = new ExtrusionEntityCollection();
eecroot->entities.push_back(eec);
eec->no_sort = false;
// print thin
eec = new ExtrusionEntityCollection();
eecroot->entities.push_back(eec);
@ -103,12 +107,54 @@ namespace Slic3r {
eec->entities, STDMOVE(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? poylineVolume / extrudedVolume : 1),
(float)(flow.width*percentFlow[0] * (params.fill_exactly ? poylineVolume / extrudedVolume : 1)), (float)flow.height*0.8);
}
else{
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 += unscale(line->length());
nbLines++;
}
}
// add external "perimeter gap"
double poylineVolume = flow.height*unscale(unscale(poly->area()));
double perimeterRoundGap = unscale(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 += unscale(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
extrusion_entities_append_paths(
eec->entities, STDMOVE(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 ? poylineVolume / extrudedVolume : 1),
(float)(flow.width*percentFlow[0] * (params.fill_exactly ? poylineVolume / extrudedVolume : 1)), (float)flow.height*0.8);
} else {
return;
}
}
}
//second infill
@ -154,8 +200,8 @@ namespace Slic3r {
extrusion_entities_append_paths(
eec->entities, STDMOVE(polylines_layer2),
rolePass[1],
//reduced flow width for a better view (it's only a gui thing)
params.flow_mult * flow.mm3_per_mm() * percentFlow[1] * (params.fill_exactly ? volumeToOccupy / extrudedVolume : 1),
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{

View File

@ -38,6 +38,8 @@ public:
// Unspecified fill polygons, used for overhang detection ("ensure vertical wall thickness feature")
// and for re-starting of infills.
ExPolygons fill_expolygons;
// Unspecified fill polygons, used for interecting when we don't want the infill/perimeter overlap
ExPolygons fill_no_overlap_expolygons;
// collection of surfaces for infill generation
SurfaceCollection fill_surfaces;

View File

@ -84,6 +84,8 @@ LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection*
g.solid_infill_flow = this->flow(frSolidInfill);
g.process();
this->fill_no_overlap_expolygons = g.fill_no_overlap;
}
//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3.

View File

@ -425,8 +425,10 @@ void PerimeterGenerator::process()
// two or more loops?
perimeter_spacing / 2;
// only apply infill overlap if we actually have one perimeter
if (inset > 0)
inset -= scale_(this->config->get_abs_value("infill_overlap", unscale(inset + solid_infill_spacing / 2)));
coord_t overlap = 0;
if (inset > 0) {
overlap = scale_(this->config->get_abs_value("infill_overlap", unscale(inset + solid_infill_spacing / 2)));
}
// simplify infill contours according to resolution
Polygons pp;
for (ExPolygon &ex : last)
@ -434,12 +436,20 @@ void PerimeterGenerator::process()
// collapse too narrow infill areas
coord_t min_perimeter_infill_spacing = solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE);
// append infill areas to fill_surfaces
//auto it_surf = this->fill_surfaces->surfaces.end();
this->fill_surfaces->append(
offset2_ex(
union_ex(pp),
-inset -min_perimeter_infill_spacing/2,
-inset - min_perimeter_infill_spacing / 2 + overlap,
min_perimeter_infill_spacing / 2),
stInternal);
stInternal);
if (overlap != 0) {
ExPolygons polyWithoutOverlap = offset2_ex(
union_ex(pp),
-inset - min_perimeter_infill_spacing / 2,
min_perimeter_infill_spacing / 2);
this->fill_no_overlap.insert(this->fill_no_overlap.end(), polyWithoutOverlap.begin(), polyWithoutOverlap.end());
}
} // for each island
}

View File

@ -58,6 +58,7 @@ public:
ExtrusionEntityCollection* loops;
ExtrusionEntityCollection* gap_fill;
SurfaceCollection* fill_surfaces;
ExPolygons fill_no_overlap;
PerimeterGenerator(
// Input:

View File

@ -37,6 +37,7 @@ 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)