OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::FillSpiralInset Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/Fill/FillSpiralInset.hpp>

Inheritance diagram for Slic3r::FillSpiralInset:
Collaboration diagram for Slic3r::FillSpiralInset:

Public Member Functions

 ~FillSpiralInset () override=default
bool is_self_crossing () override
virtual bool use_bridge_flow () const
void set_bounding_box (const Slic3r::BoundingBox &bbox)
BoundingBox extended_object_bounding_box () const
virtual bool has_consistent_pattern () const
virtual bool aligned_to_origin () const
virtual Polylines fill_surface (const Surface *surface, const FillParams &params)
virtual ThickPolylines fill_surface_arachne (const Surface *surface, const FillParams &params)
virtual void set_lock_region_param (const LockRegionParam &lock_param)
virtual void fill_surface_extrusion (const Surface *surface, const FillParams &params, ExtrusionEntitiesPtr &out)

Static Public Member Functions

static Fill * new_from_type (const InfillPattern type)
static Fill * new_from_type (const std::string &type)
static bool use_bridge_flow (const InfillPattern type)
static void connect_infill (Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams &params)
static void connect_infill (Polylines &&infill_ordered, const Polygons &boundary, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams &params)
static void connect_infill (Polylines &&infill_ordered, const std::vector< const Polygon * > &boundary, const BoundingBox &bbox, Polylines &polylines_out, double spacing, const FillParams &params)
static void chain_or_connect_infill (Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams &params)
static void connect_base_support (Polylines &&infill_ordered, const std::vector< const Polygon * > &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams &params)
static void connect_base_support (Polylines &&infill_ordered, const Polygons &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams &params)
static coord_t _adjust_solid_spacing (const coord_t width, const coord_t distance)

Public Attributes

size_t layer_id
coordf_t z
coordf_t spacing
coordf_t overlap
float angle
bool fixed_angle {false}
coord_t link_max_length
coord_t loop_clipping
BoundingBox bounding_box
FillAdaptive::Octree * adapt_fill_octree = nullptr
const AdaptiveInfillField * adaptive_infill_field = nullptr
const PrintConfig * print_config = nullptr
const PrintObjectConfig * print_object_config = nullptr
ExPolygons no_overlap_expolygons
bool dont_alternate_fill_direction = false

Static Public Attributes

static float infill_anchor = 400
static float infill_anchor_max = 20

Protected Member Functions

Fill * clone () const override
void _fill_surface_single (const FillParams &params, unsigned int thickness_layers, const std::pair< float, Point > &direction, ExPolygon expolygon, Polylines &polylines_out) override
void _fill_surface_single (const FillParams &params, unsigned int thickness_layers, const std::pair< float, Point > &direction, ExPolygon expolygon, ThickPolylines &thick_polylines_out) override
bool no_sort () const override
virtual float _layer_angle (size_t idx) const
virtual std::pair< float, Point > _infill_direction (const Surface *surface) const
void _create_gap_fill (const Surface *surface, const FillParams &params, ExtrusionEntityCollection *out)

Detailed Description

Constructor & Destructor Documentation

◆ ~FillSpiralInset()

Slic3r::FillSpiralInset::~FillSpiralInset ( )
overridedefault

Member Function Documentation

◆ _adjust_solid_spacing()

coord_t Slic3r::Fill::_adjust_solid_spacing ( const coord_t width,
const coord_t distance )
staticinherited
367{
368 assert(width >= 0);
369 assert(distance > 0);
370 // floor(width / distance)
371 const auto number_of_intervals = coord_t((width - EPSILON) / distance);
372 coord_t distance_new = (number_of_intervals == 0) ?
373 distance :
374 coord_t((width - EPSILON) / number_of_intervals);
375 const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
376 assert(factor > 1. - 1e-5);
377 // How much could the extrusion width be increased? By 20%.
378 const coordf_t factor_max = 1.2;
379 if (factor > factor_max)
380 distance_new = coord_t(floor((coordf_t(distance) * factor_max + 0.5)));
381 return distance_new;
382}
#define EPSILON
Definition ColorUtils.cpp:64
int64_t coord_t
Definition libslic3r.h:48
coord_t width(const BoundingBox &box)
Definition Arrange.cpp:1184
double coordf_t
Definition GUI_ObjectList.hpp:46

References EPSILON.

Referenced by Slic3r::FillConcentric::_fill_surface_single(), Slic3r::FillLine::_fill_surface_single(), Slic3r::FillSpiralInset::_fill_surface_single(), and Slic3r::FillRectilinear::fill_surface_by_lines().

Here is the caller graph for this function:

◆ _create_gap_fill()

void Slic3r::Fill::_create_gap_fill ( const Surface * surface,
const FillParams & params,
ExtrusionEntityCollection * out )
protectedinherited
306 {
307
308 //Orca: just to be safe, check against null pointer for the print object config and if NULL return.
309 if (this->print_object_config == nullptr) return;
310
311 // Orca: Enable gap fill as per the user preference. Return early if gap fill is to not be applied.
312 if ((this->print_object_config->gap_fill_target.value == gftNowhere) ||
313 (surface->surface_type == stInternalSolid && this->print_object_config->gap_fill_target.value != gftEverywhere))
314 return;
315
316 Flow new_flow = params.flow;
317 ExPolygons unextruded_areas;
318 unextruded_areas = diff_ex(this->no_overlap_expolygons, union_ex(out->polygons_covered_by_spacing(10)));
319 ExPolygons gapfill_areas = union_ex(unextruded_areas);
320 if (!this->no_overlap_expolygons.empty())
321 gapfill_areas = intersection_ex(gapfill_areas, this->no_overlap_expolygons);
322
323 if (gapfill_areas.size() > 0 && params.density >= 1) {
324 double min = 0.2 * new_flow.scaled_spacing() * (1 - INSET_OVERLAP_TOLERANCE);
325 double max = 2. * new_flow.scaled_spacing();
326 ExPolygons gaps_ex = diff_ex(
327 opening_ex(gapfill_areas, float(min / 2.)),
328 offset2_ex(gapfill_areas, -float(max / 2.), float(max / 2. + ClipperSafetyOffset)));
329 //BBS: sort the gap_ex to avoid mess travel
330 Points ordering_points;
331 ordering_points.reserve(gaps_ex.size());
332 ExPolygons gaps_ex_sorted;
333 gaps_ex_sorted.reserve(gaps_ex.size());
334 for (const ExPolygon &ex : gaps_ex)
335 ordering_points.push_back(ex.contour.first_point());
336 std::vector<Points::size_type> order2 = chain_points(ordering_points);
337 for (size_t i : order2)
338 gaps_ex_sorted.emplace_back(std::move(gaps_ex[i]));
339
340 ThickPolylines polylines;
341 for (ExPolygon& ex : gaps_ex_sorted) {
342 //BBS: Use DP simplify to avoid duplicated points and accelerate medial-axis calculation as well.
343 ex.douglas_peucker(SCALED_RESOLUTION * 0.1);
344 ex.medial_axis(min, max, &polylines);
345 }
346
347 if (!polylines.empty() && !is_bridge(params.extrusion_role)) {
348 polylines.erase(std::remove_if(polylines.begin(), polylines.end(),
349 [&](const ThickPolyline& p) {
350 return p.length() < scale_(params.config->filter_out_gap_fill.value);
351 }), polylines.end());
352
353 if (out->no_sort)
354 insert_gap_fill(polylines, params.flow, out->entities);
355 else
356 variable_width(polylines, erGapFill, params.flow, out->entities);
357 }
358 }
359}
ExPolygons no_overlap_expolygons
Definition FillBase.hpp:176
const PrintObjectConfig * print_object_config
Definition FillBase.hpp:173
static constexpr double INSET_OVERLAP_TOLERANCE
Definition libslic3r.h:95
#define SCALED_RESOLUTION
Definition libslic3r.h:87
Slic3r::ExPolygons opening_ex(const Slic3r::ExPolygons &polygons, const float delta, JoinType joinType=DefaultJoinType, double miterLimit=DefaultMiterLimit)
Definition ClipperUtils.hpp:447
static void insert_gap_fill(const ThickPolylines &gaps, const Flow &flow, ExtrusionEntitiesPtr &entities)
Definition FillBase.cpp:232
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:831
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:20
void variable_width(const ThickPolylines &polylines, ExtrusionRole role, const Flow &flow, std::vector< ExtrusionEntity * > &out)
Definition VariableWidth.cpp:228
bool is_bridge(ExtrusionRole role)
Definition ExtrusionEntity.hpp:105
@ gftEverywhere
Definition PrintConfig.hpp:425
@ gftNowhere
Definition PrintConfig.hpp:425
@ erGapFill
Definition ExtrusionEntity.hpp:38
std::vector< size_t > chain_points(const Points &points, const Point *start_near)
Definition ShortestPath.cpp:1565
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:878
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:73
Slic3r::ExPolygons union_ex(const Slic3r::Polygons &subject, PolyFillType fill_type)
Definition ClipperUtils.cpp:1011
@ stInternalSolid
Definition Surface.hpp:28
std::vector< ThickPolyline > ThickPolylines
Definition Polyline.hpp:23
ExPolygons offset2_ex(const ExPolygons &expolygons, const float delta1, const float delta2, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:652
static constexpr const float ClipperSafetyOffset
Definition ClipperUtils.hpp:30

References Slic3r::chain_points(), Slic3r::ClipperSafetyOffset, Slic3r::FillParams::density, Slic3r::diff_ex(), Slic3r::ExtrusionEntityCollection::entities, Slic3r::erGapFill, Slic3r::FillParams::extrusion_role, Slic3r::FillParams::flow, Slic3r::gftEverywhere, Slic3r::gftNowhere, Slic3r::insert_gap_fill(), INSET_OVERLAP_TOLERANCE, Slic3r::intersection_ex(), Slic3r::is_bridge(), no_overlap_expolygons, Slic3r::ExtrusionEntityCollection::no_sort, Slic3r::offset2_ex(), Slic3r::opening_ex(), Slic3r::ExtrusionEntityCollection::polygons_covered_by_spacing(), print_object_config, SCALED_RESOLUTION, Slic3r::Flow::scaled_spacing(), Slic3r::stInternalSolid, Slic3r::Surface::surface_type, Slic3r::union_ex(), and Slic3r::variable_width().

Referenced by fill_surface_extrusion().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _fill_surface_single() [1/2]

void Slic3r::FillSpiralInset::_fill_surface_single ( const FillParams & params,
unsigned int thickness_layers,
const std::pair< float, Point > & direction,
ExPolygon expolygon,
Polylines & polylines_out )
overrideprotectedvirtual

Reimplemented from Slic3r::Fill.

314{
315 BoundingBox bounding_box = expolygon.contour.bounding_box();
316
317 coord_t min_spacing = scale_(this->spacing);
318 coord_t distance = coord_t(min_spacing / params.density);
319
320 if (params.density > 0.9999f && !params.dont_adjust) {
321 distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
322 this->spacing = unscale<double>(distance);
323 }
324
325 Polygons loops = to_polygons(expolygon);
326
327 ExPolygons last{std::move(expolygon)};
328 while (!last.empty()) {
329 last = offset2_ex(last, -(distance + min_spacing / 2), +min_spacing / 2);
330 append(loops, to_polygons(last));
331 }
332
333 // Orders the loops outside in, depth first, which is the order the chaining below expects.
334 loops = union_pt_chained_outside_in(loops);
335
336 std::vector<const Polygon*> loop_refs;
337 loop_refs.reserve(loops.size());
338 for (const Polygon& loop : loops)
339 loop_refs.emplace_back(&loop);
340
341 Polylines spiral_result = generate_spiral_insets<Polygon, Polyline>(params, loop_refs, loops, distance, expolygon);
342
343 append(polylines_out, spiral_result);
344}
coordf_t spacing
Definition FillBase.hpp:147
BoundingBox bounding_box
Definition FillBase.hpp:162
static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance)
Definition FillBase.cpp:366
#define scale_(val)
Definition libslic3r.h:106
float distance(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b)
Definition SpiralVase.cpp:19
static std::vector< PathType > generate_spiral_insets(const FillParams &params, const std::vector< const LoopType * > &loops, const Polygons &loop_outlines, const coord_t distance, const ExPolygon &original_expoly)
Definition FillSpiralInset.cpp:201
Polygons union_pt_chained_outside_in(const Polygons &subject)
Definition ClipperUtils.cpp:1289
std::vector< Polyline > Polylines
Definition Polyline.hpp:22
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:22
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:307
T unscale(Q v)
Definition libslic3r.h:138
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:157

References Slic3r::Fill::_adjust_solid_spacing(), Slic3r::append(), Slic3r::Fill::bounding_box, Slic3r::MultiPoint::bounding_box(), Slic3r::ExPolygon::contour, Slic3r::FillParams::density, Slic3r::FillParams::dont_adjust, Slic3r::generate_spiral_insets(), Slic3r::offset2_ex(), scale_, Slic3r::BoundingBoxBase< PointType, APointsType >::size(), Slic3r::Fill::spacing, Slic3r::to_polygons(), Slic3r::union_pt_chained_outside_in(), and Slic3r::unscale().

Referenced by _fill_surface_single().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _fill_surface_single() [2/2]

void Slic3r::FillSpiralInset::_fill_surface_single ( const FillParams & params,
unsigned int thickness_layers,
const std::pair< float, Point > & direction,
ExPolygon expolygon,
ThickPolylines & thick_polylines_out )
overrideprotectedvirtual

Reimplemented from Slic3r::Fill.

351{
352 assert(params.use_arachne);
353 assert(this->print_config != nullptr && this->print_object_config != nullptr);
354
355 // Internal solid infill must not add Arachne's standalone thin walls: one of those walls can
356 // become the extra centre point after the spiral has finished. Top and bottom surfaces keep
357 // Arachne, including the centre plug handled by generate_spiral_insets().
358 if (params.extrusion_role == erSolidInfill) {
359 Polylines polylines;
360 this->_fill_surface_single(params, thickness_layers, direction, expolygon, polylines);
361 append(thick_polylines_out, to_thick_polylines(std::move(polylines), scaled<coord_t>(this->spacing)));
362 return;
363 }
364
365 // Only a solid surface is worth the variable width walls; a sparse one falls back to plain loops.
366 if (params.density <= 0.9999f || params.dont_adjust) {
367 Polylines polylines;
368 this->_fill_surface_single(params, thickness_layers, direction, expolygon, polylines);
369 append(thick_polylines_out, to_thick_polylines(std::move(polylines), scaled<coord_t>(this->spacing)));
370 return;
371 }
372
373 // no rotation is supported for this infill pattern
374 Point bbox_size = expolygon.contour.bounding_box().size();
375 coord_t min_spacing = scaled<coord_t>(this->spacing);
376
377 coord_t loops_count = std::max(bbox_size.x(), bbox_size.y()) / min_spacing + 1;
378 Polygons polygons = offset(expolygon, float(min_spacing) / 2.f);
379
380 double min_nozzle_diameter = *std::min_element(print_config->nozzle_diameter.values.begin(), print_config->nozzle_diameter.values.end());
381 Arachne::WallToolPathsParams input_params;
382 input_params.min_bead_width = 0.85 * min_nozzle_diameter;
383 input_params.min_feature_size = 0.25 * min_nozzle_diameter;
384 input_params.wall_transition_length = 1.0 * min_nozzle_diameter;
385 input_params.wall_transition_angle = 10;
386 input_params.wall_transition_filter_deviation = 0.25 * min_nozzle_diameter;
387 input_params.wall_distribution_count = 1;
388
389 Arachne::WallToolPaths wallToolPaths(polygons, min_spacing, min_spacing, loops_count, 0, params.layer_height, input_params);
390 std::vector<Arachne::VariableWidthLines> walls_by_inset = wallToolPaths.getToolPaths();
391
392 // Open walls are the thin features Arachne fits between the closed ones. They cannot join a
393 // spiral, so they go out as they are; leaving them behind is what would put the gaps back.
394 std::vector<const Arachne::ExtrusionLine*> walls;
395 Polygons wall_outlines;
396 ThickPolylines open_walls;
397 for (const Arachne::VariableWidthLines& inset : walls_by_inset)
398 for (const Arachne::ExtrusionLine& wall : inset) {
399 if (wall.empty())
400 continue;
401 if (wall.is_closed) {
402 walls.emplace_back(&wall);
403 wall_outlines.emplace_back(wall.toPolygon());
404 } else {
405 open_walls.emplace_back(Arachne::to_thick_polyline(wall));
406 }
407 }
408
409 // Arachne hands the walls back grouped by inset, which is not their nesting: around a hole the
410 // wall of a given inset lies inside the wall of that same inset around the contour. Nest them by
411 // containment instead, so the spiral follows one island all the way in before starting the next,
412 // the same order union_pt_chained_outside_in gives the classic path above.
413 const size_t wall_count = walls.size();
414 std::vector<int> nesting_depth(wall_count, 0), parent(wall_count, -1);
415 std::vector<char> inside(wall_count * wall_count, 0);
416 for (size_t i = 0; i < wall_count; ++i)
417 for (size_t j = 0; j < wall_count; ++j)
418 if (i != j && wall_outlines[j].contains(walls[i]->junctions.front().p)) {
419 inside[i * wall_count + j] = 1;
420 ++nesting_depth[i];
421 }
422 // The innermost of the walls containing this one, which is the deepest of them, is its parent.
423 for (size_t i = 0; i < wall_count; ++i)
424 for (size_t j = 0; j < wall_count; ++j)
425 if (inside[i * wall_count + j] && (parent[i] < 0 || nesting_depth[parent[i]] < nesting_depth[j]))
426 parent[i] = int(j);
427
428 std::vector<const Arachne::ExtrusionLine*> ordered;
429 Polygons outlines;
430 ordered.reserve(wall_count);
431 outlines.reserve(wall_count);
432 std::function<void(int)> descend = [&](int idx) {
433 ordered.emplace_back(walls[idx]);
434 outlines.emplace_back(wall_outlines[idx]);
435 for (size_t k = 0; k < wall_count; ++k)
436 if (parent[k] == idx)
437 descend(int(k));
438 };
439 for (size_t i = 0; i < wall_count; ++i)
440 if (parent[i] < 0)
441 descend(int(i));
442
443 ThickPolylines spiral_result =
444 generate_spiral_insets<Arachne::ExtrusionLine, ThickPolyline>(params, ordered, outlines, min_spacing, expolygon);
445
446 append(thick_polylines_out, std::move(spiral_result));
447 append(thick_polylines_out, std::move(open_walls));
448}
void _fill_surface_single(const FillParams &params, unsigned int thickness_layers, const std::pair< float, Point > &direction, ExPolygon expolygon, Polylines &polylines_out) override
Definition FillSpiralInset.cpp:309
const PrintConfig * print_config
Definition FillBase.hpp:172
static Slic3r::ThickPolyline to_thick_polyline(const PathType &path)
Definition ExtrusionLine.hpp:212
std::vector< ExtrusionLine > VariableWidthLines
Definition ExtrusionLine.hpp:290
bool inside(const Polygons &polygons, const Point &p)
Definition TreeNode.cpp:160
bool contains(const std::vector< T > &vector, const Point &point)
Definition Geometry.cpp:55
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
indexed_triangle_set walls(const Polygon &lower, const Polygon &upper, double lower_z_mm, double upper_z_mm)
Definition Pad.cpp:42
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:284
ThickPolylines to_thick_polylines(Polylines &&polylines, const coordf_t width)
Definition Polyline.hpp:285
@ erSolidInfill
Definition ExtrusionEntity.hpp:32
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582

References _fill_surface_single(), Slic3r::append(), Slic3r::MultiPoint::bounding_box(), Slic3r::Geometry::contains(), Slic3r::ExPolygon::contour, Slic3r::FillParams::density, Slic3r::FillParams::dont_adjust, Slic3r::erSolidInfill, Slic3r::FillParams::extrusion_role, Slic3r::generate_spiral_insets(), Slic3r::Arachne::WallToolPaths::getToolPaths(), Slic3r::FillParams::layer_height, Slic3r::Arachne::WallToolPathsParams::min_bead_width, Slic3r::Arachne::WallToolPathsParams::min_feature_size, Slic3r::offset(), Slic3r::Fill::print_config, Slic3r::Fill::print_object_config, Slic3r::scaled(), Slic3r::BoundingBoxBase< PointType, APointsType >::size(), Slic3r::Fill::spacing, Slic3r::Arachne::to_thick_polyline(), Slic3r::to_thick_polylines(), Slic3r::FillParams::use_arachne, Slic3r::Arachne::WallToolPathsParams::wall_distribution_count, Slic3r::Arachne::WallToolPathsParams::wall_transition_angle, Slic3r::Arachne::WallToolPathsParams::wall_transition_filter_deviation, and Slic3r::Arachne::WallToolPathsParams::wall_transition_length.

Here is the call graph for this function:

◆ _infill_direction()

std::pair< float, Point > Slic3r::Fill::_infill_direction ( const Surface * surface) const
protectedvirtualinherited
387{
388 // set infill angle
389 float out_angle = this->angle;
390
391 if (out_angle == FLT_MAX) {
392 //FIXME Vojtech: Add a warning?
393 printf("Using undefined infill angle\n");
394 out_angle = 0.f;
395 }
396
397 // Bounding box is the bounding box of a perl object Slic3r::Print::Object (c++ object Slic3r::PrintObject)
398 // The bounding box is only undefined in unit tests.
399 Point out_shift = empty(this->bounding_box) ?
400 surface->expolygon.contour.bounding_box().center() :
401 this->bounding_box.center();
402
403#if 0
404 if (empty(this->bounding_box)) {
405 printf("Fill::_infill_direction: empty bounding box!");
406 } else {
407 printf("Fill::_infill_direction: reference point %d, %d\n", out_shift.x, out_shift.y);
408 }
409#endif
410
411 if (surface->bridge_angle >= 0) {
412 // use bridge angle
413 //FIXME Vojtech: Add a debugf?
414 // Slic3r::debugf "Filling bridge with angle %d\n", rad2deg($surface->bridge_angle);
415#ifdef SLIC3R_DEBUG
416 printf("Filling bridge with angle %f\n", surface->bridge_angle);
417#endif /* SLIC3R_DEBUG */
418 out_angle = float(surface->bridge_angle);
419 } else if (this->layer_id != size_t(-1) && !fixed_angle) {
420 // alternate fill direction
421 //Orca: Do not alternate direction if Fill.fixed_angle is true
423 out_angle += this->_layer_angle(this->layer_id / surface->thickness_layers);
424 }
425 } else {
426// printf("Layer_ID undefined!\n");
427 }
428
429 out_angle += float(M_PI/2.);
430 return std::pair<float, Point>(out_angle, out_shift);
431}
#define M_PI
Definition ExtrusionSimulator.cpp:31
bool dont_alternate_fill_direction
Definition FillBase.hpp:177
virtual float _layer_angle(size_t idx) const
Definition FillBase.hpp:244
float angle
Definition FillBase.hpp:151
bool fixed_angle
Definition FillBase.hpp:154
size_t layer_id
Definition FillBase.hpp:143
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:273

References _layer_angle(), angle, bounding_box, Slic3r::MultiPoint::bounding_box(), Slic3r::Surface::bridge_angle, Slic3r::BoundingBoxBase< PointType, APointsType >::center(), Slic3r::ExPolygon::contour, dont_alternate_fill_direction, Slic3r::empty(), Slic3r::Surface::expolygon, fixed_angle, layer_id, M_PI, and Slic3r::Surface::thickness_layers.

Referenced by fill_surface(), Slic3r::FillSupportBase::fill_surface(), fill_surface_arachne(), Slic3r::FillRectilinear::fill_surface_by_lines(), Slic3r::FillRectilinear::fill_surface_by_multilines(), and Slic3r::FillRectilinear::fill_surface_trapezoidal().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _layer_angle()

virtual float Slic3r::Fill::_layer_angle ( size_t idx) const
inlineprotectedvirtualinherited

Reimplemented in Slic3r::FillAlignedRectilinear, Slic3r::FillCubic, Slic3r::FillGrid, Slic3r::FillHoneycomb, Slic3r::FillLateralLattice, Slic3r::FillPlanePath, Slic3r::FillQuarterCubic, Slic3r::FillStars, Slic3r::FillSupportBase, and Slic3r::FillTriangles.

244{ return fixed_angle ? 0.f : (idx & 1) ? float(M_PI/2.) : 0.f; }

References fixed_angle, and M_PI.

Referenced by _infill_direction().

Here is the caller graph for this function:

◆ aligned_to_origin()

virtual bool Slic3r::Fill::aligned_to_origin ( ) const
inlinevirtualinherited

Reimplemented in Slic3r::Fill3DHoneycomb, Slic3r::FillCrossHatch, Slic3r::FillGyroid, Slic3r::FillHoneycomb, Slic3r::FillTpmsD, and Slic3r::FillTpmsFK.

204{ return false; }

Referenced by fill_surface().

Here is the caller graph for this function:

◆ chain_or_connect_infill()

void Slic3r::Fill::chain_or_connect_infill ( Polylines && infill_ordered,
const ExPolygon & boundary,
Polylines & polylines_out,
const double spacing,
const FillParams & params )
staticinherited
2054{
2055 if (!infill_ordered.empty()) {
2056 if (params.dont_connect()) {
2057 if (infill_ordered.size() > 1)
2058 infill_ordered = chain_polylines(std::move(infill_ordered));
2059 append(polylines_out, std::move(infill_ordered));
2060 } else
2061 connect_infill(std::move(infill_ordered), boundary, polylines_out, spacing, params);
2062 }
2063}
static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams &params)
Definition FillBase.cpp:1354
Polylines chain_polylines(Polylines &&polylines, const Point *start_near)
Definition ShortestPath.cpp:2502

References Slic3r::append(), Slic3r::chain_polylines(), connect_infill(), Slic3r::FillParams::dont_connect(), and spacing.

Referenced by Slic3r::Fill3DHoneycomb::_fill_surface_single(), Slic3r::FillCrossHatch::_fill_surface_single(), Slic3r::FillGyroid::_fill_surface_single(), Slic3r::FillHoneycomb::_fill_surface_single(), and Slic3r::FillLightning::Filler::_fill_surface_single().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clone()

Fill * Slic3r::FillSpiralInset::clone ( ) const
inlineoverrideprotectedvirtual

Implements Slic3r::Fill.

20{ return new FillSpiralInset(*this); };

References Slic3r::Fill::Fill().

Here is the call graph for this function:

◆ connect_base_support() [1/2]

void Slic3r::Fill::connect_base_support ( Polylines && infill_ordered,
const Polygons & boundary_src,
const BoundingBox & bbox,
Polylines & polylines_out,
const double spacing,
const FillParams & params )
staticinherited
2938{
2939 auto polygons_src = reserve_vector<const Polygon*>(boundary_src.size());
2940 for (const Polygon &polygon : boundary_src)
2941 polygons_src.emplace_back(&polygon);
2942
2943 connect_base_support(std::move(infill_ordered), polygons_src, bbox, polylines_out, spacing, params);
2944}
static void connect_base_support(Polylines &&infill_ordered, const std::vector< const Polygon * > &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams &params)
Definition FillBase.cpp:2480
IntegerOnly< I, std::vector< T, Args... > > reserve_vector(I capacity)
Definition libslic3r.h:370

References connect_base_support(), Slic3r::reserve_vector(), and spacing.

Here is the call graph for this function:

◆ connect_base_support() [2/2]

void Slic3r::Fill::connect_base_support ( Polylines && infill_ordered,
const std::vector< const Polygon * > & boundary_src,
const BoundingBox & bbox,
Polylines & polylines_out,
const double spacing,
const FillParams & params )
staticinherited
2481{
2482// assert(! infill_ordered.empty());
2483 assert(params.anchor_length >= 0.);
2484 assert(params.anchor_length_max >= 0.01f);
2485 assert(params.anchor_length_max >= params.anchor_length);
2486
2487 BoundaryInfillGraph graph = create_boundary_infill_graph(infill_ordered, boundary_src, bbox, spacing);
2488
2489#ifdef INFILL_DEBUG_OUTPUT
2490 static int iRun = 0;
2491 ++ iRun;
2492 export_partial_infill_to_svg(debug_out_path("connect_base_support-initial-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2493#endif // INFILL_DEBUG_OUTPUT
2494
2495 const double line_half_width = 0.5 * scale_(spacing);
2496 const double line_spacing = scale_(spacing) / params.density;
2497 const double min_arch_length = 1.3 * line_spacing;
2498 const double trim_length = line_half_width * 0.3;
2499
2500// After mark_boundary_segments_touching_infill() marks boundary segments overlapping trimmed infill lines,
2501// there are possibly some very short boundary segments unmarked, but overlapping the untrimmed infill lines fully.
2502// Mark those short boundary segments.
2504
2505#ifdef INFILL_DEBUG_OUTPUT
2506 export_partial_infill_to_svg(debug_out_path("connect_base_support-marked-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2507#endif // INFILL_DEBUG_OUTPUT
2508
2509 // Detect loops with zero infill end points connected.
2510 // Extrude these loops as perimeters.
2511 {
2512 std::vector<size_t> num_boundary_contour_infill_points(graph.boundary.size(), 0);
2513 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary)
2514 ++ num_boundary_contour_infill_points[cp.contour_idx];
2515 for (size_t i = 0; i < num_boundary_contour_infill_points.size(); ++ i)
2516 if (num_boundary_contour_infill_points[i] == 0 && graph.boundary_params[i].back() > trim_length + 0.5 * line_spacing) {
2517 // Emit a perimeter.
2518 Polyline pl(graph.boundary[i]);
2519 pl.points.emplace_back(pl.points.front());
2520 pl.clip_end(trim_length);
2521 if (pl.size() > 1)
2522 polylines_out.emplace_back(std::move(pl));
2523 }
2524 }
2525
2526 // Before processing the boundary arches, emit those arches, which were trimmed by the infill lines at both sides, but which
2527 // depart from the infill line at least once after touching the infill line.
2528 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2529 if (cp.next_on_contour && cp.next_trimmed && cp.next_on_contour->prev_trimmed) {
2530 // The arch is leaving one infill line to end up at the same infill line or at the neighbouring one.
2531 // The arch is touching one of those infill lines at least once.
2532 // Trace those arches and emit their parts, which are not attached to the end points and they are not overlapping with the two infill lines mentioned.
2533 bool first = graph.first(cp);
2534 coord_t left = graph.point(cp).x();
2535 coord_t right = left;
2536 if (first) {
2537 left += line_half_width;
2538 right += line_spacing - line_half_width;
2539 } else {
2540 left -= line_spacing - line_half_width;
2541 right -= line_half_width;
2542 }
2543 double param_start = cp.param + cp.contour_not_taken_length_next;
2544 double param_end = cp.next_on_contour->param - cp.next_on_contour->contour_not_taken_length_prev;
2545 double contour_length = graph.boundary_params[cp.contour_idx].back();
2546 if (param_start >= contour_length)
2547 param_start -= contour_length;
2548 if (param_end < 0)
2549 param_end += contour_length;
2550 // Verify that the interval (param_overlap1, param_overlap2) is inside the interval (ip_low->param, ip_high->param).
2551 assert(cyclic_interval_inside_interval(cp.param, cp.next_on_contour->param, param_start, param_end, contour_length));
2552 emit_loops_in_band(left, right, graph.boundary[cp.contour_idx], graph.boundary_params[cp.contour_idx], param_start, param_end, 0.5 * line_spacing, polylines_out);
2553 }
2554 }
2555#ifdef INFILL_DEBUG_OUTPUT
2556 export_partial_infill_to_svg(debug_out_path("connect_base_support-excess-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2557#endif // INFILL_DEBUG_OUTPUT
2558
2559 base_support_extend_infill_lines(infill_ordered, graph, spacing, params);
2560
2561#ifdef INFILL_DEBUG_OUTPUT
2562 export_partial_infill_to_svg(debug_out_path("connect_base_support-extended-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2563#endif // INFILL_DEBUG_OUTPUT
2564
2565 std::vector<size_t> merged_with(infill_ordered.size());
2566 std::iota(merged_with.begin(), merged_with.end(), 0);
2567 auto get_and_update_merged_with = [&graph, &merged_with](const ContourIntersectionPoint *cp) -> size_t {
2568 size_t polyline_idx = (cp - graph.map_infill_end_point_to_boundary.data()) / 2;
2569 for (size_t last = polyline_idx;;) {
2570 size_t lower = merged_with[last];
2571 assert(lower <= last);
2572 if (lower == last) {
2573 merged_with[polyline_idx] = last;
2574 return last;
2575 }
2576 last = lower;
2577 }
2578 assert(false);
2579 return std::numeric_limits<size_t>::max();
2580 };
2581
2582 auto vertical = [](BoundaryInfillGraph::Direction dir) {
2583 return dir == BoundaryInfillGraph::Up || dir == BoundaryInfillGraph::Down;
2584 };
2585 // When both left / right arch connected to cp is vertical (ends up at the same vertical infill line), which one to take?
2586 auto take_vertical_prev = [](const ContourIntersectionPoint &cp) {
2587 return cp.prev_trimmed == cp.next_trimmed ?
2588 // Both are either trimmed or not trimmed. Take the longer contour.
2589 cp.contour_not_taken_length_prev > cp.contour_not_taken_length_next :
2590 // One is trimmed, the other is not trimmed. Take the not trimmed.
2591 ! cp.prev_trimmed && cp.next_trimmed;
2592 };
2593
2594 // Connect infill lines at cp and cpo_next_on_contour.
2595 // If the complete arch cannot be taken, then
2596 // if (take_first)
2597 // take the infill line at cp and an arc from cp towards cp.next_on_contour.
2598 // else
2599 // take the infill line at cp_next_on_contour and an arc from cp.next_on_contour towards cp.
2600 // If cp1 == next_on_contour (a single infill line is connected to a contour, this is a valid case for contours with holes),
2601 // then extrude the full circle.
2602 // Nothing is done if the arch could no more be taken (one of it end points were consumed already).
2603 auto take_next = [&graph, &infill_ordered, &merged_with, get_and_update_merged_with, line_half_width, trim_length](ContourIntersectionPoint &cp, bool take_first) {
2604 // Indices of the polylines to be connected by a perimeter segment.
2605 ContourIntersectionPoint *cp1 = &cp;
2606 ContourIntersectionPoint *cp2 = cp.next_on_contour;
2607 assert(cp1->next_trimmed == cp2->prev_trimmed);
2608 //assert(cp1->next_trimmed || cp1->consumed == cp2->consumed);
2609 if (take_first ? cp1->consumed : cp2->consumed)
2610 return;
2611 size_t polyline_idx1 = get_and_update_merged_with(cp1);
2612 size_t polyline_idx2 = get_and_update_merged_with(cp2);
2613 Polyline &polyline1 = infill_ordered[polyline_idx1];
2614 Polyline &polyline2 = infill_ordered[polyline_idx2];
2615 const Points &contour = graph.boundary[cp1->contour_idx];
2616 const std::vector<double> &contour_params = graph.boundary_params[cp1->contour_idx];
2617 assert(cp1->consumed || contour[cp1->point_idx] == polyline1.points.front() || contour[cp1->point_idx] == polyline1.points.back());
2618 assert(cp2->consumed || contour[cp2->point_idx] == polyline2.points.front() || contour[cp2->point_idx] == polyline2.points.back());
2619 bool trimmed = take_first ? cp1->next_trimmed : cp2->prev_trimmed;
2620 if (! trimmed) {
2621 // Trim the end if closing a loop or making a T-joint.
2622 trimmed = cp1 == cp2 || polyline_idx1 == polyline_idx2 || (take_first ? cp2->consumed : cp1->consumed);
2623 if (! trimmed) {
2624 const bool cp1_first = ((cp1 - graph.map_infill_end_point_to_boundary.data()) & 1) == 0;
2625 const ContourIntersectionPoint* cp1_other = cp1_first ? cp1 + 1 : cp1 - 1;
2626 // Self loop, connecting the end points of the same infill line.
2627 trimmed = cp2 == cp1_other;
2628 }
2629 if (trimmed) /* [[unlikely]] */ {
2630 // Single end point on a contour. This may happen on contours with holes. Extrude a loop.
2631 // Or a self loop, connecting the end points of the same infill line.
2632 // Or closing a chain of infill lines. This may happen if infilling a contour with a hole.
2633 double len = cp1 == cp2 ? contour_params.back() : path_length_along_contour_ccw(cp1, cp2, contour_params.back());
2634 if (take_first) {
2635 cp1->trim_next(std::max(0., len - trim_length - SCALED_EPSILON));
2636 cp2->trim_prev(0);
2637 } else {
2638 cp1->trim_next(0);
2639 cp2->trim_prev(std::max(0., len - trim_length - SCALED_EPSILON));
2640 }
2641 }
2642 }
2643 if (trimmed) {
2644 if (take_first)
2645 take_limited(polyline1, contour, contour_params, cp1, cp2, false, 1e10, line_half_width);
2646 else
2647 take_limited(polyline2, contour, contour_params, cp2, cp1, true, 1e10, line_half_width);
2648 } else if (! cp1->consumed && ! cp2->consumed) {
2649 if (contour[cp1->point_idx] == polyline1.points.front())
2650 polyline1.reverse();
2651 if (contour[cp2->point_idx] == polyline2.points.back())
2652 polyline2.reverse();
2653 take(polyline1, polyline2, contour, cp1, cp2, false);
2654 // Mark the second polygon as merged with the first one.
2655 if (polyline_idx2 < polyline_idx1) {
2656 polyline2 = std::move(polyline1);
2657 polyline1.points.clear();
2658 merged_with[polyline_idx1] = merged_with[polyline_idx2];
2659 } else {
2660 polyline2.points.clear();
2661 merged_with[polyline_idx2] = merged_with[polyline_idx1];
2662 }
2663 }
2664 };
2665
2666 // Consume all vertical arches. If a vertical arch is touching a neighboring vertical infill line, thus the vertical arch is trimmed,
2667 // only consume the trimmed part if it is longer than min_arch_length.
2668 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2669 assert(cp.contour_idx != boundary_idx_unconnected);
2670 if (cp.consumed)
2671 continue;
2672 const ContourIntersectionPoint &cp_other = graph.other(cp);
2673 assert((cp.next_on_contour == &cp_other) == (cp_other.prev_on_contour == &cp));
2674 assert((cp.prev_on_contour == &cp_other) == (cp_other.next_on_contour == &cp));
2675 BoundaryInfillGraph::Direction dir_prev = graph.dir_prev(cp);
2676 BoundaryInfillGraph::Direction dir_next = graph.dir_next(cp);
2677 // Following code will also consume contours with just a single infill line attached. (cp1->next_on_contour == cp1).
2678 assert((cp.next_on_contour == &cp) == (cp.prev_on_contour == &cp));
2679 bool can_take_prev = vertical(dir_prev) && ! cp.prev_on_contour->consumed && cp.prev_on_contour != &cp_other;
2680 bool can_take_next = vertical(dir_next) && ! cp.next_on_contour->consumed && cp.next_on_contour != &cp_other;
2681 if (can_take_prev && (! can_take_next || take_vertical_prev(cp))) {
2682 if (! cp.prev_trimmed || cp.contour_not_taken_length_prev > min_arch_length)
2683 // take previous
2684 take_next(*cp.prev_on_contour, false);
2685 } else if (can_take_next) {
2686 if (! cp.next_trimmed || cp.contour_not_taken_length_next > min_arch_length)
2687 // take next
2688 take_next(cp, true);
2689 }
2690 }
2691
2692#ifdef INFILL_DEBUG_OUTPUT
2693 export_partial_infill_to_svg(debug_out_path("connect_base_support-vertical-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2694#endif // INFILL_DEBUG_OUTPUT
2695
2696 const std::vector<SupportArcCost> arches = evaluate_support_arches(infill_ordered, graph, spacing, params);
2697 // Must not be static: line_spacing varies per call (base vs interface fills differ),
2698 // and a static here would fix these to whichever call ran first, order depending on thread count.
2699 const double cost_low = line_spacing * 1.3;
2700 const double cost_high = line_spacing * 2.;
2701 const double cost_veryhigh = line_spacing * 3.;
2702
2703 {
2704 std::vector<const SupportArcCost*> selected;
2705 selected.reserve(graph.map_infill_end_point_to_boundary.size());
2706 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2707 if (cp.consumed)
2708 continue;
2709 const SupportArcCost &cost_prev = arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2];
2710 const SupportArcCost &cost_next = *(&cost_prev + 1);
2711 double cost_min = cost_prev.cost;
2712 double cost_max = cost_next.cost;
2713 if (cost_min > cost_max)
2714 std::swap(cost_min, cost_max);
2715 if (cost_max < cost_low || cost_min > cost_high)
2716 // Don't take any of the prev / next arches now, take zig-zag instead. It does not matter which one will be taken.
2717 continue;
2718 const double cost_diff_relative = (cost_max - cost_min) / cost_max;
2719 if (cost_diff_relative < 0.25)
2720 // Don't take any of the prev / next arches now, take zig-zag instead. It does not matter which one will be taken.
2721 continue;
2722 if (cost_prev.cost > cost_low)
2723 selected.emplace_back(&cost_prev);
2724 if (cost_next.cost > cost_low)
2725 selected.emplace_back(&cost_next);
2726 }
2727 // Take the longest arch first.
2728 std::sort(selected.begin(), selected.end(), [](const auto *l, const auto *r) { return l->cost > r->cost; });
2729 // And connect along the arches.
2730 for (const SupportArcCost *arc : selected) {
2731 ContourIntersectionPoint &cp = graph.map_infill_end_point_to_boundary[(arc - arches.data()) / 2];
2732 if (! cp.consumed) {
2733 bool prev = ((arc - arches.data()) & 1) == 0;
2734 if (prev)
2735 take_next(*cp.prev_on_contour, false);
2736 else
2737 take_next(cp, true);
2738 }
2739 }
2740 }
2741
2742#if 0
2743 {
2744 // Connect infill lines with long horizontal arches. Only take a horizontal arch, if it will not block
2745 // the end caps (vertical arches) at the other side of the infill line.
2746 struct Arc {
2747 ContourIntersectionPoint *intersection;
2748 double arc_length;
2749 bool take_next;
2750 };
2751 std::vector<Arc> arches;
2752 arches.reserve(graph.map_infill_end_point_to_boundary.size());
2753 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2754 if (cp.consumed)
2755 continue;
2756 // Not a losed loop, such loops should already be consumed.
2757 assert(cp.next_on_contour != &cp);
2758 const bool first = ((&cp - graph.map_infill_end_point_to_boundary.data()) & 1) == 0;
2759 const ContourIntersectionPoint *other_end = first ? &cp + 1 : &cp - 1;
2760 const bool loop_next = cp.next_on_contour == other_end;
2761 if (! loop_next && cp.could_connect_next()) {
2762 if (cp.contour_not_taken_length_next > min_arch_length) {
2763 // Try both directions. This is useful to be able to close a loop back to the same line to take a long arch.
2764 arches.push_back({ &cp, cp.contour_not_taken_length_next, true });
2765 arches.push_back({ cp.next_on_contour, cp.contour_not_taken_length_next, false });
2766 }
2767 } else {
2768 //bool first = ((&cp - graph.map_infill_end_point_to_boundary) & 1) == 0;
2769 if (cp.prev_trimmed && cp.could_take_prev()) {
2770 //FIXME trace the trimmed line to decide what priority to assign to it.
2771 // Is the end point close to the current vertical line or to the other vertical line?
2772 const Point &pt = graph.point(cp);
2773 const Point &prev = graph.point(*cp.prev_on_contour);
2774 if (std::abs(pt.x() - prev.x()) < coord_t(0.5 * line_spacing)) {
2775 // End point on the same line.
2776 // Measure maximum distance from the current vertical line.
2777 if (cp.contour_not_taken_length_prev > 0.5 * line_spacing)
2778 arches.push_back({ &cp, cp.contour_not_taken_length_prev, false });
2779 } else {
2780 // End point on the other line.
2781 if (cp.contour_not_taken_length_prev > min_arch_length)
2782 arches.push_back({ &cp, cp.contour_not_taken_length_prev, false });
2783 }
2784 }
2785 if (cp.next_trimmed && cp.could_take_next()) {
2786 //FIXME trace the trimmed line to decide what priority to assign to it.
2787 const Point &pt = graph.point(cp);
2788 const Point &next = graph.point(*cp.next_on_contour);
2789 if (std::abs(pt.x() - next.x()) < coord_t(0.5 * line_spacing)) {
2790 // End point on the same line.
2791 // Measure maximum distance from the current vertical line.
2792 if (cp.contour_not_taken_length_next > 0.5 * line_spacing)
2793 arches.push_back({ &cp, cp.contour_not_taken_length_next, true });
2794 } else {
2795 // End point on the other line.
2796 if (cp.contour_not_taken_length_next > min_arch_length)
2797 arches.push_back({ &cp, cp.contour_not_taken_length_next, true });
2798 }
2799 }
2800 }
2801 }
2802 // Take the longest arch first.
2803 std::sort(arches.begin(), arches.end(), [](const auto &l, const auto &r) { return l.arc_length > r.arc_length; });
2804 // And connect along the arches.
2805 for (Arc &arc : arches)
2806 if (arc.take_next)
2807 take_next(*arc.intersection, true);
2808 else
2809 take_next(*arc.intersection->prev_on_contour, false);
2810 }
2811#endif
2812
2813#ifdef INFILL_DEBUG_OUTPUT
2814 export_partial_infill_to_svg(debug_out_path("connect_base_support-arches-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2815#endif // INFILL_DEBUG_OUTPUT
2816
2817 // Traverse the unconnected lines in a zig-zag fashion, left to right only.
2818 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2819 assert(cp.contour_idx != boundary_idx_unconnected);
2820 if (cp.consumed)
2821 continue;
2822 bool first = ((&cp - graph.map_infill_end_point_to_boundary.data()) & 1) == 0;
2823 if (first) {
2824 // Only connect if the two lines are not connected by the same line already.
2825 if (get_and_update_merged_with(&cp) != get_and_update_merged_with(cp.next_on_contour))
2826 take_next(cp, true);
2827 } else {
2828 if (get_and_update_merged_with(&cp) != get_and_update_merged_with(cp.prev_on_contour))
2829 take_next(*cp.prev_on_contour, false);
2830 }
2831 }
2832
2833#ifdef INFILL_DEBUG_OUTPUT
2834 export_partial_infill_to_svg(debug_out_path("connect_base_support-zigzag-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2835#endif // INFILL_DEBUG_OUTPUT
2836
2837 // Add the left caps.
2838 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2839 const bool first = ((&cp - graph.map_infill_end_point_to_boundary.data()) & 1) == 0;
2840 const ContourIntersectionPoint *other_end = first ? &cp + 1 : &cp - 1;
2841 const bool loop_next = cp.next_on_contour == other_end;
2842 const bool loop_prev = other_end->next_on_contour == &cp;
2843#ifndef NDEBUG
2844 const SupportArcCost &cost_prev = arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2];
2845 const SupportArcCost &cost_next = *(&cost_prev + 1);
2846 assert(cost_prev.self_loop == loop_prev);
2847 assert(cost_next.self_loop == loop_next);
2848#endif // NDEBUG
2849 if (loop_prev && cp.could_take_prev())
2850 take_next(*cp.prev_on_contour, false);
2851 if (loop_next && cp.could_take_next())
2852 take_next(cp, true);
2853 }
2854
2855#ifdef INFILL_DEBUG_OUTPUT
2856 export_partial_infill_to_svg(debug_out_path("connect_base_support-caps-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2857#endif // INFILL_DEBUG_OUTPUT
2858
2859 // Connect with T joints using long arches. Loops could be created only if a very long arc has to be added.
2860 {
2861 std::vector<const SupportArcCost*> candidates;
2862 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2863 if (cp.could_take_prev())
2864 candidates.emplace_back(&arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2]);
2865 if (cp.could_take_next())
2866 candidates.emplace_back(&arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2 + 1]);
2867 }
2868 std::sort(candidates.begin(), candidates.end(), [](auto *c1, auto *c2) { return c1->cost > c2->cost; });
2869 for (const SupportArcCost *candidate : candidates) {
2870 ContourIntersectionPoint &cp = graph.map_infill_end_point_to_boundary[(candidate - arches.data()) / 2];
2871 bool prev = ((candidate - arches.data()) & 1) == 0;
2872 if (prev) {
2873 if (cp.could_take_prev() && (get_and_update_merged_with(&cp) != get_and_update_merged_with(cp.prev_on_contour) || candidate->cost > cost_high))
2874 take_next(*cp.prev_on_contour, false);
2875 } else {
2876 if (cp.could_take_next() && (get_and_update_merged_with(&cp) != get_and_update_merged_with(cp.next_on_contour) || candidate->cost > cost_high))
2877 take_next(cp, true);
2878 }
2879 }
2880 }
2881
2882#ifdef INFILL_DEBUG_OUTPUT
2883 export_partial_infill_to_svg(debug_out_path("connect_base_support-Tjoints-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2884#endif // INFILL_DEBUG_OUTPUT
2885
2886 // Add very long arches and reasonably long caps even if both of its end points were already consumed.
2887 const double cap_cost = 0.5 * line_spacing;
2888 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2889 const SupportArcCost &cost_prev = arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2];
2890 const SupportArcCost &cost_next = *(&cost_prev + 1);
2891 if (cp.contour_not_taken_length_prev > SCALED_EPSILON &&
2892 (cost_prev.self_loop ?
2893 cost_prev.cost > cap_cost :
2894 cost_prev.cost > cost_veryhigh)) {
2895 assert(cp.consumed && (cp.prev_on_contour->consumed || cp.prev_trimmed));
2896 Polyline pl { graph.point(cp) };
2897 if (! cp.prev_trimmed) {
2898 cp.trim_prev(cp.contour_not_taken_length_prev - line_half_width);
2899 cp.prev_on_contour->trim_next(0);
2900 }
2901 if (cp.contour_not_taken_length_prev > SCALED_EPSILON) {
2902 take_cw_limited(pl, graph.boundary[cp.contour_idx], graph.boundary_params[cp.contour_idx], cp.point_idx, cp.prev_on_contour->point_idx, cp.contour_not_taken_length_prev);
2903 cp.trim_prev(0);
2904 pl.clip_start(line_half_width);
2905 polylines_out.emplace_back(std::move(pl));
2906 }
2907 }
2908 if (cp.contour_not_taken_length_next > SCALED_EPSILON &&
2909 (cost_next.self_loop ?
2910 cost_next.cost > cap_cost :
2911 cost_next.cost > cost_veryhigh)) {
2912 assert(cp.consumed && (cp.next_on_contour->consumed || cp.next_trimmed));
2913 Polyline pl { graph.point(cp) };
2914 if (! cp.next_trimmed) {
2915 cp.trim_next(cp.contour_not_taken_length_next - line_half_width);
2916 cp.next_on_contour->trim_prev(0);
2917 }
2918 if (cp.contour_not_taken_length_next > SCALED_EPSILON) {
2919 take_ccw_limited(pl, graph.boundary[cp.contour_idx], graph.boundary_params[cp.contour_idx], cp.point_idx, cp.next_on_contour->point_idx, cp.contour_not_taken_length_next); // line_half_width);
2920 cp.trim_next(0);
2921 pl.clip_start(line_half_width);
2922 polylines_out.emplace_back(std::move(pl));
2923 }
2924 }
2925 }
2926
2927#ifdef INFILL_DEBUG_OUTPUT
2928 export_partial_infill_to_svg(debug_out_path("connect_base_support-final-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2929#endif // INFILL_DEBUG_OUTPUT
2930
2931 polylines_out.reserve(polylines_out.size() + std::count_if(infill_ordered.begin(), infill_ordered.end(), [](const Polyline &pl) { return ! pl.empty(); }));
2932 for (Polyline &pl : infill_ordered)
2933 if (! pl.empty())
2934 polylines_out.emplace_back(std::move(pl));
2935}
Points points
Definition MultiPoint.hpp:22
#define SCALED_EPSILON
Definition libslic3r.h:109
void arc(std::vector< std::pair< Vec2d, Vec2d > > &out, double cx, double cy, double rx, double ry, double a0, double a1, int n=14)
Definition DesignSketchTool.cpp:7759
std::string debug_out_path(const char *name,...)
Definition utils.cpp:382
static double take_ccw_limited(Polyline &pl, const Points &contour, const std::vector< double > &params, size_t idx_start, size_t idx_end, double length_to_take)
Definition FillBase.cpp:601
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:769
static void take(Polyline &pl1, const Polyline &pl2, const Points &contour, size_t idx_start, size_t idx_end, bool clockwise)
Definition FillBase.cpp:642
double path_length_along_contour_ccw(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, double contour_length)
Definition FillBase.cpp:502
static void emit_loops_in_band(coord_t left, coord_t right, const Points &contour, const std::vector< double > &contour_params, double tbegin, double tend, double min_length, Polylines &polylines_out)
Definition FillBase.cpp:2188
BoundaryInfillGraph create_boundary_infill_graph(const Polylines &infill_ordered, const std::vector< const Polygon * > &boundary_src, const BoundingBox &bbox, const double spacing)
Definition FillBase.cpp:1543
static bool cyclic_interval_inside_interval(double outer_low, double outer_high, double inner_low, double inner_high, double length)
Definition FillBase.cpp:968
static constexpr auto boundary_idx_unconnected
Definition FillBase.cpp:1374
static void take_limited(Polyline &pl1, const Points &contour, const std::vector< double > &params, ContourIntersectionPoint *cp_start, ContourIntersectionPoint *cp_end, bool clockwise, double take_max_length, double line_half_width)
Definition FillBase.cpp:688
static std::vector< SupportArcCost > evaluate_support_arches(Polylines &infill, BoundaryInfillGraph &graph, const double spacing, const FillParams &params)
Definition FillBase.cpp:2436
static double take_cw_limited(Polyline &pl, const Points &contour, const std::vector< double > &params, size_t idx_start, size_t idx_end, double length_to_take)
Definition FillBase.cpp:545
static void mark_boundary_segments_overlapping_infill(BoundaryInfillGraph &graph, const Polylines &infill, const double spacing)
Definition FillBase.cpp:1463
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:30
static void base_support_extend_infill_lines(Polylines &infill, BoundaryInfillGraph &graph, const double spacing, const FillParams &params)
Definition FillBase.cpp:2067
@ right
Definition MarchingSquares.hpp:190
@ left
Definition MarchingSquares.hpp:188
Direction
Definition FillBase.cpp:1409
@ Down
Definition FillBase.cpp:1413
@ Up
Definition FillBase.cpp:1412

References Slic3r::FillParams::anchor_length, Slic3r::FillParams::anchor_length_max, Slic3r::base_support_extend_infill_lines(), Slic3r::BoundaryInfillGraph::boundary, Slic3r::boundary_idx_unconnected, Slic3r::BoundaryInfillGraph::boundary_params, Slic3r::Polyline::clip_end(), Slic3r::Polyline::clip_start(), Slic3r::ContourIntersectionPoint::consumed, Slic3r::contour(), Slic3r::ContourIntersectionPoint::contour_idx, Slic3r::ContourIntersectionPoint::contour_not_taken_length_next, Slic3r::ContourIntersectionPoint::contour_not_taken_length_prev, Slic3r::SupportArcCost::cost, Slic3r::ContourIntersectionPoint::could_connect_next(), Slic3r::ContourIntersectionPoint::could_take_next(), Slic3r::ContourIntersectionPoint::could_take_prev(), Slic3r::create_boundary_infill_graph(), Slic3r::cyclic_interval_inside_interval(), Slic3r::debug_out_path(), Slic3r::FillParams::density, Slic3r::BoundaryInfillGraph::dir_next(), Slic3r::BoundaryInfillGraph::dir_prev(), Slic3r::BoundaryInfillGraph::Down, Slic3r::emit_loops_in_band(), Slic3r::MultiPoint::empty(), Slic3r::evaluate_support_arches(), Slic3r::BoundaryInfillGraph::first(), Slic3r::intersection(), Slic3r::BoundaryInfillGraph::map_infill_end_point_to_boundary, Slic3r::mark_boundary_segments_overlapping_infill(), Slic3r::ContourIntersectionPoint::next_on_contour, Slic3r::ContourIntersectionPoint::next_trimmed, Slic3r::BoundaryInfillGraph::other(), Slic3r::ContourIntersectionPoint::param, Slic3r::path_length_along_contour_ccw(), Slic3r::BoundaryInfillGraph::point(), Slic3r::ContourIntersectionPoint::point_idx, Slic3r::MultiPoint::points, Slic3r::ContourIntersectionPoint::prev_on_contour, Slic3r::ContourIntersectionPoint::prev_trimmed, Slic3r::Polyline::reverse(), scale_, SCALED_EPSILON, Slic3r::SupportArcCost::self_loop, Slic3r::MultiPoint::size(), spacing, Slic3r::take(), Slic3r::take_ccw_limited(), Slic3r::take_cw_limited(), Slic3r::take_limited(), Slic3r::ContourIntersectionPoint::trim_next(), Slic3r::ContourIntersectionPoint::trim_prev(), and Slic3r::BoundaryInfillGraph::Up.

Referenced by connect_base_support(), and Slic3r::FillSupportBase::fill_surface().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ connect_infill() [1/3]

void Slic3r::Fill::connect_infill ( Polylines && infill_ordered,
const ExPolygon & boundary,
Polylines & polylines_out,
const double spacing,
const FillParams & params )
staticinherited
1355{
1356 assert(! boundary_src.contour.points.empty());
1357 auto polygons_src = reserve_vector<const Polygon*>(boundary_src.holes.size() + 1);
1358 polygons_src.emplace_back(&boundary_src.contour);
1359 for (const Polygon &polygon : boundary_src.holes)
1360 polygons_src.emplace_back(&polygon);
1361
1362 connect_infill(std::move(infill_ordered), polygons_src, get_extents(boundary_src.contour), polylines_out, spacing, params);
1363}
BoundingBox get_extents(const ExPolygonsWithIds &e)
Definition Emboss.cpp:1374

References connect_infill(), Slic3r::ExPolygon::contour, Slic3r::get_extents(), Slic3r::ExPolygon::holes, Slic3r::MultiPoint::points, Slic3r::reserve_vector(), and spacing.

Referenced by Slic3r::FillPlanePath::_fill_surface_single(), Slic3r::FillTpmsD::_fill_surface_single(), Slic3r::FillTpmsFK::_fill_surface_single(), chain_or_connect_infill(), connect_infill(), connect_infill(), Slic3r::FillRectilinear::fill_surface_by_multilines(), and Slic3r::FillRectilinear::fill_surface_trapezoidal().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ connect_infill() [2/3]

void Slic3r::Fill::connect_infill ( Polylines && infill_ordered,
const Polygons & boundary,
const BoundingBox & bbox,
Polylines & polylines_out,
const double spacing,
const FillParams & params )
staticinherited
1366{
1367 auto polygons_src = reserve_vector<const Polygon*>(boundary_src.size());
1368 for (const Polygon &polygon : boundary_src)
1369 polygons_src.emplace_back(&polygon);
1370
1371 connect_infill(std::move(infill_ordered), polygons_src, bbox, polylines_out, spacing, params);
1372}

References connect_infill(), Slic3r::reserve_vector(), and spacing.

Here is the call graph for this function:

◆ connect_infill() [3/3]

void Slic3r::Fill::connect_infill ( Polylines && infill_ordered,
const std::vector< const Polygon * > & boundary,
const BoundingBox & bbox,
Polylines & polylines_out,
double spacing,
const FillParams & params )
staticinherited
1697{
1698 assert(! infill_ordered.empty());
1699 assert(params.anchor_length >= 0.);
1700 assert(params.anchor_length_max >= 0.01f);
1701 assert(params.anchor_length_max >= params.anchor_length);
1702 const double anchor_length = scale_(params.anchor_length);
1703 const double anchor_length_max = scale_(params.anchor_length_max);
1704
1705#if 0
1706 append(polylines_out, infill_ordered);
1707 return;
1708#endif
1709
1710 BoundaryInfillGraph graph = create_boundary_infill_graph(infill_ordered, boundary_src, bbox, spacing);
1711
1712 std::vector<size_t> merged_with(infill_ordered.size());
1713 std::iota(merged_with.begin(), merged_with.end(), 0);
1714
1715 auto get_and_update_merged_with = [&merged_with](size_t polyline_idx) -> size_t {
1716 for (size_t last = polyline_idx;;) {
1717 size_t lower = merged_with[last];
1718 assert(lower <= last);
1719 if (lower == last) {
1720 merged_with[polyline_idx] = last;
1721 return last;
1722 }
1723 last = lower;
1724 }
1725 assert(false);
1726 return std::numeric_limits<size_t>::max();
1727 };
1728
1729 const double line_half_width = 0.5 * scale_(spacing);
1730 // Two ends whose anchors would meet are joined instead, with about as much wall.
1731 const double join_length = anchor_length > SCALED_EPSILON ? std::max(anchor_length_max, 2. * (anchor_length + line_half_width)) : anchor_length_max;
1732
1733#if 0
1734 // Connection from end of one infill line to the start of another infill line.
1735 //const double length_max = scale_(spacing);
1736// const auto length_max = double(scale_((2. / params.density) * spacing));
1737 const auto length_max = double(scale_((1000. / params.density) * spacing));
1738 struct ConnectionCost {
1739 ConnectionCost(size_t idx_first, double cost, bool reversed) : idx_first(idx_first), cost(cost), reversed(reversed) {}
1740 size_t idx_first;
1741 double cost;
1742 bool reversed;
1743 };
1744 std::vector<ConnectionCost> connections_sorted;
1745 connections_sorted.reserve(infill_ordered.size() * 2 - 2);
1746 for (size_t idx_chain = 1; idx_chain < infill_ordered.size(); ++ idx_chain) {
1747 const ContourIntersectionPoint *cp1 = &graph.map_infill_end_point_to_boundary[(idx_chain - 1) * 2 + 1];
1748 const ContourIntersectionPoint *cp2 = &graph.map_infill_end_point_to_boundary[idx_chain * 2];
1749 if (cp1->contour_idx != boundary_idx_unconnected && cp1->contour_idx == cp2->contour_idx) {
1750 // End points on the same contour. Try to connect them.
1751 std::pair<double, double> len = path_lengths_along_contour(cp1, cp2, graph.boundary_params[cp1->contour_idx].back());
1752 if (len.first < length_max)
1753 connections_sorted.emplace_back(idx_chain - 1, len.first, false);
1754 if (len.second < length_max)
1755 connections_sorted.emplace_back(idx_chain - 1, len.second, true);
1756 }
1757 }
1758 std::sort(connections_sorted.begin(), connections_sorted.end(), [](const ConnectionCost& l, const ConnectionCost& r) { return l.cost < r.cost; });
1759
1760 for (ConnectionCost &connection_cost : connections_sorted) {
1761 ContourIntersectionPoint *cp1 = &graph.map_infill_end_point_to_boundary[connection_cost.idx_first * 2 + 1];
1762 ContourIntersectionPoint *cp2 = &graph.map_infill_end_point_to_boundary[(connection_cost.idx_first + 1) * 2];
1763 assert(cp1 != cp2);
1764 assert(cp1->contour_idx == cp2->contour_idx && cp1->contour_idx != boundary_idx_unconnected);
1765 if (cp1->consumed || cp2->consumed)
1766 continue;
1767 const double length = connection_cost.cost;
1768 bool could_connect;
1769 {
1770 // cp1, cp2 sorted CCW.
1771 ContourIntersectionPoint *cp_low = connection_cost.reversed ? cp2 : cp1;
1772 ContourIntersectionPoint *cp_high = connection_cost.reversed ? cp1 : cp2;
1773 assert(std::abs(length - closed_contour_distance_ccw(cp_low->param, cp_high->param, graph.boundary_params[cp1->contour_idx].back())) < SCALED_EPSILON);
1774 could_connect = ! cp_low->next_trimmed && ! cp_high->prev_trimmed;
1775 if (could_connect && cp_low->next_on_contour != cp_high) {
1776 // Other end of cp1, may or may not be on the same contour as cp1.
1777 const ContourIntersectionPoint *cp1prev = cp1 - 1;
1778 // Other end of cp2, may or may not be on the same contour as cp2.
1779 const ContourIntersectionPoint *cp2next = cp2 + 1;
1780 for (auto *cp = cp_low->next_on_contour; cp != cp_high; cp = cp->next_on_contour)
1781 if (cp->consumed || cp == cp1prev || cp == cp2next || cp->prev_trimmed || cp->next_trimmed) {
1782 could_connect = false;
1783 break;
1784 }
1785 }
1786 }
1787 // Indices of the polylines to be connected by a perimeter segment.
1788 size_t idx_first = connection_cost.idx_first;
1789 size_t idx_second = idx_first + 1;
1790 idx_first = get_and_update_merged_with(idx_first);
1791 assert(idx_first < idx_second);
1792 assert(idx_second == merged_with[idx_second]);
1793 if (could_connect && length < anchor_length_max) {
1794 // Take the complete contour.
1795 // Connect the two polygons using the boundary contour.
1796 take(infill_ordered[idx_first], infill_ordered[idx_second], graph.boundary[cp1->contour_idx], cp1, cp2, connection_cost.reversed);
1797 // Mark the second polygon as merged with the first one.
1798 merged_with[idx_second] = merged_with[idx_first];
1799 infill_ordered[idx_second].points.clear();
1800 } else {
1801 // Try to connect cp1 resp. cp2 with a piece of perimeter line.
1802 take_limited(infill_ordered[idx_first], graph.boundary[cp1->contour_idx], graph.boundary_params[cp1->contour_idx], cp1, cp2, connection_cost.reversed, anchor_length, line_half_width);
1803 take_limited(infill_ordered[idx_second], graph.boundary[cp1->contour_idx], graph.boundary_params[cp1->contour_idx], cp2, cp1, ! connection_cost.reversed, anchor_length, line_half_width);
1804 }
1805 }
1806#endif
1807
1808 // Line ends not yet joined to another line along the contour.
1809 std::vector<char> open_end(graph.map_infill_end_point_to_boundary.size(), 1);
1810 auto end_index = [&graph](const ContourIntersectionPoint *cp) { return size_t(cp - graph.map_infill_end_point_to_boundary.data()); };
1811
1812 struct Arc {
1813 ContourIntersectionPoint *intersection;
1814 double arc_length;
1815 };
1816 std::vector<Arc> arches;
1817 if (!params.dont_sort) {
1818 arches.reserve(graph.map_infill_end_point_to_boundary.size());
1819 for (ContourIntersectionPoint& cp : graph.map_infill_end_point_to_boundary)
1820 if (cp.contour_idx != boundary_idx_unconnected && cp.next_on_contour != &cp && cp.could_connect_next())
1821 arches.push_back({ &cp, path_length_along_contour_ccw(&cp, cp.next_on_contour, graph.boundary_params[cp.contour_idx].back()) });
1822 std::sort(arches.begin(), arches.end(), [](const auto& l, const auto& r) { return l.arc_length < r.arc_length; });
1823
1824 // Lines the arcs would join in this order.
1825 auto count_joins = [&](const std::vector<Arc> &order) {
1826 std::vector<char> consumed(graph.map_infill_end_point_to_boundary.size());
1827 for (size_t i = 0; i < consumed.size(); ++ i)
1828 consumed[i] = graph.map_infill_end_point_to_boundary[i].consumed;
1829 std::vector<size_t> parent(infill_ordered.size());
1830 std::iota(parent.begin(), parent.end(), 0);
1831 auto find = [&parent](size_t i) {
1832 while (parent[i] != i)
1833 i = parent[i] = parent[parent[i]];
1834 return i;
1835 };
1836 size_t joins = 0;
1837 for (const Arc &arc : order) {
1838 const size_t end1 = end_index(arc.intersection), end2 = end_index(arc.intersection->next_on_contour);
1839 if (consumed[end1] || consumed[end2] || (params.multiline > 1 && arc.arc_length < scale_(spacing) * params.multiline))
1840 continue;
1841 const size_t polyline1 = find(end1 / 2), polyline2 = find(end2 / 2);
1842 if (polyline1 == polyline2)
1843 continue;
1844 if (arc.arc_length < join_length) {
1845 parent[polyline2] = polyline1;
1846 ++ joins;
1847 } else if (anchor_length <= SCALED_EPSILON)
1848 continue;
1849 consumed[end1] = consumed[end2] = 1;
1850 }
1851 // The last pass joins the open ends next to each other, also those of a multiline group.
1852 for (size_t end = 0; end < consumed.size(); ++ end) {
1853 const ContourIntersectionPoint &cp = graph.map_infill_end_point_to_boundary[end];
1854 if (consumed[end] || cp.contour_idx == boundary_idx_unconnected)
1855 continue;
1856 const double length = graph.boundary_params[cp.contour_idx].back();
1857 auto open = [&](const ContourIntersectionPoint *other, bool trimmed) {
1858 return other != &cp && ! consumed[end_index(other)] && ! trimmed;
1859 };
1860 const double lprev = open(cp.prev_on_contour, cp.prev_trimmed || cp.prev_on_contour->next_trimmed) ?
1861 path_length_along_contour_ccw(cp.prev_on_contour, &cp, length) : std::numeric_limits<double>::max();
1862 const double lnext = open(cp.next_on_contour, cp.next_trimmed || cp.next_on_contour->prev_trimmed) ?
1863 path_length_along_contour_ccw(&cp, cp.next_on_contour, length) : std::numeric_limits<double>::max();
1864 consumed[end] = anchor_length > SCALED_EPSILON;
1865 for (const double l : { std::min(lprev, lnext), std::max(lprev, lnext) }) {
1866 if (l > join_length)
1867 break;
1868 const size_t other = end_index(l == lprev ? cp.prev_on_contour : cp.next_on_contour);
1869 const size_t polyline1 = find(end / 2), polyline2 = find(other / 2);
1870 if (polyline1 == polyline2)
1871 continue;
1872 parent[polyline2] = polyline1;
1873 consumed[end] = consumed[other] = 1;
1874 ++ joins;
1875 break;
1876 }
1877 }
1878 return joins;
1879 };
1880 // Equal arcs taken along the contour pair a wall in one phase; keep the order that joins the most lines.
1881 size_t best_joins = count_joins(arches);
1882 const double bucket = 0.5 * scale_(spacing);
1883 for (const bool backwards : { false, true }) {
1884 std::vector<Arc> along_contour = arches;
1885 std::sort(along_contour.begin(), along_contour.end(), [bucket, backwards](const Arc &l, const Arc &r) {
1886 const long long bucket_l = std::llround(l.arc_length / bucket), bucket_r = std::llround(r.arc_length / bucket);
1887 if (bucket_l != bucket_r)
1888 return bucket_l < bucket_r;
1889 if (l.intersection->contour_idx != r.intersection->contour_idx)
1890 return l.intersection->contour_idx < r.intersection->contour_idx;
1891 return backwards ? l.intersection->param > r.intersection->param : l.intersection->param < r.intersection->param;
1892 });
1893 if (const size_t joins = count_joins(along_contour); joins > best_joins) {
1894 best_joins = joins;
1895 arches = std::move(along_contour);
1896 }
1897 }
1898 }
1899
1900 //FIXME improve the Traveling Salesman problem with 2-opt and 3-opt local optimization.
1901 for (Arc &arc : arches)
1902 if (! arc.intersection->consumed && ! arc.intersection->next_on_contour->consumed) {
1903 // Indices of the polylines to be connected by a perimeter segment.
1904 ContourIntersectionPoint *cp1 = arc.intersection;
1905 ContourIntersectionPoint *cp2 = arc.intersection->next_on_contour;
1906 size_t polyline_idx1 = get_and_update_merged_with(((cp1 - graph.map_infill_end_point_to_boundary.data()) / 2));
1907 size_t polyline_idx2 = get_and_update_merged_with(((cp2 - graph.map_infill_end_point_to_boundary.data()) / 2));
1908 const Points &contour = graph.boundary[cp1->contour_idx];
1909
1910 // Orca: If multiline infill is requested, skip connections that are too short.
1911 if (params.multiline > 1 && arc.arc_length < scale_(spacing) * params.multiline) {
1912 continue;
1913 }
1914
1915 const std::vector<double> &contour_params = graph.boundary_params[cp1->contour_idx];
1916 if (polyline_idx1 != polyline_idx2) {
1917 Polyline &polyline1 = infill_ordered[polyline_idx1];
1918 Polyline &polyline2 = infill_ordered[polyline_idx2];
1919 if (arc.arc_length < join_length) {
1920 // Not closing a loop, connecting the lines.
1921 assert(contour[cp1->point_idx] == polyline1.points.front() || contour[cp1->point_idx] == polyline1.points.back());
1922 if (contour[cp1->point_idx] == polyline1.points.front())
1923 polyline1.reverse();
1924 assert(contour[cp2->point_idx] == polyline2.points.front() || contour[cp2->point_idx] == polyline2.points.back());
1925 if (contour[cp2->point_idx] == polyline2.points.back())
1926 polyline2.reverse();
1927 take(polyline1, polyline2, contour, cp1, cp2, false);
1928 open_end[end_index(cp1)] = open_end[end_index(cp2)] = 0;
1929 // Mark the second polygon as merged with the first one.
1930 if (polyline_idx2 < polyline_idx1) {
1931 polyline2 = std::move(polyline1);
1932 polyline1.points.clear();
1933 merged_with[polyline_idx1] = merged_with[polyline_idx2];
1934 } else {
1935 polyline2.points.clear();
1936 merged_with[polyline_idx2] = merged_with[polyline_idx1];
1937 }
1938 } else if (anchor_length > SCALED_EPSILON) {
1939 // Move along the perimeter, but don't take the whole arc.
1940 take_limited(polyline1, contour, contour_params, cp1, cp2, false, anchor_length, line_half_width);
1941 take_limited(polyline2, contour, contour_params, cp2, cp1, true, anchor_length, line_half_width);
1942 }
1943 }
1944 }
1945
1946 // Distance along the contour to the nearest open end of another polyline, within 64 ends.
1947 auto distance_to_open_end = [&](const ContourIntersectionPoint &from, size_t polyline_idx, bool backwards) {
1948 const double length = graph.boundary_params[from.contour_idx].back();
1949 double distance = 0.;
1950 const ContourIntersectionPoint *cp = &from;
1951 for (size_t step = 0; step < 64; ++ step) {
1952 const ContourIntersectionPoint *other = backwards ? cp->prev_on_contour : cp->next_on_contour;
1953 if (other == nullptr || other == &from)
1954 break;
1955 distance += backwards ? closed_contour_distance_cw(cp->param, other->param, length) : closed_contour_distance_ccw(cp->param, other->param, length);
1956 if (open_end[end_index(other)] && get_and_update_merged_with(end_index(other) / 2) != polyline_idx)
1957 return distance;
1958 cp = other;
1959 }
1960 return std::numeric_limits<double>::max();
1961 };
1962
1963 // Connect the remaining open infill lines to the perimeter lines if possible.
1964 for (ContourIntersectionPoint &contour_point : graph.map_infill_end_point_to_boundary)
1965 if (! contour_point.consumed && contour_point.contour_idx != boundary_idx_unconnected) {
1966 const Points &contour = graph.boundary[contour_point.contour_idx];
1967 const std::vector<double> &contour_params = graph.boundary_params[contour_point.contour_idx];
1968
1969 double lprev = contour_point.could_connect_prev() ?
1970 path_length_along_contour_ccw(contour_point.prev_on_contour, &contour_point, contour_params.back()) :
1971 std::numeric_limits<double>::max();
1972 double lnext = contour_point.could_connect_next() ?
1973 path_length_along_contour_ccw(&contour_point, contour_point.next_on_contour, contour_params.back()) :
1974 std::numeric_limits<double>::max();
1975 size_t polyline_idx = get_and_update_merged_with(((&contour_point - graph.map_infill_end_point_to_boundary.data()) / 2));
1976 Polyline &polyline = infill_ordered[polyline_idx];
1977 assert(! polyline.empty());
1978 assert(contour[contour_point.point_idx] == polyline.points.front() || contour[contour_point.point_idx] == polyline.points.back());
1979 bool connected = false;
1980 for (double l : { std::min(lprev, lnext), std::max(lprev, lnext) }) {
1981 if (l == std::numeric_limits<double>::max() || l > join_length)
1982 break;
1983 // Take the complete contour.
1984 bool reversed = l == lprev;
1985 ContourIntersectionPoint *cp2 = reversed ? contour_point.prev_on_contour : contour_point.next_on_contour;
1986 // Identify which end of the polyline touches the boundary.
1987 size_t polyline_idx2 = get_and_update_merged_with(((cp2 - graph.map_infill_end_point_to_boundary.data()) / 2));
1988 if (polyline_idx == polyline_idx2)
1989 // Try the other side.
1990 continue;
1991 // Not closing a loop.
1992 if (contour[contour_point.point_idx] == polyline.points.front())
1993 polyline.reverse();
1994 Polyline &polyline2 = infill_ordered[polyline_idx2];
1995 assert(! polyline.empty());
1996 assert(contour[cp2->point_idx] == polyline2.points.front() || contour[cp2->point_idx] == polyline2.points.back());
1997 if (contour[cp2->point_idx] == polyline2.points.back())
1998 polyline2.reverse();
1999 take(polyline, polyline2, contour, &contour_point, cp2, reversed);
2000 open_end[end_index(&contour_point)] = open_end[end_index(cp2)] = 0;
2001 if (polyline_idx < polyline_idx2) {
2002 // Mark the second polyline as merged with the first one.
2003 merged_with[polyline_idx2] = polyline_idx;
2004 polyline2.points.clear();
2005 } else {
2006 // Mark the first polyline as merged with the second one.
2007 merged_with[polyline_idx] = polyline_idx2;
2008 polyline2 = std::move(polyline);
2009 polyline.points.clear();
2010 }
2011 connected = true;
2012 break;
2013 }
2014 if (! connected && anchor_length > SCALED_EPSILON) {
2015 // Hook toward the nearest open end of another polyline, where the next path likely starts.
2016 const double free_prev = contour_point.contour_not_taken_length_prev;
2017 const double free_next = contour_point.contour_not_taken_length_next;
2018 const double to_prev = distance_to_open_end(contour_point, polyline_idx, true);
2019 const double to_next = distance_to_open_end(contour_point, polyline_idx, false);
2020 bool backwards = free_prev > free_next;
2021 if (to_prev < to_next && free_prev > SCALED_EPSILON)
2022 backwards = true;
2023 else if (to_next < to_prev && free_next > SCALED_EPSILON)
2024 backwards = false;
2025 // Orca: with multiline, a hook toward a copy stops short of it; the copy takes half a width over the sine of its wall angle.
2026 double length = anchor_length;
2027 if (const ContourIntersectionPoint *other = backwards ? contour_point.prev_on_contour : contour_point.next_on_contour;
2028 params.multiline > 1 && other != &contour_point) {
2029 const Point &end = contour[contour_point.point_idx];
2030 Vec2d dir = Vec2d::Zero();
2031 for (size_t i = 1; i < polyline.size() && dir.squaredNorm() < sqr(2. * scale_(spacing) * params.multiline); ++ i)
2032 dir = (end - polyline.points[polyline.points.front() == end ? i : polyline.size() - 1 - i]).cast<double>();
2033 const Vec2d to_copy = (contour[other->point_idx] - end).cast<double>();
2034 const double across = dir.squaredNorm() > 0. ? std::abs(cross2(dir.normalized(), to_copy)) : 0.;
2035 if (across > SCALED_EPSILON && across < scale_(spacing) * params.multiline) {
2036 const double gap = backwards ? path_length_along_contour_ccw(other, &contour_point, contour_params.back()) :
2037 path_length_along_contour_ccw(&contour_point, other, contour_params.back());
2038 length = std::min(length, gap - line_half_width * (1. + to_copy.norm() / across));
2039 }
2040 }
2041 if ((backwards ? free_prev : free_next) > SCALED_EPSILON)
2042 take_limited(polyline, contour, contour_params, &contour_point, backwards ? contour_point.prev_on_contour : contour_point.next_on_contour,
2043 backwards, std::max(0., length), line_half_width);
2044 }
2045 }
2046
2047 polylines_out.reserve(polylines_out.size() + std::count_if(infill_ordered.begin(), infill_ordered.end(), [](const Polyline &pl) { return ! pl.empty(); }));
2048 for (Polyline &pl : infill_ordered)
2049 if (! pl.empty())
2050 polylines_out.emplace_back(std::move(pl));
2051}
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841
const Point & contour_point(const VD::cell_type &cell, const Line &line)
Definition VoronoiOffset.hpp:21
static double closed_contour_distance_ccw(double param1, double param2, double contour_length)
Definition FillBase.cpp:485
double length(const Points &pts)
Definition MultiPoint.hpp:181
int32_t cross2(const Eigen::MatrixBase< Eigen::Matrix< int32_t, 2, 1, Options > > &v1, const Eigen::MatrixBase< Eigen::Matrix< int32_t, 2, 1, Options > > &v2)=delete
static double closed_contour_distance_cw(double param1, double param2, double contour_length)
Definition FillBase.cpp:496
std::pair< double, double > path_lengths_along_contour(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, double contour_length)
Definition FillBase.cpp:512
constexpr T sqr(T x)
Definition libslic3r.h:301
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299
RaycastManager::TrItems::iterator find(RaycastManager::TrItems &items, const RaycastManager::TrKey &key)
Definition RaycastManager.cpp:298
void step(Coord &crd, const Dir d, const long n=1)
Definition MarchingSquares.hpp:213

References Slic3r::FillParams::anchor_length, Slic3r::FillParams::anchor_length_max, Slic3r::append(), Slic3r::BoundaryInfillGraph::boundary, Slic3r::boundary_idx_unconnected, Slic3r::BoundaryInfillGraph::boundary_params, Slic3r::cast(), Slic3r::closed_contour_distance_ccw(), Slic3r::closed_contour_distance_cw(), Slic3r::ContourIntersectionPoint::consumed, Slic3r::contour(), Slic3r::ContourIntersectionPoint::contour_idx, Slic3r::ContourIntersectionPoint::could_connect_next(), Slic3r::create_boundary_infill_graph(), Slic3r::cross2(), Slic3r::FillParams::density, Slic3r::FillParams::dont_sort, Slic3r::MultiPoint::empty(), Slic3r::intersection(), Slic3r::length(), Slic3r::BoundaryInfillGraph::map_infill_end_point_to_boundary, Slic3r::FillParams::multiline, Slic3r::ContourIntersectionPoint::next_on_contour, Slic3r::ContourIntersectionPoint::next_trimmed, Slic3r::ContourIntersectionPoint::param, Slic3r::path_length_along_contour_ccw(), Slic3r::path_lengths_along_contour(), Slic3r::ContourIntersectionPoint::point_idx, Slic3r::MultiPoint::points, Slic3r::ContourIntersectionPoint::prev_on_contour, Slic3r::ContourIntersectionPoint::prev_trimmed, Slic3r::Polyline::reverse(), scale_, SCALED_EPSILON, Slic3r::MultiPoint::size(), spacing, Slic3r::sqr(), Slic3r::take(), and Slic3r::take_limited().

Here is the call graph for this function:

◆ extended_object_bounding_box()

BoundingBox Slic3r::Fill::extended_object_bounding_box ( ) const
inherited
1681{
1682 // Orca: Extend about the box center, which separated infills move off the origin.
1683 const Point c = this->bounding_box.center();
1684 BoundingBox out = this->bounding_box;
1685 out.translate(-c.x(), -c.y());
1686 out.merge(Point(out.min.y(), out.min.x()));
1687 out.merge(Point(out.max.y(), out.max.x()));
1688
1689 // The bounding box is scaled by sqrt(2.) to ensure that the bounding box
1690 // covers any possible rotations.
1691 out = out.scaled(sqrt(2.));
1692 out.translate(c.x(), c.y());
1693 return out;
1694}

References bounding_box, Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::merge(), Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::BoundingBox::scaled(), and Slic3r::BoundingBoxBase< PointType, APointsType >::translate().

Referenced by Slic3r::FillPlanePath::_fill_surface_single(), Slic3r::FillRectilinear::fill_surface_by_lines(), and Slic3r::FillRectilinear::fill_surface_trapezoidal().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fill_surface()

Polylines Slic3r::Fill::fill_surface ( const Surface * surface,
const FillParams & params )
virtualinherited

Reimplemented in Slic3r::FillCubic, Slic3r::FillGrid, Slic3r::FillLateralHoneycomb, Slic3r::FillLateralLattice, Slic3r::FillMonotonic, Slic3r::FillMonotonicLine, Slic3r::FillMonotonicLines, Slic3r::FillQuarterCubic, Slic3r::FillRectilinear, Slic3r::FillStars, Slic3r::FillSupportBase, and Slic3r::FillTriangles.

132{
133 // Perform offset.
134 Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing)));
135 // Orca: Separated infills move the box center onto each body; origin-aligned patterns follow it.
136 const Point shift = this->aligned_to_origin() && ! empty(this->bounding_box) ? this->bounding_box.center() : Point::Zero();
137 translate(expp, -shift);
138 // Create the infills for each of the regions.
139 Polylines polylines_out;
140 for (size_t i = 0; i < expp.size(); ++ i)
142 params,
143 surface->thickness_layers,
144 _infill_direction(surface),
145 std::move(expp[i]),
146 polylines_out);
147 for (Polyline &pl : polylines_out)
148 pl.translate(shift);
149 return polylines_out;
150}
virtual std::pair< float, Point > _infill_direction(const Surface *surface) const
Definition FillBase.cpp:386
virtual void _fill_surface_single(const FillParams &, unsigned int, const std::pair< float, Point > &, ExPolygon, Polylines &)
Definition FillBase.hpp:230
virtual bool aligned_to_origin() const
Definition FillBase.hpp:204
coordf_t overlap
Definition FillBase.hpp:149
void translate(ExPolygonsWithIds &e, const Point &p)
Definition Emboss.cpp:1368
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:605

References _fill_surface_single(), _infill_direction(), aligned_to_origin(), bounding_box, Slic3r::empty(), Slic3r::Surface::expolygon, Slic3r::offset_ex(), overlap, scale_, spacing, Slic3r::Surface::thickness_layers, and Slic3r::translate().

Referenced by Slic3r::fill_expolygon_generate_paths(), Slic3r::fill_expolygon_generate_paths(), and fill_surface_extrusion().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fill_surface_arachne()

ThickPolylines Slic3r::Fill::fill_surface_arachne ( const Surface * surface,
const FillParams & params )
virtualinherited
153{
154 // Perform offset.
155 Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing)));
156 // Create the infills for each of the regions.
157 ThickPolylines thick_polylines_out;
158 for (ExPolygon& expoly : expp)
159 _fill_surface_single(params, surface->thickness_layers, _infill_direction(surface), std::move(expoly), thick_polylines_out);
160 return thick_polylines_out;
161}

References _fill_surface_single(), _infill_direction(), Slic3r::Surface::expolygon, Slic3r::offset_ex(), overlap, scale_, spacing, and Slic3r::Surface::thickness_layers.

Referenced by fill_surface_extrusion().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fill_surface_extrusion()

void Slic3r::Fill::fill_surface_extrusion ( const Surface * surface,
const FillParams & params,
ExtrusionEntitiesPtr & out )
virtualinherited

Reimplemented in Slic3r::FillConcentricInternal, and Slic3r::FillLockedZag.

165{
166 Polylines polylines;
167 ThickPolylines thick_polylines;
168 try {
169 if (params.use_arachne)
170 thick_polylines = this->fill_surface_arachne(surface, params);
171 else
172 polylines = this->fill_surface(surface, params);
173 }
174 catch (InfillFailedException&) {}
175
176 if (!polylines.empty() || !thick_polylines.empty()) {
177 // calculate actual flow from spacing (which might have been adjusted by the infill
178 // pattern generator)
179 double flow_mm3_per_mm = params.flow.mm3_per_mm();
180 double flow_width = params.flow.width();
181 if (params.using_internal_flow) {
182 // if we used the internal flow we're not doing a solid infill
183 // so we can safely ignore the slight variation that might have
184 // been applied to f->spacing
185 }
186 else {
187 Flow new_flow = params.flow.with_spacing(this->spacing);
188 flow_mm3_per_mm = new_flow.mm3_per_mm();
189 flow_width = new_flow.width();
190 }
191 // Save into layer.
192 ExtrusionEntityCollection* eec = nullptr;
193 out.push_back(eec = new ExtrusionEntityCollection());
194 // Only concentric fills are not sorted.
195 eec->no_sort = this->no_sort();
196 // ORCA: special flag for flow rate calibration
197 auto is_flow_calib = params.extrusion_role == erTopSolidInfill && this->print_object_config->has("calib_flowrate_topinfill_special_order") &&
198 this->print_object_config->option("calib_flowrate_topinfill_special_order")->getBool();
199 // Orca: a forced surface fill order must survive the G-code path planner, which would
200 // otherwise re-chain and possibly reverse the paths. The same applies to the flow rate
201 // calibration's special toolpath order.
202 const bool keep_fill_order = params.fill_order != SurfaceFillOrder::Default;
203 if (is_flow_calib || keep_fill_order) {
204 eec->no_sort = true;
205 }
206 size_t idx = eec->entities.size();
207 if (params.use_arachne) {
208 Flow new_flow = params.flow.with_spacing(float(this->spacing));
209 variable_width(thick_polylines, params.extrusion_role, new_flow, eec->entities);
210 thick_polylines.clear();
211 }
212 else {
213 // Orca: sparse infill lines whose ends are next to each other print as one path, without a travel between them.
214 if (params.extrusion_role == erInternalInfill && ! eec->no_sort)
215 join_close_ends(polylines, scale_(2. * this->spacing), params.can_reverse);
217 eec->entities, std::move(polylines),
218 params.extrusion_role,
219 flow_mm3_per_mm, float(flow_width), params.flow.height());
220 }
221 if (!params.can_reverse || is_flow_calib || keep_fill_order) {
222 for (size_t i = idx; i < eec->entities.size(); i++)
223 eec->entities[i]->set_reverse();
224 }
225
226 // Orca: run gap fill
227 this->_create_gap_fill(surface, params, eec);
228 }
229}
virtual ThickPolylines fill_surface_arachne(const Surface *surface, const FillParams &params)
Definition FillBase.cpp:152
virtual bool no_sort() const
Definition FillBase.hpp:196
virtual Polylines fill_surface(const Surface *surface, const FillParams &params)
Definition FillBase.cpp:131
void _create_gap_fill(const Surface *surface, const FillParams &params, ExtrusionEntityCollection *out)
Definition FillBase.cpp:306
void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height, bool can_reverse=true)
Definition ExtrusionEntity.hpp:608
@ erTopSolidInfill
Definition ExtrusionEntity.hpp:33
@ erInternalInfill
Definition ExtrusionEntity.hpp:31
@ Default
Definition PrintConfig.hpp:283
void join_close_ends(Polylines &polylines, double max_gap, bool can_reverse)
Definition FillBase.cpp:3001

References _create_gap_fill(), Slic3r::FillParams::can_reverse, Slic3r::Default, Slic3r::ExtrusionEntityCollection::entities, Slic3r::erInternalInfill, Slic3r::erTopSolidInfill, Slic3r::extrusion_entities_append_paths(), Slic3r::FillParams::extrusion_role, Slic3r::FillParams::fill_order, fill_surface(), fill_surface_arachne(), Slic3r::FillParams::flow, Slic3r::Flow::height(), Slic3r::join_close_ends(), Slic3r::Flow::mm3_per_mm(), Slic3r::ExtrusionEntityCollection::no_sort, no_sort(), print_object_config, scale_, spacing, Slic3r::FillParams::use_arachne, Slic3r::FillParams::using_internal_flow, Slic3r::variable_width(), Slic3r::Flow::width(), and Slic3r::Flow::with_spacing().

Here is the call graph for this function:

◆ has_consistent_pattern()

virtual bool Slic3r::Fill::has_consistent_pattern ( ) const
inlinevirtualinherited

Reimplemented in Slic3r::FillCrossZag, Slic3r::FillLockedZag, and Slic3r::FillZigZag.

201{ return false; }

Referenced by Slic3r::FillRectilinear::fill_surface_by_lines().

Here is the caller graph for this function:

◆ is_self_crossing()

bool Slic3r::FillSpiralInset::is_self_crossing ( )
inlineoverridevirtual

Implements Slic3r::Fill.

17{ return false; }

◆ new_from_type() [1/2]

Fill * Slic3r::Fill::new_from_type ( const InfillPattern type)
staticinherited
66{
67 switch (type) {
68 case ipConcentric: return new FillConcentric();
69 case ipSpiralInset: return new FillSpiralInset();
70 case ipHoneycomb: return new FillHoneycomb();
71 case ipLateralHoneycomb: return new FillLateralHoneycomb();
72 case ip3DHoneycomb: return new Fill3DHoneycomb();
73 case ipGyroid: return new FillGyroid();
74 case ipTpmsD: return new FillTpmsD();//from creality print
75 case ipTpmsFK: return new FillTpmsFK();
76 case ipRectilinear: return new FillRectilinear();
77 case ipAlignedRectilinear: return new FillAlignedRectilinear();
78 case ipCrossHatch: return new FillCrossHatch();
79 case ipMonotonic: return new FillMonotonic();
80 case ipLine: return new FillLine();
81 case ipGrid: return new FillGrid();
82 case ipLateralLattice: return new FillLateralLattice();
83 case ipTriangles: return new FillTriangles();
84 case ipStars: return new FillStars();
85 case ipCubic: return new FillCubic();
86 case ipQuarterCubic: return new FillQuarterCubic();
87 case ipArchimedeanChords: return new FillArchimedeanChords();
88 case ipHilbertCurve: return new FillHilbertCurve();
89 case ipOctagramSpiral: return new FillOctagramSpiral();
90 case ipAdaptiveCubic: return new FillAdaptive::Filler();
91 case ipSupportCubic: return new FillAdaptive::Filler();
92 case ipSupportBase: return new FillSupportBase(); // simply line fill
93 case ipLightning: return new FillLightning::Filler();
94 // BBS: for internal solid infill only
95 case ipConcentricInternal: return new FillConcentricInternal();
96 // BBS: for bottom and top surface only
97 // Orca: Replace BBS implementation with Prusa implementation
98 case ipMonotonicLine: return new FillMonotonicLines();
99 case ipZigZag: return new FillZigZag();
100 case ipCrossZag: return new FillCrossZag();
101 case ipLockedZag: return new FillLockedZag();
102 default: throw Slic3r::InvalidArgument("unknown type");
103 }
104}
@ ipStars
Definition PrintConfig.hpp:130
@ ipHilbertCurve
Definition PrintConfig.hpp:134
@ ipGrid
Definition PrintConfig.hpp:129
@ ipQuarterCubic
Definition PrintConfig.hpp:131
@ ipArchimedeanChords
Definition PrintConfig.hpp:134
@ ipConcentric
Definition PrintConfig.hpp:134
@ ipZigZag
Definition PrintConfig.hpp:128
@ ipTpmsD
Definition PrintConfig.hpp:133
@ ipLateralLattice
Definition PrintConfig.hpp:132
@ ipAlignedRectilinear
Definition PrintConfig.hpp:128
@ ipMonotonic
Definition PrintConfig.hpp:127
@ ip3DHoneycomb
Definition PrintConfig.hpp:132
@ ipAdaptiveCubic
Definition PrintConfig.hpp:131
@ ipCrossZag
Definition PrintConfig.hpp:128
@ ipMonotonicLine
Definition PrintConfig.hpp:127
@ ipLine
Definition PrintConfig.hpp:129
@ ipHoneycomb
Definition PrintConfig.hpp:132
@ ipCubic
Definition PrintConfig.hpp:131
@ ipOctagramSpiral
Definition PrintConfig.hpp:134
@ ipTriangles
Definition PrintConfig.hpp:130
@ ipSupportCubic
Definition PrintConfig.hpp:131
@ ipTpmsFK
Definition PrintConfig.hpp:133
@ ipRectilinear
Definition PrintConfig.hpp:128
@ ipConcentricInternal
Definition PrintConfig.hpp:135
@ ipCrossHatch
Definition PrintConfig.hpp:133
@ ipGyroid
Definition PrintConfig.hpp:133
@ ipSupportBase
Definition PrintConfig.hpp:135
@ ipLockedZag
Definition PrintConfig.hpp:128
@ ipLateralHoneycomb
Definition PrintConfig.hpp:132
@ ipLightning
Definition PrintConfig.hpp:131
@ ipSpiralInset
Definition PrintConfig.hpp:134

References Fill(), Slic3r::ip3DHoneycomb, Slic3r::ipAdaptiveCubic, Slic3r::ipAlignedRectilinear, Slic3r::ipArchimedeanChords, Slic3r::ipConcentric, Slic3r::ipConcentricInternal, Slic3r::ipCrossHatch, Slic3r::ipCrossZag, Slic3r::ipCubic, Slic3r::ipGrid, Slic3r::ipGyroid, Slic3r::ipHilbertCurve, Slic3r::ipHoneycomb, Slic3r::ipLateralHoneycomb, Slic3r::ipLateralLattice, Slic3r::ipLightning, Slic3r::ipLine, Slic3r::ipLockedZag, Slic3r::ipMonotonic, Slic3r::ipMonotonicLine, Slic3r::ipOctagramSpiral, Slic3r::ipQuarterCubic, Slic3r::ipRectilinear, Slic3r::ipSpiralInset, Slic3r::ipStars, Slic3r::ipSupportBase, Slic3r::ipSupportCubic, Slic3r::ipTpmsD, Slic3r::ipTpmsFK, Slic3r::ipTriangles, and Slic3r::ipZigZag.

Referenced by Slic3r::Layer::generate_sparse_infill_polylines_for_anchoring(), Slic3r::WipeTower2::generate_support_cone_wall(), Slic3r::TreeSupport3D::generate_support_infill_lines(), Slic3r::generate_support_toolpaths(), Slic3r::TreeSupport::generate_toolpaths(), Slic3r::Layer::make_fills(), Slic3r::Layer::make_ironing(), new_from_type(), Slic3r::spreadDotsArea(), and use_bridge_flow().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ new_from_type() [2/2]

Fill * Slic3r::Fill::new_from_type ( const std::string & type)
staticinherited
107{
109 t_config_enum_values::const_iterator it = enum_keys_map.find(type);
110 return (it == enum_keys_map.end()) ? nullptr : new_from_type(InfillPattern(it->second));
111}
static const t_config_enum_values & get_enum_values()
static Fill * new_from_type(const InfillPattern type)
Definition FillBase.cpp:65
InfillPattern
Definition PrintConfig.hpp:126
std::map< std::string, int > t_config_enum_values
Definition Config.hpp:2072

References Fill(), Slic3r::ConfigOptionEnum< T >::get_enum_values(), and new_from_type().

Here is the call graph for this function:

◆ no_sort()

bool Slic3r::FillSpiralInset::no_sort ( ) const
inlineoverrideprotectedvirtual

Reimplemented from Slic3r::Fill.

37{ return true; }

◆ set_bounding_box()

void Slic3r::Fill::set_bounding_box ( const Slic3r::BoundingBox & bbox)
inlineinherited
190{ bounding_box = bbox; }

References bounding_box.

◆ set_lock_region_param()

virtual void Slic3r::Fill::set_lock_region_param ( const LockRegionParam & lock_param)
inlinevirtualinherited

Reimplemented in Slic3r::FillLockedZag.

209{};

◆ use_bridge_flow() [1/2]

virtual bool Slic3r::Fill::use_bridge_flow ( ) const
inlinevirtualinherited

Reimplemented in Slic3r::Fill3DHoneycomb, Slic3r::FillGyroid, Slic3r::FillTpmsD, and Slic3r::FillTpmsFK.

193{ return false; }

◆ use_bridge_flow() [2/2]

bool Slic3r::Fill::use_bridge_flow ( const InfillPattern type)
staticinherited
118{
119 static std::vector<unsigned char> cached;
120 if (cached.empty()) {
121 cached.assign(size_t(ipCount), 0);
122 for (size_t i = 0; i < cached.size(); ++ i) {
123 auto *fill = Fill::new_from_type((InfillPattern)i);
124 cached[i] = fill->use_bridge_flow();
125 delete fill;
126 }
127 }
128 return cached[type] != 0;
129}
@ ipCount
Definition PrintConfig.hpp:136

References Slic3r::ipCount, and new_from_type().

Referenced by Slic3r::group_fills().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ adapt_fill_octree

FillAdaptive::Octree* Slic3r::Fill::adapt_fill_octree = nullptr
inherited

◆ adaptive_infill_field

◆ angle

◆ bounding_box

◆ dont_alternate_fill_direction

bool Slic3r::Fill::dont_alternate_fill_direction = false
inherited

Referenced by _infill_direction().

◆ fixed_angle

bool Slic3r::Fill::fixed_angle {false}
inherited
154{false};

Referenced by _infill_direction(), and _layer_angle().

◆ infill_anchor

float Slic3r::Fill::infill_anchor = 400
staticinherited

◆ infill_anchor_max

float Slic3r::Fill::infill_anchor_max = 20
staticinherited

◆ layer_id

◆ link_max_length

coord_t Slic3r::Fill::link_max_length
inherited

◆ loop_clipping

◆ no_overlap_expolygons

ExPolygons Slic3r::Fill::no_overlap_expolygons
inherited

◆ overlap

◆ print_config

◆ print_object_config

◆ spacing

◆ z


The documentation for this class was generated from the following files: