Refactored PerimeterGenerator for functional style, better constness
with the goal of calling PerimeterGenerator::process_xxx()
for each surface at once to collect its fill expolygons.
This commit is contained in:
Vojtech Bubnik 2022-10-27 13:04:52 +02:00
parent 715a603ab4
commit 237e56c7ce
6 changed files with 251 additions and 199 deletions

View File

@ -268,13 +268,13 @@ void extrusion_paths_append(ExtrusionPaths &dst, const ClipperLib_Z::Paths &extr
{ {
for (const ClipperLib_Z::Path &extrusion_path : extrusion_paths) { for (const ClipperLib_Z::Path &extrusion_path : extrusion_paths) {
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion_path); ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion_path);
Slic3r::append(dst, thick_polyline_to_multi_path(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON)).paths); Slic3r::append(dst, PerimeterGenerator::thick_polyline_to_multi_path(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON)).paths);
} }
} }
void extrusion_paths_append(ExtrusionPaths &dst, const Arachne::ExtrusionLine &extrusion, const ExtrusionRole role, const Flow &flow) void extrusion_paths_append(ExtrusionPaths &dst, const Arachne::ExtrusionLine &extrusion, const ExtrusionRole role, const Flow &flow)
{ {
ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion); ThickPolyline thick_polyline = Arachne::to_thick_polyline(extrusion);
Slic3r::append(dst, thick_polyline_to_multi_path(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON)).paths); Slic3r::append(dst, PerimeterGenerator::thick_polyline_to_multi_path(thick_polyline, role, flow, scaled<float>(0.05), float(SCALED_EPSILON)).paths);
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -8,6 +8,7 @@
#include "../Print.hpp" #include "../Print.hpp"
#include "../PrintConfig.hpp" #include "../PrintConfig.hpp"
#include "../Surface.hpp" #include "../Surface.hpp"
// for Arachne based infills
#include "../PerimeterGenerator.hpp" #include "../PerimeterGenerator.hpp"
#include "FillBase.hpp" #include "FillBase.hpp"
@ -427,7 +428,7 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
for (const ThickPolyline &thick_polyline : thick_polylines) { for (const ThickPolyline &thick_polyline : thick_polylines) {
Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing)); Flow new_flow = surface_fill.params.flow.with_spacing(float(f->spacing));
ExtrusionMultiPath multi_path = thick_polyline_to_multi_path(thick_polyline, surface_fill.params.extrusion_role, new_flow, scaled<float>(0.05), float(SCALED_EPSILON)); ExtrusionMultiPath multi_path = PerimeterGenerator::thick_polyline_to_multi_path(thick_polyline, surface_fill.params.extrusion_role, new_flow, scaled<float>(0.05), float(SCALED_EPSILON));
// Append paths to collection. // Append paths to collection.
if (!multi_path.empty()) { if (!multi_path.empty()) {
if (multi_path.paths.front().first_point() == multi_path.paths.back().last_point()) if (multi_path.paths.front().first_point() == multi_path.paths.back().last_point())

View File

@ -72,35 +72,46 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
(this->layer()->id() >= size_t(region_config.bottom_solid_layers.value) && (this->layer()->id() >= size_t(region_config.bottom_solid_layers.value) &&
this->layer()->print_z >= region_config.bottom_solid_min_thickness - EPSILON); this->layer()->print_z >= region_config.bottom_solid_min_thickness - EPSILON);
PerimeterGenerator g( PerimeterGenerator::Parameters params(
// input:
&slices,
this->layer()->height, this->layer()->height,
int(this->layer()->id()),
this->flow(frPerimeter), this->flow(frPerimeter),
&region_config, this->flow(frExternalPerimeter),
&this->layer()->object()->config(), this->bridging_flow(frPerimeter),
&print_config, this->flow(frSolidInfill),
spiral_vase, region_config,
this->layer()->object()->config(),
// output: print_config,
&m_perimeters, spiral_vase
&m_thin_fills,
fill_surfaces
); );
if (this->layer()->lower_layer != nullptr) // Cummulative sum of polygons over all the regions.
// Cummulative sum of polygons over all the regions. const ExPolygons *lower_slices = this->layer()->lower_layer ? &this->layer()->lower_layer->lslices : nullptr;
g.lower_slices = &this->layer()->lower_layer->lslices; // Cache for offsetted lower_slices
Polygons lower_layer_polygons_cache;
g.layer_id = (int)this->layer()->id();
g.ext_perimeter_flow = this->flow(frExternalPerimeter);
g.overhang_flow = this->bridging_flow(frPerimeter);
g.solid_infill_flow = this->flow(frSolidInfill);
if (this->layer()->object()->config().perimeter_generator.value == PerimeterGeneratorType::Arachne && !spiral_vase) if (this->layer()->object()->config().perimeter_generator.value == PerimeterGeneratorType::Arachne && !spiral_vase)
g.process_arachne(); PerimeterGenerator::process_arachne(
// input:
params,
&slices,
lower_slices,
lower_layer_polygons_cache,
// output:
m_perimeters,
m_thin_fills,
*fill_surfaces);
else else
g.process_classic(); PerimeterGenerator::process_classic(
// input:
params,
&slices,
lower_slices,
lower_layer_polygons_cache,
// output:
m_perimeters,
m_thin_fills,
*fill_surfaces);
} }
//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3. //#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3.

View File

@ -21,7 +21,7 @@
namespace Slic3r { namespace Slic3r {
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance, const float merge_tolerance) ExtrusionMultiPath PerimeterGenerator::thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, const float tolerance, const float merge_tolerance)
{ {
ExtrusionMultiPath multi_path; ExtrusionMultiPath multi_path;
ExtrusionPath path(role); ExtrusionPath path(role);
@ -121,7 +121,7 @@ static void variable_width(const ThickPolylines &polylines, ExtrusionRole role,
// of segments, and any pruning shall be performed before we apply this tolerance. // of segments, and any pruning shall be performed before we apply this tolerance.
const auto tolerance = float(scale_(0.05)); const auto tolerance = float(scale_(0.05));
for (const ThickPolyline &p : polylines) { for (const ThickPolyline &p : polylines) {
ExtrusionMultiPath multi_path = thick_polyline_to_multi_path(p, role, flow, tolerance, tolerance); ExtrusionMultiPath multi_path = PerimeterGenerator::thick_polyline_to_multi_path(p, role, flow, tolerance, tolerance);
// Append paths to collection. // Append paths to collection.
if (!multi_path.paths.empty()) { if (!multi_path.paths.empty()) {
for (auto it = std::next(multi_path.paths.begin()); it != multi_path.paths.end(); ++it) { for (auto it = std::next(multi_path.paths.begin()); it != multi_path.paths.end(); ++it) {
@ -157,7 +157,15 @@ public:
// External perimeter. It may be CCW or CW oriented (outer contour or hole contour). // External perimeter. It may be CCW or CW oriented (outer contour or hole contour).
bool is_external() const { return this->depth == 0; } bool is_external() const { return this->depth == 0; }
// An island, which may have holes, but it does not have another internal island. // An island, which may have holes, but it does not have another internal island.
bool is_internal_contour() const; bool is_internal_contour() const {
// An internal contour is a contour containing no other contours
if (! this->is_contour)
return false;
for (const PerimeterGeneratorLoop &loop : this->children)
if (loop.is_contour)
return false;
return true;
}
}; };
// Thanks Cura developers for this function. // Thanks Cura developers for this function.
@ -243,7 +251,7 @@ static void fuzzy_extrusion_line(Arachne::ExtrusionLine &ext_lines, double fuzzy
using PerimeterGeneratorLoops = std::vector<PerimeterGeneratorLoop>; using PerimeterGeneratorLoops = std::vector<PerimeterGeneratorLoop>;
static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perimeter_generator, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator::Parameters &params, const Polygons &lower_slices_polygons_cache, const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls)
{ {
// loops is an arrayref of ::Loop objects // loops is an arrayref of ::Loop objects
// turn each one into an ExtrusionLoop object // turn each one into an ExtrusionLoop object
@ -269,30 +277,30 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
const Polygon &polygon = loop.fuzzify ? fuzzified : loop.polygon; const Polygon &polygon = loop.fuzzify ? fuzzified : loop.polygon;
if (loop.fuzzify) { if (loop.fuzzify) {
fuzzified = loop.polygon; fuzzified = loop.polygon;
fuzzy_polygon(fuzzified, scaled<float>(perimeter_generator.config->fuzzy_skin_thickness.value), scaled<float>(perimeter_generator.config->fuzzy_skin_point_dist.value)); fuzzy_polygon(fuzzified, scaled<float>(params.config.fuzzy_skin_thickness.value), scaled<float>(params.config.fuzzy_skin_point_dist.value));
} }
if (perimeter_generator.config->overhangs && perimeter_generator.layer_id > perimeter_generator.object_config->raft_layers if (params.config.overhangs && params.layer_id > params.object_config.raft_layers
&& ! ((perimeter_generator.object_config->support_material || perimeter_generator.object_config->support_material_enforce_layers > 0) && && ! ((params.object_config.support_material || params.object_config.support_material_enforce_layers > 0) &&
perimeter_generator.object_config->support_material_contact_distance.value == 0)) { params.object_config.support_material_contact_distance.value == 0)) {
// get non-overhang paths by intersecting this loop with the grown lower slices // get non-overhang paths by intersecting this loop with the grown lower slices
extrusion_paths_append( extrusion_paths_append(
paths, paths,
intersection_pl({ polygon }, perimeter_generator.lower_slices_polygons()), intersection_pl({ polygon }, lower_slices_polygons_cache),
role, role,
is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(), is_external ? params.ext_mm3_per_mm : params.mm3_per_mm,
is_external ? perimeter_generator.ext_perimeter_flow.width() : perimeter_generator.perimeter_flow.width(), is_external ? params.ext_perimeter_flow.width() : params.perimeter_flow.width(),
(float)perimeter_generator.layer_height); float(params.layer_height));
// get overhang paths by checking what parts of this loop fall // get overhang paths by checking what parts of this loop fall
// outside the grown lower slices (thus where the distance between // outside the grown lower slices (thus where the distance between
// the loop centerline and original lower slices is >= half nozzle diameter // the loop centerline and original lower slices is >= half nozzle diameter
extrusion_paths_append( extrusion_paths_append(
paths, paths,
diff_pl({ polygon }, perimeter_generator.lower_slices_polygons()), diff_pl({ polygon }, lower_slices_polygons_cache),
erOverhangPerimeter, erOverhangPerimeter,
perimeter_generator.mm3_per_mm_overhang(), params.mm3_per_mm_overhang,
perimeter_generator.overhang_flow.width(), params.overhang_flow.width(),
perimeter_generator.overhang_flow.height()); params.overhang_flow.height());
// Reapply the nearest point search for starting point. // Reapply the nearest point search for starting point.
// We allow polyline reversal because Clipper may have randomly reversed polylines during clipping. // We allow polyline reversal because Clipper may have randomly reversed polylines during clipping.
@ -300,9 +308,9 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
} else { } else {
ExtrusionPath path(role); ExtrusionPath path(role);
path.polyline = polygon.split_at_first_point(); path.polyline = polygon.split_at_first_point();
path.mm3_per_mm = is_external ? perimeter_generator.ext_mm3_per_mm() : perimeter_generator.mm3_per_mm(); path.mm3_per_mm = is_external ? params.ext_mm3_per_mm : params.mm3_per_mm;
path.width = is_external ? perimeter_generator.ext_perimeter_flow.width() : perimeter_generator.perimeter_flow.width(); path.width = is_external ? params.ext_perimeter_flow.width() : params.perimeter_flow.width();
path.height = (float)perimeter_generator.layer_height; path.height = float(params.layer_height);
paths.push_back(path); paths.push_back(path);
} }
@ -311,7 +319,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
// Append thin walls to the nearest-neighbor search (only for first iteration) // Append thin walls to the nearest-neighbor search (only for first iteration)
if (! thin_walls.empty()) { if (! thin_walls.empty()) {
variable_width(thin_walls, erExternalPerimeter, perimeter_generator.ext_perimeter_flow, coll.entities); variable_width(thin_walls, erExternalPerimeter, params.ext_perimeter_flow, coll.entities);
thin_walls.clear(); thin_walls.clear();
} }
@ -331,7 +339,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime
} else { } else {
const PerimeterGeneratorLoop &loop = loops[idx.first]; const PerimeterGeneratorLoop &loop = loops[idx.first];
assert(thin_walls.empty()); assert(thin_walls.empty());
ExtrusionEntityCollection children = traverse_loops(perimeter_generator, loop.children, thin_walls); ExtrusionEntityCollection children = traverse_loops(params, lower_slices_polygons_cache, loop.children, thin_walls);
out.entities.reserve(out.entities.size() + children.entities.size() + 1); out.entities.reserve(out.entities.size() + children.entities.size() + 1);
ExtrusionLoop *eloop = static_cast<ExtrusionLoop*>(coll.entities[idx.first]); ExtrusionLoop *eloop = static_cast<ExtrusionLoop*>(coll.entities[idx.first]);
coll.entities[idx.first] = nullptr; coll.entities[idx.first] = nullptr;
@ -436,7 +444,7 @@ struct PerimeterGeneratorArachneExtrusion
bool fuzzify = false; bool fuzzify = false;
}; };
static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator &perimeter_generator, std::vector<PerimeterGeneratorArachneExtrusion> &pg_extrusions) static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator::Parameters &params, const Polygons &lower_slices_polygons_cache, std::vector<PerimeterGeneratorArachneExtrusion> &pg_extrusions)
{ {
ExtrusionEntityCollection extrusion_coll; ExtrusionEntityCollection extrusion_coll;
for (PerimeterGeneratorArachneExtrusion &pg_extrusion : pg_extrusions) { for (PerimeterGeneratorArachneExtrusion &pg_extrusion : pg_extrusions) {
@ -448,13 +456,13 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator &p
ExtrusionRole role = is_external ? erExternalPerimeter : erPerimeter; ExtrusionRole role = is_external ? erExternalPerimeter : erPerimeter;
if (pg_extrusion.fuzzify) if (pg_extrusion.fuzzify)
fuzzy_extrusion_line(*extrusion, scaled<float>(perimeter_generator.config->fuzzy_skin_thickness.value), scaled<float>(perimeter_generator.config->fuzzy_skin_point_dist.value)); fuzzy_extrusion_line(*extrusion, scaled<float>(params.config.fuzzy_skin_thickness.value), scaled<float>(params.config.fuzzy_skin_point_dist.value));
ExtrusionPaths paths; ExtrusionPaths paths;
// detect overhanging/bridging perimeters // detect overhanging/bridging perimeters
if (perimeter_generator.config->overhangs && perimeter_generator.layer_id > perimeter_generator.object_config->raft_layers if (params.config.overhangs && params.layer_id > params.object_config.raft_layers
&& ! ((perimeter_generator.object_config->support_material || perimeter_generator.object_config->support_material_enforce_layers > 0) && && ! ((params.object_config.support_material || params.object_config.support_material_enforce_layers > 0) &&
perimeter_generator.object_config->support_material_contact_distance.value == 0)) { params.object_config.support_material_contact_distance.value == 0)) {
ClipperLib_Z::Path extrusion_path; ClipperLib_Z::Path extrusion_path;
extrusion_path.reserve(extrusion->size()); extrusion_path.reserve(extrusion->size());
@ -462,8 +470,8 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator &p
extrusion_path.emplace_back(ej.p.x(), ej.p.y(), ej.w); extrusion_path.emplace_back(ej.p.x(), ej.p.y(), ej.w);
ClipperLib_Z::Paths lower_slices_paths; ClipperLib_Z::Paths lower_slices_paths;
lower_slices_paths.reserve(perimeter_generator.lower_slices_polygons().size()); lower_slices_paths.reserve(lower_slices_polygons_cache.size());
for (const Polygon &poly : perimeter_generator.lower_slices_polygons()) { for (const Polygon &poly : lower_slices_polygons_cache) {
lower_slices_paths.emplace_back(); lower_slices_paths.emplace_back();
ClipperLib_Z::Path &out = lower_slices_paths.back(); ClipperLib_Z::Path &out = lower_slices_paths.back();
out.reserve(poly.points.size()); out.reserve(poly.points.size());
@ -473,13 +481,13 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator &p
// get non-overhang paths by intersecting this loop with the grown lower slices // get non-overhang paths by intersecting this loop with the grown lower slices
extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role, extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctIntersection), role,
is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow); is_external ? params.ext_perimeter_flow : params.perimeter_flow);
// get overhang paths by checking what parts of this loop fall // get overhang paths by checking what parts of this loop fall
// outside the grown lower slices (thus where the distance between // outside the grown lower slices (thus where the distance between
// the loop centerline and original lower slices is >= half nozzle diameter // the loop centerline and original lower slices is >= half nozzle diameter
extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctDifference), erOverhangPerimeter, extrusion_paths_append(paths, clip_extrusion(extrusion_path, lower_slices_paths, ClipperLib_Z::ctDifference), erOverhangPerimeter,
perimeter_generator.overhang_flow); params.overhang_flow);
// Reapply the nearest point search for starting point. // Reapply the nearest point search for starting point.
// We allow polyline reversal because Clipper may have randomly reversed polylines during clipping. // We allow polyline reversal because Clipper may have randomly reversed polylines during clipping.
@ -519,7 +527,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator &p
chain_and_reorder_extrusion_paths(paths, &start_point); chain_and_reorder_extrusion_paths(paths, &start_point);
} }
} else { } else {
extrusion_paths_append(paths, *extrusion, role, is_external ? perimeter_generator.ext_perimeter_flow : perimeter_generator.perimeter_flow); extrusion_paths_append(paths, *extrusion, role, is_external ? params.ext_perimeter_flow : params.perimeter_flow);
} }
// Append paths to collection. // Append paths to collection.
@ -590,42 +598,48 @@ static void export_perimeters_to_svg(const std::string &path, const Polygons &co
// Thanks, Cura developers, for implementing an algorithm for generating perimeters with variable width (Arachne) that is based on the paper // Thanks, Cura developers, for implementing an algorithm for generating perimeters with variable width (Arachne) that is based on the paper
// "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling" // "A framework for adaptive width control of dense contour-parallel toolpaths in fused deposition modeling"
void PerimeterGenerator::process_arachne() void PerimeterGenerator::process_arachne(
// Inputs:
const Parameters &params,
const SurfaceCollection *slices,
const ExPolygons *lower_slices,
// Cache:
Polygons &lower_slices_polygons_cache,
// Output:
// Loops with the external thin walls
ExtrusionEntityCollection &out_loops,
// Gaps without the thin walls
ExtrusionEntityCollection &out_gap_fill,
// Infills without the gap fills
SurfaceCollection &out_fill_surfaces)
{ {
// other perimeters // other perimeters
m_mm3_per_mm = this->perimeter_flow.mm3_per_mm(); coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing();
coord_t perimeter_spacing = this->perimeter_flow.scaled_spacing();
// external perimeters // external perimeters
m_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm(); coord_t ext_perimeter_width = params.ext_perimeter_flow.scaled_width();
coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width(); coord_t ext_perimeter_spacing = params.ext_perimeter_flow.scaled_spacing();
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing(); coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (params.ext_perimeter_flow.spacing() + params.perimeter_flow.spacing()));
coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (this->ext_perimeter_flow.spacing() + this->perimeter_flow.spacing()));
// overhang perimeters
m_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm();
// solid infill // solid infill
coord_t solid_infill_spacing = this->solid_infill_flow.scaled_spacing(); coord_t solid_infill_spacing = params.solid_infill_flow.scaled_spacing();
// prepare grown lower layer slices for overhang detection // prepare grown lower layer slices for overhang detection
if (this->lower_slices != nullptr && this->config->overhangs) { if (lower_slices != nullptr && params.config.overhangs) {
// We consider overhang any part where the entire nozzle diameter is not supported by the // We consider overhang any part where the entire nozzle diameter is not supported by the
// lower layer, so we take lower slices and offset them by half the nozzle diameter used // lower layer, so we take lower slices and offset them by half the nozzle diameter used
// in the current layer // in the current layer
double nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->perimeter_extruder-1); double nozzle_diameter = params.print_config.nozzle_diameter.get_at(params.config.perimeter_extruder-1);
m_lower_slices_polygons = offset(*this->lower_slices, float(scale_(+nozzle_diameter/2))); lower_slices_polygons_cache = offset(*lower_slices, float(scale_(+nozzle_diameter/2)));
} }
// we need to process each island separately because we might have different // we need to process each island separately because we might have different
// extra perimeters for each one // extra perimeters for each one
for (const Surface &surface : this->slices->surfaces) { for (const Surface &surface : slices->surfaces) {
// detect how many perimeters must be generated for this island // detect how many perimeters must be generated for this island
int loop_number = this->config->perimeters + surface.extra_perimeters - 1; // 0-indexed loops int loop_number = params.config.perimeters + surface.extra_perimeters - 1; // 0-indexed loops
ExPolygons last = offset_ex(surface.expolygon.simplify_p(m_scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.)); ExPolygons last = offset_ex(surface.expolygon.simplify_p(params.scaled_resolution), - float(ext_perimeter_width / 2. - ext_perimeter_spacing / 2.));
Polygons last_p = to_polygons(last); Polygons last_p = to_polygons(last);
Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), 0, layer_height, *this->object_config, *this->print_config); Arachne::WallToolPaths wallToolPaths(last_p, ext_perimeter_spacing, perimeter_spacing, coord_t(loop_number + 1), 0, params.layer_height, params.object_config, params.print_config);
std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths(); std::vector<Arachne::VariableWidthLines> perimeters = wallToolPaths.getToolPaths();
loop_number = int(perimeters.size()) - 1; loop_number = int(perimeters.size()) - 1;
@ -651,7 +665,7 @@ void PerimeterGenerator::process_arachne()
int end_perimeter = -1; int end_perimeter = -1;
int direction = -1; int direction = -1;
if (this->config->external_perimeters_first) { if (params.config.external_perimeters_first) {
start_perimeter = 0; start_perimeter = 0;
end_perimeter = int(perimeters.size()); end_perimeter = int(perimeters.size());
direction = 1; direction = 1;
@ -672,7 +686,7 @@ void PerimeterGenerator::process_arachne()
for (size_t idx = 0; idx < all_extrusions.size(); idx++) for (size_t idx = 0; idx < all_extrusions.size(); idx++)
map_extrusion_to_idx.emplace(all_extrusions[idx], idx); map_extrusion_to_idx.emplace(all_extrusions[idx], idx);
auto extrusions_constrains = Arachne::WallToolPaths::getRegionOrder(all_extrusions, this->config->external_perimeters_first); auto extrusions_constrains = Arachne::WallToolPaths::getRegionOrder(all_extrusions, params.config.external_perimeters_first);
for (auto [before, after] : extrusions_constrains) { for (auto [before, after] : extrusions_constrains) {
auto after_it = map_extrusion_to_idx.find(after); auto after_it = map_extrusion_to_idx.find(after);
++blocked[after_it->second]; ++blocked[after_it->second];
@ -736,18 +750,18 @@ void PerimeterGenerator::process_arachne()
} }
} }
if (this->layer_id > 0 && this->config->fuzzy_skin != FuzzySkinType::None) { if (params.layer_id > 0 && params.config.fuzzy_skin != FuzzySkinType::None) {
std::vector<PerimeterGeneratorArachneExtrusion *> closed_loop_extrusions; std::vector<PerimeterGeneratorArachneExtrusion *> closed_loop_extrusions;
for (PerimeterGeneratorArachneExtrusion &extrusion : ordered_extrusions) for (PerimeterGeneratorArachneExtrusion &extrusion : ordered_extrusions)
if (extrusion.extrusion->inset_idx == 0) { if (extrusion.extrusion->inset_idx == 0) {
if (extrusion.extrusion->is_closed && this->config->fuzzy_skin == FuzzySkinType::External) { if (extrusion.extrusion->is_closed && params.config.fuzzy_skin == FuzzySkinType::External) {
closed_loop_extrusions.emplace_back(&extrusion); closed_loop_extrusions.emplace_back(&extrusion);
} else { } else {
extrusion.fuzzify = true; extrusion.fuzzify = true;
} }
} }
if (this->config->fuzzy_skin == FuzzySkinType::External) { if (params.config.fuzzy_skin == FuzzySkinType::External) {
ClipperLib_Z::Paths loops_paths; ClipperLib_Z::Paths loops_paths;
loops_paths.reserve(closed_loop_extrusions.size()); loops_paths.reserve(closed_loop_extrusions.size());
for (const auto &cl_extrusion : closed_loop_extrusions) { for (const auto &cl_extrusion : closed_loop_extrusions) {
@ -776,8 +790,8 @@ void PerimeterGenerator::process_arachne()
} }
} }
if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(*this, ordered_extrusions); !extrusion_coll.empty()) if (ExtrusionEntityCollection extrusion_coll = traverse_extrusions(params, lower_slices_polygons_cache, ordered_extrusions); !extrusion_coll.empty())
this->loops->append(extrusion_coll); out_loops.append(extrusion_coll);
ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour()); ExPolygons infill_contour = union_ex(wallToolPaths.getInnerContour());
const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing; const coord_t spacing = (perimeters.size() == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
@ -796,14 +810,14 @@ void PerimeterGenerator::process_arachne()
// two or more loops? // two or more loops?
perimeter_spacing; perimeter_spacing;
inset = coord_t(scale_(this->config->get_abs_value("infill_overlap", unscale<double>(inset)))); inset = coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale<double>(inset))));
Polygons pp; Polygons pp;
for (ExPolygon &ex : infill_contour) for (ExPolygon &ex : infill_contour)
ex.simplify_p(m_scaled_resolution, &pp); ex.simplify_p(params.scaled_resolution, &pp);
// collapse too narrow infill areas // collapse too narrow infill areas
const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE)); const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
// append infill areas to fill_surfaces // append infill areas to fill_surfaces
this->fill_surfaces->append( out_fill_surfaces.append(
offset2_ex( offset2_ex(
union_ex(pp), union_ex(pp),
float(- min_perimeter_infill_spacing / 2.), float(- min_perimeter_infill_spacing / 2.),
@ -812,24 +826,30 @@ void PerimeterGenerator::process_arachne()
} }
} }
void PerimeterGenerator::process_classic() void PerimeterGenerator::process_classic(
// Inputs:
const Parameters &params,
const SurfaceCollection *slices,
const ExPolygons *lower_slices,
// Cache:
Polygons &lower_slices_polygons_cache,
// Output:
// Loops with the external thin walls
ExtrusionEntityCollection &out_loops,
// Gaps without the thin walls
ExtrusionEntityCollection &out_gap_fill,
// Infills without the gap fills
SurfaceCollection &out_fill_surfaces)
{ {
// other perimeters // other perimeters
m_mm3_per_mm = this->perimeter_flow.mm3_per_mm(); coord_t perimeter_width = params.perimeter_flow.scaled_width();
coord_t perimeter_width = this->perimeter_flow.scaled_width(); coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing();
coord_t perimeter_spacing = this->perimeter_flow.scaled_spacing();
// external perimeters // external perimeters
m_ext_mm3_per_mm = this->ext_perimeter_flow.mm3_per_mm(); coord_t ext_perimeter_width = params.ext_perimeter_flow.scaled_width();
coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width(); coord_t ext_perimeter_spacing = params.ext_perimeter_flow.scaled_spacing();
coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing(); coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (params.ext_perimeter_flow.spacing() + params.perimeter_flow.spacing()));
coord_t ext_perimeter_spacing2 = scaled<coord_t>(0.5f * (this->ext_perimeter_flow.spacing() + this->perimeter_flow.spacing()));
// overhang perimeters
m_mm3_per_mm_overhang = this->overhang_flow.mm3_per_mm();
// solid infill // solid infill
coord_t solid_infill_spacing = this->solid_infill_flow.scaled_spacing(); coord_t solid_infill_spacing = params.solid_infill_flow.scaled_spacing();
// Calculate the minimum required spacing between two adjacent traces. // Calculate the minimum required spacing between two adjacent traces.
// This should be equal to the nominal flow spacing but we experiment // This should be equal to the nominal flow spacing but we experiment
@ -843,23 +863,23 @@ void PerimeterGenerator::process_classic()
// internal flow which is unrelated. // internal flow which is unrelated.
coord_t min_spacing = coord_t(perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE)); coord_t min_spacing = coord_t(perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE));
coord_t ext_min_spacing = coord_t(ext_perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE)); coord_t ext_min_spacing = coord_t(ext_perimeter_spacing * (1 - INSET_OVERLAP_TOLERANCE));
bool has_gap_fill = this->config->gap_fill_enabled.value && this->config->gap_fill_speed.value > 0; bool has_gap_fill = params.config.gap_fill_enabled.value && params.config.gap_fill_speed.value > 0;
// prepare grown lower layer slices for overhang detection // prepare grown lower layer slices for overhang detection
if (this->lower_slices != NULL && this->config->overhangs) { if (lower_slices != nullptr && params.config.overhangs) {
// We consider overhang any part where the entire nozzle diameter is not supported by the // We consider overhang any part where the entire nozzle diameter is not supported by the
// lower layer, so we take lower slices and offset them by half the nozzle diameter used // lower layer, so we take lower slices and offset them by half the nozzle diameter used
// in the current layer // in the current layer
double nozzle_diameter = this->print_config->nozzle_diameter.get_at(this->config->perimeter_extruder-1); double nozzle_diameter = params.print_config.nozzle_diameter.get_at(params.config.perimeter_extruder-1);
m_lower_slices_polygons = offset(*this->lower_slices, float(scale_(+nozzle_diameter/2))); lower_slices_polygons_cache = offset(*lower_slices, float(scale_(+nozzle_diameter/2)));
} }
// we need to process each island separately because we might have different // we need to process each island separately because we might have different
// extra perimeters for each one // extra perimeters for each one
for (const Surface &surface : this->slices->surfaces) { for (const Surface &surface : slices->surfaces) {
// detect how many perimeters must be generated for this island // detect how many perimeters must be generated for this island
int loop_number = this->config->perimeters + surface.extra_perimeters - 1; // 0-indexed loops int loop_number = params.config.perimeters + surface.extra_perimeters - 1; // 0-indexed loops
ExPolygons last = union_ex(surface.expolygon.simplify_p(m_scaled_resolution)); ExPolygons last = union_ex(surface.expolygon.simplify_p(params.scaled_resolution));
ExPolygons gaps; ExPolygons gaps;
if (loop_number >= 0) { if (loop_number >= 0) {
// In case no perimeters are to be generated, loop_number will equal to -1. // In case no perimeters are to be generated, loop_number will equal to -1.
@ -873,17 +893,17 @@ void PerimeterGenerator::process_classic()
if (i == 0) { if (i == 0) {
// the minimum thickness of a single loop is: // the minimum thickness of a single loop is:
// ext_width/2 + ext_spacing/2 + spacing/2 + width/2 // ext_width/2 + ext_spacing/2 + spacing/2 + width/2
offsets = this->config->thin_walls ? offsets = params.config.thin_walls ?
offset2_ex( offset2_ex(
last, last,
- float(ext_perimeter_width / 2. + ext_min_spacing / 2. - 1), - float(ext_perimeter_width / 2. + ext_min_spacing / 2. - 1),
+ float(ext_min_spacing / 2. - 1)) : + float(ext_min_spacing / 2. - 1)) :
offset_ex(last, - float(ext_perimeter_width / 2.)); offset_ex(last, - float(ext_perimeter_width / 2.));
// look for thin walls // look for thin walls
if (this->config->thin_walls) { if (params.config.thin_walls) {
// the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width // the following offset2 ensures almost nothing in @thin_walls is narrower than $min_width
// (actually, something larger than that still may exist due to mitering or other causes) // (actually, something larger than that still may exist due to mitering or other causes)
coord_t min_width = coord_t(scale_(this->ext_perimeter_flow.nozzle_diameter() / 3)); coord_t min_width = coord_t(scale_(params.ext_perimeter_flow.nozzle_diameter() / 3));
ExPolygons expp = opening_ex( ExPolygons expp = opening_ex(
// medial axis requires non-overlapping geometry // medial axis requires non-overlapping geometry
diff_ex(last, offset(offsets, float(ext_perimeter_width / 2.) + ClipperSafetyOffset)), diff_ex(last, offset(offsets, float(ext_perimeter_width / 2.) + ClipperSafetyOffset)),
@ -892,7 +912,7 @@ void PerimeterGenerator::process_classic()
for (ExPolygon &ex : expp) for (ExPolygon &ex : expp)
ex.medial_axis(ext_perimeter_width + ext_perimeter_spacing2, min_width, &thin_walls); ex.medial_axis(ext_perimeter_width + ext_perimeter_spacing2, min_width, &thin_walls);
} }
if (m_spiral_vase && offsets.size() > 1) { if (params.spiral_vase && offsets.size() > 1) {
// Remove all but the largest area polygon. // Remove all but the largest area polygon.
keep_largest_contour_only(offsets); keep_largest_contour_only(offsets);
} }
@ -900,7 +920,7 @@ void PerimeterGenerator::process_classic()
//FIXME Is this offset correct if the line width of the inner perimeters differs //FIXME Is this offset correct if the line width of the inner perimeters differs
// from the line width of the infill? // from the line width of the infill?
coord_t distance = (i == 1) ? ext_perimeter_spacing2 : perimeter_spacing; coord_t distance = (i == 1) ? ext_perimeter_spacing2 : perimeter_spacing;
offsets = this->config->thin_walls ? offsets = params.config.thin_walls ?
// This path will ensure, that the perimeters do not overfill, as in // This path will ensure, that the perimeters do not overfill, as in
// prusa3d/Slic3r GH #32, but with the cost of rounding the perimeters // prusa3d/Slic3r GH #32, but with the cost of rounding the perimeters
// excessively, creating gaps, which then need to be filled in by the not very // excessively, creating gaps, which then need to be filled in by the not very
@ -933,8 +953,8 @@ void PerimeterGenerator::process_classic()
break; break;
} }
{ {
const bool fuzzify_contours = this->config->fuzzy_skin != FuzzySkinType::None && i == 0 && this->layer_id > 0; const bool fuzzify_contours = params.config.fuzzy_skin != FuzzySkinType::None && i == 0 && params.layer_id > 0;
const bool fuzzify_holes = fuzzify_contours && this->config->fuzzy_skin == FuzzySkinType::All; const bool fuzzify_holes = fuzzify_contours && params.config.fuzzy_skin == FuzzySkinType::All;
for (const ExPolygon &expolygon : offsets) { for (const ExPolygon &expolygon : offsets) {
// Outer contour may overlap with an inner contour, // Outer contour may overlap with an inner contour,
// inner contour may overlap with another inner contour, // inner contour may overlap with another inner contour,
@ -951,7 +971,7 @@ void PerimeterGenerator::process_classic()
} }
} }
last = std::move(offsets); last = std::move(offsets);
if (i == loop_number && (! has_gap_fill || this->config->fill_density.value == 0)) { if (i == loop_number && (! has_gap_fill || params.config.fill_density.value == 0)) {
// The last run of this loop is executed to collect gaps for gap fill. // The last run of this loop is executed to collect gaps for gap fill.
// As the gap fill is either disabled or not // As the gap fill is either disabled or not
break; break;
@ -1013,16 +1033,16 @@ void PerimeterGenerator::process_classic()
} }
} }
// at this point, all loops should be in contours[0] // at this point, all loops should be in contours[0]
ExtrusionEntityCollection entities = traverse_loops(*this, contours.front(), thin_walls); ExtrusionEntityCollection entities = traverse_loops(params, lower_slices_polygons_cache, contours.front(), thin_walls);
// if brim will be printed, reverse the order of perimeters so that // if brim will be printed, reverse the order of perimeters so that
// we continue inwards after having finished the brim // we continue inwards after having finished the brim
// TODO: add test for perimeter order // TODO: add test for perimeter order
if (this->config->external_perimeters_first || if (params.config.external_perimeters_first ||
(this->layer_id == 0 && this->object_config->brim_width.value > 0)) (params.layer_id == 0 && params.object_config.brim_width.value > 0))
entities.reverse(); entities.reverse();
// append perimeters for this slice as a collection // append perimeters for this slice as a collection
if (! entities.empty()) if (! entities.empty())
this->loops->append(entities); out_loops.append(entities);
} // for each loop of an island } // for each loop of an island
// fill gaps // fill gaps
@ -1039,7 +1059,7 @@ void PerimeterGenerator::process_classic()
ex.medial_axis(max, min, &polylines); ex.medial_axis(max, min, &polylines);
if (! polylines.empty()) { if (! polylines.empty()) {
ExtrusionEntityCollection gap_fill; ExtrusionEntityCollection gap_fill;
variable_width(polylines, erGapFill, this->solid_infill_flow, gap_fill.entities); variable_width(polylines, erGapFill, params.solid_infill_flow, gap_fill.entities);
/* Make sure we don't infill narrow parts that are already gap-filled /* Make sure we don't infill narrow parts that are already gap-filled
(we only consider this surface's gaps to reduce the diff() complexity). (we only consider this surface's gaps to reduce the diff() complexity).
Growing actual extrusions ensures that gaps not filled by medial axis Growing actual extrusions ensures that gaps not filled by medial axis
@ -1049,7 +1069,7 @@ void PerimeterGenerator::process_classic()
//FIXME Vojtech: This grows by a rounded extrusion width, not by line spacing, //FIXME Vojtech: This grows by a rounded extrusion width, not by line spacing,
// therefore it may cover the area, but no the volume. // therefore it may cover the area, but no the volume.
last = diff_ex(last, gap_fill.polygons_covered_by_width(10.f)); last = diff_ex(last, gap_fill.polygons_covered_by_width(10.f));
this->gap_fill->append(std::move(gap_fill.entities)); out_gap_fill.append(std::move(gap_fill.entities));
} }
} }
@ -1066,15 +1086,15 @@ void PerimeterGenerator::process_classic()
perimeter_spacing / 2; perimeter_spacing / 2;
// only apply infill overlap if we actually have one perimeter // only apply infill overlap if we actually have one perimeter
if (inset > 0) if (inset > 0)
inset -= coord_t(scale_(this->config->get_abs_value("infill_overlap", unscale<double>(inset + solid_infill_spacing / 2)))); inset -= coord_t(scale_(params.config.get_abs_value("infill_overlap", unscale<double>(inset + solid_infill_spacing / 2))));
// simplify infill contours according to resolution // simplify infill contours according to resolution
Polygons pp; Polygons pp;
for (ExPolygon &ex : last) for (ExPolygon &ex : last)
ex.simplify_p(m_scaled_resolution, &pp); ex.simplify_p(params.scaled_resolution, &pp);
// collapse too narrow infill areas // collapse too narrow infill areas
coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE)); coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
// append infill areas to fill_surfaces // append infill areas to fill_surfaces
this->fill_surfaces->append( out_fill_surfaces.append(
offset2_ex( offset2_ex(
union_ex(pp), union_ex(pp),
float(- inset - min_perimeter_infill_spacing / 2.), float(- inset - min_perimeter_infill_spacing / 2.),
@ -1083,15 +1103,4 @@ void PerimeterGenerator::process_classic()
} // for each island } // for each island
} }
bool PerimeterGeneratorLoop::is_internal_contour() const
{
// An internal contour is a contour containing no other contours
if (! this->is_contour)
return false;
for (const PerimeterGeneratorLoop &loop : this->children)
if (loop.is_contour)
return false;
return true;
}
} }

View File

@ -10,70 +10,93 @@
namespace Slic3r { namespace Slic3r {
class PerimeterGenerator { namespace PerimeterGenerator
public: {
// Inputs:
const SurfaceCollection *slices; struct Parameters {
const ExPolygons *lower_slices; Parameters(
double layer_height,
int layer_id,
Flow perimeter_flow,
Flow ext_perimeter_flow,
Flow overhang_flow,
Flow solid_infill_flow,
const PrintRegionConfig &config,
const PrintObjectConfig &object_config,
const PrintConfig &print_config,
const bool spiral_vase) :
layer_height(layer_height),
layer_id(layer_id),
perimeter_flow(perimeter_flow),
ext_perimeter_flow(ext_perimeter_flow),
overhang_flow(overhang_flow),
solid_infill_flow(solid_infill_flow),
config(config),
object_config(object_config),
print_config(print_config),
spiral_vase(spiral_vase),
scaled_resolution(scaled<double>(print_config.gcode_resolution.value)),
mm3_per_mm(perimeter_flow.mm3_per_mm()),
ext_mm3_per_mm(ext_perimeter_flow.mm3_per_mm()),
mm3_per_mm_overhang(overhang_flow.mm3_per_mm())
{
}
// Input parameters
double layer_height; double layer_height;
int layer_id; int layer_id;
Flow perimeter_flow; Flow perimeter_flow;
Flow ext_perimeter_flow; Flow ext_perimeter_flow;
Flow overhang_flow; Flow overhang_flow;
Flow solid_infill_flow; Flow solid_infill_flow;
const PrintRegionConfig *config; const PrintRegionConfig &config;
const PrintObjectConfig *object_config; const PrintObjectConfig &object_config;
const PrintConfig *print_config; const PrintConfig &print_config;
// Outputs:
ExtrusionEntityCollection *loops;
ExtrusionEntityCollection *gap_fill;
SurfaceCollection *fill_surfaces;
PerimeterGenerator(
// Input:
const SurfaceCollection* slices,
double layer_height,
Flow flow,
const PrintRegionConfig* config,
const PrintObjectConfig* object_config,
const PrintConfig* print_config,
const bool spiral_vase,
// Output:
// Loops with the external thin walls
ExtrusionEntityCollection* loops,
// Gaps without the thin walls
ExtrusionEntityCollection* gap_fill,
// Infills without the gap fills
SurfaceCollection* fill_surfaces)
: slices(slices), lower_slices(nullptr), layer_height(layer_height),
layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
overhang_flow(flow), solid_infill_flow(flow),
config(config), object_config(object_config), print_config(print_config),
m_spiral_vase(spiral_vase),
m_scaled_resolution(scaled<double>(print_config->gcode_resolution.value)),
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces),
m_ext_mm3_per_mm(-1), m_mm3_per_mm(-1), m_mm3_per_mm_overhang(-1)
{}
void process_classic(); // Derived parameters
void process_arachne(); bool spiral_vase;
double scaled_resolution;
double ext_mm3_per_mm() const { return m_ext_mm3_per_mm; } double ext_mm3_per_mm;
double mm3_per_mm() const { return m_mm3_per_mm; } double mm3_per_mm;
double mm3_per_mm_overhang() const { return m_mm3_per_mm_overhang; } double mm3_per_mm_overhang;
Polygons lower_slices_polygons() const { return m_lower_slices_polygons; }
private: private:
bool m_spiral_vase; Parameters() = delete;
double m_scaled_resolution;
double m_ext_mm3_per_mm;
double m_mm3_per_mm;
double m_mm3_per_mm_overhang;
Polygons m_lower_slices_polygons;
}; };
void process_classic(
// Inputs:
const Parameters &params,
const SurfaceCollection *slices,
const ExPolygons *lower_slices,
// Cache:
Polygons &lower_slices_polygons_cache,
// Output:
// Loops with the external thin walls
ExtrusionEntityCollection &out_loops,
// Gaps without the thin walls
ExtrusionEntityCollection &out_gap_fill,
// Infills without the gap fills
SurfaceCollection &out_fill_surfaces);
void process_arachne(
// Inputs:
const Parameters &params,
const SurfaceCollection *slices,
const ExPolygons *lower_slices,
// Cache:
Polygons &lower_slices_polygons_cache,
// Output:
// Loops with the external thin walls
ExtrusionEntityCollection &out_loops,
// Gaps without the thin walls
ExtrusionEntityCollection &out_gap_fill,
// Infills without the gap fills
SurfaceCollection &out_fill_surfaces);
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance); ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance);
} } // namespace PerimeterGenerator
} // namespace Slic3r
#endif #endif

View File

@ -45,21 +45,29 @@ SCENARIO("Perimeter nesting", "[Perimeters]")
ExtrusionEntityCollection loops; ExtrusionEntityCollection loops;
ExtrusionEntityCollection gap_fill; ExtrusionEntityCollection gap_fill;
SurfaceCollection fill_surfaces; SurfaceCollection fill_surfaces;
PerimeterGenerator perimeter_generator( Flow flow(1., 1., 1.);
&slices, PerimeterGenerator::Parameters perimeter_generator_params(
1., // layer height 1., // layer height
Flow(1., 1., 1.), -1, // layer ID
static_cast<const PrintRegionConfig*>(&config), flow, flow, flow, flow,
static_cast<const PrintObjectConfig*>(&config), static_cast<const PrintRegionConfig&>(config),
static_cast<const PrintConfig*>(&config), static_cast<const PrintObjectConfig&>(config),
false, // spiral_vase static_cast<const PrintConfig&>(config),
// output: false); // spiral_vase
&loops, &gap_fill, &fill_surfaces); Polygons lower_layer_polygons_cache;
// FIXME Lukas H.: Disable this test for Arachne because it is failing and needs more investigation. // FIXME Lukas H.: Disable this test for Arachne because it is failing and needs more investigation.
// if (config.perimeter_generator == PerimeterGeneratorType::Arachne) // if (config.perimeter_generator == PerimeterGeneratorType::Arachne)
// perimeter_generator.process_arachne(); // PerimeterGenerator::process_arachne();
// else // else
perimeter_generator.process_classic(); PerimeterGenerator::process_classic(
// input:
perimeter_generator_params,
&slices,
nullptr,
// cache:
lower_layer_polygons_cache,
// output:
loops, gap_fill, fill_surfaces);
THEN("expected number of collections") { THEN("expected number of collections") {
REQUIRE(loops.entities.size() == data.expolygons.size()); REQUIRE(loops.entities.size() == data.expolygons.size());