mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 06:55:54 +08:00
new solid infill pattern : rectilinear with gapfill.
* it replace rectilinear fill by gapfill when width < spacing * 1.6 * it permit to fill spaces too thin to be filled by infill (if it's not already filled by the perimeter gapfill) * it print the gapfill after the rectilinear infill. * the exact volume option only do his thing on the rectilinear area, not the gapfill one (as it's already done in the medial axis).
This commit is contained in:
parent
dc618b72bc
commit
7b71d74b38
@ -103,5 +103,6 @@ Refer to the CMake scripts inside the `deps` directory to see which dependencies
|
||||
|
||||
### building tests
|
||||
|
||||
You must use vs 2015 or 2017, and convert the slic3r_test project to your version. Also, you have to add the "CRT SDK" to your windows 2017 installation (can be done via the VS intaller).
|
||||
You must use visual studio 2017, and build all deps & all projects with it (not the same compiler as vs 2013). Also, you have to add the "CRT SDK" to your windows 2017 installation (can be done via the VS intaller).
|
||||
Tested only with vs 2017. Should work with 2015 and 2019.
|
||||
|
||||
|
@ -28,6 +28,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
||||
case ipGyroid: return new FillGyroid();
|
||||
case ipRectilinear: return new FillRectilinear2();
|
||||
// case ipRectilinear: return new FillRectilinear();
|
||||
case ipRectilinearWGapFill: return new FillRectilinear2WGapFill();
|
||||
case ipScatteredRectilinear:return new FillScatteredRectilinear();
|
||||
case ipLine: return new FillLine();
|
||||
case ipGrid: return new FillGrid2();
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "../PrintConfig.hpp"
|
||||
#include "../Utils.hpp"
|
||||
#include "../Flow.hpp"
|
||||
#include "../ExtrusionEntity.hpp"
|
||||
#include "../ExtrusionEntityCollection.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -166,6 +168,19 @@ public:
|
||||
{ return Point(_align_to_grid(coord(0), spacing(0), base(0)), _align_to_grid(coord(1), spacing(1), base(1))); }
|
||||
};
|
||||
|
||||
|
||||
class ExtrusionSetRole : public ExtrusionVisitor {
|
||||
ExtrusionRole new_role;
|
||||
public:
|
||||
ExtrusionSetRole(ExtrusionRole role) : new_role(role) {}
|
||||
void use(ExtrusionPath &path) override { path.set_role(new_role); }
|
||||
void use(ExtrusionPath3D &path3D) override { path3D.set_role(new_role); }
|
||||
void use(ExtrusionMultiPath &multipath) override { for (ExtrusionPath path : multipath.paths) path.set_role(new_role); }
|
||||
void use(ExtrusionMultiPath3D &multipath) override { for (ExtrusionPath path : multipath.paths) path.set_role(new_role); }
|
||||
void use(ExtrusionLoop &loop) override { for (ExtrusionPath path : loop.paths) path.set_role(new_role); }
|
||||
void use(ExtrusionEntityCollection &collection) override { for (ExtrusionEntity *entity : collection.entities) entity->visit(*this); }
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_FillBase_hpp_
|
||||
|
@ -65,18 +65,6 @@ void FillConcentric::_fill_surface_single(
|
||||
// We want the loops to be split inside the G-code generator to get optimum path planning.
|
||||
}
|
||||
|
||||
class ExtrusionSetRole : public ExtrusionVisitor {
|
||||
ExtrusionRole new_role;
|
||||
public:
|
||||
ExtrusionSetRole(ExtrusionRole role) : new_role(role) {}
|
||||
void use(ExtrusionPath &path) override { path.set_role(new_role); }
|
||||
void use(ExtrusionPath3D &path3D) override { path3D.set_role(new_role); }
|
||||
void use(ExtrusionMultiPath &multipath) override { for (ExtrusionPath path : multipath.paths) path.set_role(new_role); }
|
||||
void use(ExtrusionMultiPath3D &multipath) override { for (ExtrusionPath path : multipath.paths) path.set_role(new_role); }
|
||||
void use(ExtrusionLoop &loop) override { for (ExtrusionPath path : loop.paths) path.set_role(new_role); }
|
||||
void use(ExtrusionEntityCollection &collection) override { for (ExtrusionEntity *entity : collection.entities) entity->visit(*this); }
|
||||
};
|
||||
|
||||
void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms,
|
||||
ExtrusionEntitiesPtr &out) {
|
||||
|
||||
|
@ -1439,7 +1439,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||
Polylines FillRectilinear2::fill_surface(const Surface *surface, const FillParams ¶ms)
|
||||
{
|
||||
Polylines polylines_out;
|
||||
if (! fill_surface_by_lines(surface, params, 0.f, 0.f, polylines_out)) {
|
||||
if (!fill_surface_by_lines(surface, params, 0.f, 0.f, polylines_out)) {
|
||||
printf("FillRectilinear2::fill_surface() failed to fill a region.\n");
|
||||
}
|
||||
return polylines_out;
|
||||
@ -1657,7 +1657,7 @@ void
|
||||
FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) {
|
||||
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 ;
|
||||
const coord_t tooth_spacing_min = scaled_nozzle_diam;
|
||||
const coord_t tooth_spacing_max = scaled_nozzle_diam * 3;
|
||||
const coord_t tooth_zhop = scaled_nozzle_diam;
|
||||
Polylines polylines_out;
|
||||
@ -1678,7 +1678,7 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi
|
||||
extrusions->paths.push_back(ExtrusionPath3D(good_role, params.flow->mm3_per_mm() * params.flow_mult, params.flow->width * params.flow_mult, params.flow->height));
|
||||
ExtrusionPath3D *current_extrusion = &(extrusions->paths.back());
|
||||
Points &pts = poly.points;
|
||||
coord_t next_zhop = tooth_spacing_min + (coord_t) abs((rand() / (float)RAND_MAX) * (tooth_spacing_max - tooth_spacing_min));
|
||||
coord_t next_zhop = tooth_spacing_min + (coord_t)abs((rand() / (float)RAND_MAX) * (tooth_spacing_max - tooth_spacing_min));
|
||||
size_t idx = 1;
|
||||
|
||||
current_extrusion->push_back(pts[0], 0);
|
||||
@ -1688,7 +1688,7 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi
|
||||
while (idx < poly.size() && maxLength > tooth_spacing_max) {
|
||||
//go next hop line
|
||||
//do not use the "return" line nor the tangent ones.
|
||||
while (idx < poly.size() && maxLength > tooth_spacing_min && (next_zhop >= line_length || line_length < clearance
|
||||
while (idx < poly.size() && maxLength > tooth_spacing_min && (next_zhop >= line_length || line_length < clearance
|
||||
|| (std::abs(std::abs((int)(this->angle * 180 / PI) % 180) - 90) > 45 ? pts[idx].y() < pts[idx - 1].y() : pts[idx].x() < pts[idx - 1].x()))) {
|
||||
if (line_length < clearance || pts[idx].x() < pts[idx - 1].x()) {
|
||||
|
||||
@ -1740,9 +1740,9 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi
|
||||
current_extrusion = &(extrusions->paths.back());
|
||||
current_extrusion->push_back(last, 0);
|
||||
line_length = (coord_t)last.distance_to(pts[idx]);
|
||||
|
||||
|
||||
//re-init
|
||||
next_zhop = tooth_spacing_min + (coord_t) abs((rand() / (float)RAND_MAX) * (tooth_spacing_max - tooth_spacing_min));
|
||||
next_zhop = tooth_spacing_min + (coord_t)abs((rand() / (float)RAND_MAX) * (tooth_spacing_max - tooth_spacing_min));
|
||||
}
|
||||
}
|
||||
while (idx < poly.size()) {
|
||||
@ -1767,5 +1767,121 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) {
|
||||
ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection();
|
||||
coll_nosort->no_sort = true; //can be sorted inside the pass
|
||||
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
|
||||
|
||||
// remove areas for gapfill
|
||||
ExPolygons rectilinear_areas = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * 0.8f, params.flow->scaled_spacing() * 0.8f);
|
||||
ExPolygons gapfill_areas = diff_ex(ExPolygons{ surface->expolygon }, rectilinear_areas);
|
||||
double rec_area = 0;
|
||||
for (ExPolygon &p : rectilinear_areas)rec_area += p.area();
|
||||
double gf_area = 0;
|
||||
for (ExPolygon &p : gapfill_areas)gf_area += p.area();
|
||||
std::cout << unscaled(unscaled(surface->expolygon.area())) << " = " << unscaled(unscaled(rec_area)) << " + " << unscaled(unscaled(gf_area)) << "\n";
|
||||
|
||||
// rectilinear
|
||||
Polylines polylines_rectilinear;
|
||||
Surface rectilinear_surface{ *surface };
|
||||
for (const ExPolygon &rectilinear_area : rectilinear_areas) {
|
||||
rectilinear_surface.expolygon = rectilinear_area;
|
||||
if (!fill_surface_by_lines(&rectilinear_surface, params, 0.f, 0.f, polylines_rectilinear)) {
|
||||
printf("FillRectilinear2::fill_surface() failed to fill a region.\n");
|
||||
}
|
||||
}
|
||||
if (!polylines_rectilinear.empty()) {
|
||||
double flow_mult_exact_volume = 1;
|
||||
//check if not over-extruding
|
||||
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;
|
||||
for (const Polyline &pline : polylines_rectilinear) {
|
||||
Lines lines = pline.lines();
|
||||
for (auto line = lines.begin(); line != lines.end(); ++line) {
|
||||
lengthTot += unscaled(line->length());
|
||||
nbLines++;
|
||||
}
|
||||
}
|
||||
double extrudedVolume = params.flow->mm3_per_mm() * lengthTot;
|
||||
// compute real volume
|
||||
double poylineVolume = 0;
|
||||
ExPolygons rectilinear_no_overlap_areas = intersection_ex(rectilinear_areas, this->no_overlap_expolygons);
|
||||
for (const ExPolygon &poly : rectilinear_no_overlap_areas) {
|
||||
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,
|
||||
// (poylineVolume),
|
||||
// (poylineVolume) / extrudedVolume,
|
||||
// this->no_overlap_expolygons.size());
|
||||
if (extrudedVolume != 0 && poylineVolume != 0) flow_mult_exact_volume = poylineVolume / extrudedVolume;
|
||||
//failsafe, it can happen
|
||||
if (flow_mult_exact_volume > 1.3) flow_mult_exact_volume = 1.3;
|
||||
if (flow_mult_exact_volume < 0.8) flow_mult_exact_volume = 0.8;
|
||||
}
|
||||
|
||||
//Create extrusions
|
||||
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
|
||||
/// pass the no_sort attribute to the extrusion path
|
||||
eec->no_sort = this->no_sort();
|
||||
|
||||
extrusion_entities_append_paths(
|
||||
eec->entities, polylines_rectilinear,
|
||||
good_role,
|
||||
params.flow->mm3_per_mm() * params.flow_mult * flow_mult_exact_volume,
|
||||
params.flow->width * params.flow_mult * flow_mult_exact_volume,
|
||||
params.flow->height);
|
||||
|
||||
coll_nosort->entities.push_back(eec);
|
||||
}
|
||||
|
||||
//gapfill
|
||||
ThickPolylines polylines_gapfill;
|
||||
double min = 0.2 * params.flow->scaled_width() * (1 - INSET_OVERLAP_TOLERANCE);
|
||||
double max = 2. * params.flow->scaled_width();
|
||||
for (const ExPolygon &ex : gapfill_areas) {
|
||||
//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, params.flow->scaled_width()*2, params.flow->scaled_width()/5, &polylines_gapfill, params.flow->height);
|
||||
}
|
||||
}
|
||||
if (!polylines_gapfill.empty() && good_role != erBridgeInfill) {
|
||||
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines_gapfill, erGapFill, *params.flow);
|
||||
//set role if needed
|
||||
if (good_role != erSolidInfill) {
|
||||
ExtrusionSetRole set_good_role(good_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_nosort->entities.push_back(coll_gapfill);
|
||||
}
|
||||
}
|
||||
|
||||
// === end ===
|
||||
if (!coll_nosort->empty()) {
|
||||
out.push_back(coll_nosort);
|
||||
} else {
|
||||
delete coll_nosort;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -111,6 +111,15 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class FillRectilinear2WGapFill : public FillRectilinear2
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
|
@ -98,7 +98,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer)
|
||||
|
||||
coord_t max_margin = 0;
|
||||
if ((this->region()->config().perimeters > 0)) {
|
||||
max_margin = scale_(this->flow(frExternalPerimeter).width) + this->flow(frPerimeter).scaled_spacing() * (this->region()->config().perimeters.value - 1);
|
||||
max_margin = this->flow(frExternalPerimeter).scaled_width() + this->flow(frPerimeter).scaled_spacing() * (this->region()->config().perimeters.value - 1);
|
||||
}
|
||||
const Surfaces &surfaces = this->fill_surfaces.surfaces;
|
||||
const bool has_infill = this->region()->config().fill_density.value > 0.;
|
||||
|
@ -444,6 +444,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "top-fill-pattern|external-fill-pattern=s";
|
||||
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||
def->enum_values.push_back("rectilinear");
|
||||
def->enum_values.push_back("rectilineargapfill");
|
||||
def->enum_values.push_back("concentric");
|
||||
def->enum_values.push_back("concentricgapfill");
|
||||
def->enum_values.push_back("hilbertcurve");
|
||||
@ -454,6 +455,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("smoothtriple");
|
||||
def->enum_values.push_back("smoothhilbert");
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Rectilinear (filled)"));
|
||||
def->enum_labels.push_back(L("Concentric"));
|
||||
def->enum_labels.push_back(L("Concentric (filled)"));
|
||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||
@ -471,12 +473,14 @@ void PrintConfigDef::init_fff_params()
|
||||
def->cli = "bottom-fill-pattern|external-fill-pattern=s";
|
||||
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||
def->enum_values.push_back("rectilinear");
|
||||
def->enum_values.push_back("rectilineargapfill");
|
||||
def->enum_values.push_back("concentric");
|
||||
def->enum_values.push_back("concentricgapfill");
|
||||
def->enum_values.push_back("hilbertcurve");
|
||||
def->enum_values.push_back("archimedeanchords");
|
||||
def->enum_values.push_back("octagramspiral");
|
||||
def->enum_values.push_back("smooth");
|
||||
def->enum_labels.push_back(L("Rectilinear (filled)"));
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Concentric"));
|
||||
def->enum_labels.push_back(L("Concentric (filled)"));
|
||||
@ -490,24 +494,27 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("solid_fill_pattern", coEnum);
|
||||
def->label = L("Solid pattern");
|
||||
def->category = L("Infill");
|
||||
def->tooltip = L("Fill pattern for solid (internal) infill. This only affects the solid not-visible layers. You should use rectilinear is most cases. You can use ironing for transluscnet material.");
|
||||
def->tooltip = L("Fill pattern for solid (internal) infill. This only affects the solid not-visible layers. You should use rectilinear is most cases. You can try ironing for transluscnet material."
|
||||
" Rectilinear (filled) replace zig-zag patterns by a single big line & is more efficient for filling little spaces.");
|
||||
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||
def->enum_values.push_back("rectilinear");
|
||||
def->enum_values.push_back("smooth");
|
||||
def->enum_values.push_back("rectilinear");
|
||||
def->enum_values.push_back("rectilineargapfill");
|
||||
def->enum_values.push_back("concentric");
|
||||
def->enum_values.push_back("concentricgapfill");
|
||||
def->enum_values.push_back("hilbertcurve");
|
||||
def->enum_values.push_back("archimedeanchords");
|
||||
def->enum_values.push_back("octagramspiral");
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Ironing"));
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Rectilinear (filled)"));
|
||||
def->enum_labels.push_back(L("Concentric"));
|
||||
def->enum_labels.push_back(L("Concentric (filled)"));
|
||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||
def->mode = comExpert;
|
||||
def->default_value = new ConfigOptionEnum<InfillPattern>(ipRectilinear);
|
||||
def->default_value = new ConfigOptionEnum<InfillPattern>(ipRectilinearWGapFill);
|
||||
|
||||
def = this->add("enforce_full_fill_volume", coBool);
|
||||
def->label = L("Enforce 100% fill volume");
|
||||
@ -1014,7 +1021,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->enum_values.push_back("hilbertcurve");
|
||||
def->enum_values.push_back("archimedeanchords");
|
||||
def->enum_values.push_back("octagramspiral");
|
||||
def->enum_values.push_back("scatteredrectilinear");
|
||||
def->enum_values.push_back("rectilineargapfill");
|
||||
def->enum_labels.push_back(L("Rectilinear"));
|
||||
def->enum_labels.push_back(L("Grid"));
|
||||
def->enum_labels.push_back(L("Triangles"));
|
||||
|
@ -42,7 +42,7 @@ enum PrintHostType {
|
||||
enum InfillPattern {
|
||||
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSmooth, ipSmoothHilbert, ipSmoothTriple,
|
||||
ipRectiWithPerimeter, ipConcentricGapFill, ipScatteredRectilinear, ipSawtooth
|
||||
ipRectiWithPerimeter, ipConcentricGapFill, ipScatteredRectilinear, ipSawtooth, ipRectilinearWGapFill
|
||||
};
|
||||
|
||||
enum SupportMaterialPattern {
|
||||
@ -149,6 +149,7 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::g
|
||||
keys_map["smoothhilbert"] = ipSmoothHilbert;
|
||||
keys_map["rectiwithperimeter"] = ipRectiWithPerimeter;
|
||||
keys_map["scatteredrectilinear"] = ipScatteredRectilinear;
|
||||
keys_map["rectilineargapfill"] = ipRectilinearWGapFill;
|
||||
keys_map["sawtooth"] = ipSawtooth;
|
||||
}
|
||||
return keys_map;
|
||||
|
Loading…
x
Reference in New Issue
Block a user