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

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

Inheritance diagram for Slic3r::FillMonotonicLine:
Collaboration diagram for Slic3r::FillMonotonicLine:

Public Member Functions

Fill * clone () const override
 ~FillMonotonicLine () override=default
Polylines fill_surface (const Surface *surface, const FillParams &params) override
bool no_sort () const override
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 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

bool fill_surface_by_lines (const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out)
bool fill_surface_by_multilines (const Surface *surface, FillParams params, const std::initializer_list< SweepParams > &sweep_params, Polylines &polylines_out)
bool fill_surface_trapezoidal (const Surface *surface, FillParams params, Polylines &polylines_out, int Pattern_type)
virtual void _fill_surface_single (const FillParams &, unsigned int, const std::pair< float, Point > &, ExPolygon, Polylines &)
virtual void _fill_surface_single (const FillParams &params, unsigned int thickness_layers, const std::pair< float, Point > &direction, ExPolygon expolygon, ThickPolylines &thick_polylines_out)
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

◆ ~FillMonotonicLine()

Slic3r::FillMonotonicLine::~FillMonotonicLine ( )
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]

virtual void Slic3r::Fill::_fill_surface_single ( const FillParams & ,
unsigned int ,
const std::pair< float, Point > & ,
ExPolygon ,
Polylines &  )
inlineprotectedvirtualinherited

Reimplemented in Slic3r::Fill3DHoneycomb, Slic3r::FillAdaptive::Filler, Slic3r::FillConcentric, Slic3r::FillCrossHatch, Slic3r::FillGyroid, Slic3r::FillHoneycomb, Slic3r::FillLightning::Filler, Slic3r::FillLine, Slic3r::FillPlanePath, Slic3r::FillSpiralInset, Slic3r::FillTpmsD, and Slic3r::FillTpmsFK.

235 {}

Referenced by fill_surface(), and fill_surface_arachne().

Here is the caller graph for this function:

◆ _fill_surface_single() [2/2]

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

Reimplemented in Slic3r::FillConcentric, and Slic3r::FillSpiralInset.

242 {}

◆ _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
BoundingBox bounding_box
Definition FillBase.hpp:162
float angle
Definition FillBase.hpp:151
bool fixed_angle
Definition FillBase.hpp:154
size_t layer_id
Definition FillBase.hpp:143
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
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}
coordf_t spacing
Definition FillBase.hpp:147
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
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:157

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::FillMonotonicLine::clone ( ) const
inlineoverridevirtual

Implements Slic3r::Fill.

70{ return new FillMonotonicLine(*this); }

◆ 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
#define scale_(val)
Definition libslic3r.h:106
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
float distance(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b)
Definition SpiralVase.cpp:19
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::FillMonotonicLine::fill_surface ( const Surface * surface,
const FillParams & params )
overridevirtual

Reimplemented from Slic3r::Fill.

3515{
3516 FillParams params2 = params;
3517 params2.monotonic = true;
3518 params2.anchor_length_max = 0.0f;
3519 Polylines polylines_out;
3520 if (! fill_surface_by_lines(surface, params2, 0.f, 0.f, polylines_out))
3521 BOOST_LOG_TRIVIAL(error) << "Failed to fill a region by MonotonicLine pattern";
3522 return polylines_out;
3523}
bool fill_surface_by_lines(const Surface *surface, const FillParams &params, float angleBase, float pattern_shift, Polylines &polylines_out)
Definition FillRectilinear.cpp:2753
std::vector< Polyline > Polylines
Definition Polyline.hpp:22

References Slic3r::FillParams::anchor_length_max, Slic3r::FillRectilinear::fill_surface_by_lines(), and Slic3r::FillParams::monotonic.

Here is the call 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}
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
coordf_t overlap
Definition FillBase.hpp:149
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(), 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_by_lines()

bool Slic3r::FillRectilinear::fill_surface_by_lines ( const Surface * surface,
const FillParams & params,
float angleBase,
float pattern_shift,
Polylines & polylines_out )
protectedinherited
2754{
2755 // At the end, only the new polylines will be rotated back.
2756 size_t n_polylines_out_initial = polylines_out.size();
2757
2758 // Shrink the input polygon a bit first to not push the infill lines out of the perimeters.
2759// const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
2760 const float INFILL_OVERLAP_OVER_SPACING = 0.45f;
2761 assert(INFILL_OVERLAP_OVER_SPACING > 0 && INFILL_OVERLAP_OVER_SPACING < 0.5f);
2762
2763 // Rotate polygons so that we can work with vertical lines here
2764 std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
2765 if (params.locked_zag)
2766 rotate_vector.first += float(M_PI/2.);
2767 rotate_vector.first += angleBase;
2768
2769 assert(params.density > 0.0001f && params.density <= 1.f);
2770 coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
2771
2772 // On the polygons of poly_with_offset, the infill lines will be connected.
2773 ExPolygonWithOffset poly_with_offset(
2774 surface->expolygon,
2775 - rotate_vector.first,
2776 float(scale_(this->overlap - (0.5 - INFILL_OVERLAP_OVER_SPACING) * this->spacing)),
2777 float(scale_(this->overlap - 0.5f * this->spacing)));
2778 if (poly_with_offset.n_contours_inner == 0) {
2779 // Not a single infill line fits.
2780 //FIXME maybe one shall trigger the gap fill here?
2781 return true;
2782 }
2783
2784 // For infill that needs to be consistent between layers (like Zig Zag),
2785 // we use bounding box of whole object to match vertical lines between layers.
2786 BoundingBox bounding_box_src = poly_with_offset.bounding_box_src();
2787 BoundingBox bounding_box = bounding_box_src;
2788 if (this->has_consistent_pattern()) {
2789 // Orca: The polygons are rotated about the origin, so follow the box center to where it was rotated.
2790 const Point c = this->bounding_box.center();
2792 bounding_box.translate(c.rotated(- rotate_vector.first) - c);
2793 }
2794
2795 // define flow spacing according to requested density
2796 if (params.full_infill() && !params.dont_adjust) {
2797 line_spacing = this->_adjust_solid_spacing(bounding_box_src.size().x(), line_spacing);
2798 this->spacing = unscale<double>(line_spacing);
2799 } else {
2800 // extend bounding box so that our pattern will be aligned with other layers
2801 // Transform the reference point to the rotated coordinate system.
2802 Point refpt = rotate_vector.second.rotated(- rotate_vector.first);
2803 // align_to_grid will not work correctly with positive pattern_shift.
2804 coord_t pattern_shift_scaled = coord_t(scale_(pattern_shift)) % line_spacing;
2805 refpt.x() -= (pattern_shift_scaled >= 0) ? pattern_shift_scaled : (line_spacing + pattern_shift_scaled);
2807 bounding_box.min,
2808 Point(line_spacing, line_spacing),
2809 refpt));
2810 }
2811
2812 // Intersect a set of euqally spaced vertical lines wiht expolygon.
2813 // n_vlines = ceil(bbox_width / line_spacing)
2814 size_t n_vlines = (bounding_box.max(0) - bounding_box.min(0) + line_spacing - 1) / line_spacing;
2815 coord_t x0 = bounding_box.min(0);
2816 if (params.full_infill())
2817 x0 += (line_spacing + coord_t(SCALED_EPSILON)) / 2;
2818
2819 int gap_line = params.horiz_move / line_spacing;
2820 if (gap_line % 2 == 0) {
2821 x0 += params.horiz_move - gap_line * line_spacing;
2822 } else {
2823 x0 += params.horiz_move - (gap_line - 1) * line_spacing;
2824 n_vlines += 1;
2825 }
2826#ifdef SLIC3R_DEBUG
2827 static int iRun = 0;
2828 BoundingBox bbox_svg = poly_with_offset.bounding_box_outer();
2829 ::Slic3r::SVG svg(debug_out_path("FillRectilinear-%d.svg", iRun), bbox_svg); // , scale_(1.));
2830 poly_with_offset.export_to_svg(svg);
2831 {
2832 ::Slic3r::SVG svg(debug_out_path("FillRectilinear-initial-%d.svg", iRun), bbox_svg); // , scale_(1.));
2833 poly_with_offset.export_to_svg(svg);
2834 }
2835 iRun ++;
2836#endif /* SLIC3R_DEBUG */
2837 std::vector<SegmentedIntersectionLine> segs = slice_region_by_vertical_lines(poly_with_offset, n_vlines, x0, line_spacing);
2838 // Connect by horizontal / vertical links, classify the links based on link_max_length as too long.
2839 connect_segment_intersections_by_contours(poly_with_offset, segs, params, link_max_length);
2840
2841#ifdef SLIC3R_DEBUG
2842 // Paint the segments and finalize the SVG file.
2843 for (size_t i_seg = 0; i_seg < segs.size(); ++ i_seg) {
2844 SegmentedIntersectionLine &sil = segs[i_seg];
2845 for (size_t i = 0; i < sil.intersections.size();) {
2846 size_t j = i + 1;
2847 for (; j < sil.intersections.size() && sil.intersections[j].is_inner(); ++ j) ;
2848 if (i + 1 == j) {
2849 svg.draw(Line(Point(sil.pos, sil.intersections[i].pos()), Point(sil.pos, sil.intersections[j].pos())), "blue");
2850 } else {
2851 svg.draw(Line(Point(sil.pos, sil.intersections[i].pos()), Point(sil.pos, sil.intersections[i+1].pos())), "green");
2852 svg.draw(Line(Point(sil.pos, sil.intersections[i+1].pos()), Point(sil.pos, sil.intersections[j-1].pos())), (j - i + 1 > 4) ? "yellow" : "magenta");
2853 svg.draw(Line(Point(sil.pos, sil.intersections[j-1].pos()), Point(sil.pos, sil.intersections[j].pos())), "green");
2854 }
2855 i = j + 1;
2856 }
2857 }
2858 svg.Close();
2859#endif /* SLIC3R_DEBUG */
2860
2861 //FIXME this is a hack to get the monotonic infill rolling. We likely want a smarter switch, likely based on user decison.
2862 bool monotonic_infill = params.monotonic; // || params.density > 0.99;
2863 if (monotonic_infill) {
2864 // Sometimes the outer contour pinches the inner contour from both sides along a single vertical line.
2865 // This situation is not handled correctly by generate_montonous_regions().
2866 // Insert phony OUTER_HIGH / OUTER_LOW pairs at the position where the contour is pinched.
2868 std::vector<MonotonicRegion> regions = generate_montonous_regions(segs);
2869#ifdef INFILL_DEBUG_OUTPUT
2870 {
2871 static int iRun;
2872 export_monotonous_regions_to_svg(poly_with_offset, segs, regions, debug_out_path("%s-%03d.svg", "MontonousRegions-initial", iRun ++));
2873 }
2874#endif // INFILL_DEBUG_OUTPUT
2875 connect_monotonic_regions(regions, poly_with_offset, segs);
2876 if (! regions.empty()) {
2877 std::mt19937_64 rng;
2878 std::vector<MonotonicRegionLink> path = chain_monotonic_regions(regions, poly_with_offset, segs, rng);
2879 polylines_from_paths(path, poly_with_offset, segs, polylines_out);
2880 }
2881 } else {
2882 traverse_graph_generate_polylines(poly_with_offset, params, segs, this->has_consistent_pattern(), polylines_out);
2883 }
2884
2885#ifdef SLIC3R_DEBUG
2886 {
2887 {
2888 ::Slic3r::SVG svg(debug_out_path("FillRectilinear-final-%03d.svg", iRun), bbox_svg); // , scale_(1.));
2889 poly_with_offset.export_to_svg(svg);
2890 for (size_t i = n_polylines_out_initial; i < polylines_out.size(); ++ i)
2891 svg.draw(polylines_out[i].lines(), "black");
2892 }
2893 // Paint a picture per polyline. This makes it easier to discover the order of the polylines and their overlap.
2894 for (size_t i_polyline = n_polylines_out_initial; i_polyline < polylines_out.size(); ++ i_polyline) {
2895 ::Slic3r::SVG svg(debug_out_path("FillRectilinear-final-%03d-%03d.svg", iRun, i_polyline), bbox_svg); // , scale_(1.));
2896 svg.draw(polylines_out[i_polyline].lines(), "black");
2897 }
2898 }
2899#endif /* SLIC3R_DEBUG */
2900
2901 // paths must be rotated back
2902 for (Polylines::iterator it = polylines_out.begin() + n_polylines_out_initial; it != polylines_out.end(); ++ it) {
2903 // No need to translate, the absolute position is irrelevant.
2904 // it->translate(- rotate_vector.second(0), - rotate_vector.second(1));
2905 assert(! it->has_duplicate_points());
2906 it->rotate(rotate_vector.first);
2907 //FIXME rather simplify the paths to avoid very short edges?
2908 //assert(! it->has_duplicate_points());
2909 it->remove_duplicate_points();
2910
2911 //get origin direction infill
2912 if (params.symmetric_infill_y_axis) {
2913 it->symmetric_y(params.symmetric_y_axis);
2914 }
2915 }
2916
2917#ifdef SLIC3R_DEBUG
2918 // Verify, that there are no duplicate points in the sequence.
2919 for (Polyline &polyline : polylines_out)
2920 assert(! polyline.has_duplicate_points());
2921#endif /* SLIC3R_DEBUG */
2922
2923
2924
2925 return true;
2926}
coord_t link_max_length
Definition FillBase.hpp:158
virtual bool has_consistent_pattern() const
Definition FillBase.hpp:201
static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance)
Definition FillBase.cpp:366
BoundingBox extended_object_bounding_box() const
Definition FillBase.cpp:1680
static void traverse_graph_generate_polylines(const ExPolygonWithOffset &poly_with_offset, const FillParams &params, std::vector< SegmentedIntersectionLine > &segs, const bool consistent_pattern, Polylines &polylines_out)
Definition FillRectilinear.cpp:1372
static void polylines_from_paths(const std::vector< MonotonicRegionLink > &path, const ExPolygonWithOffset &poly_with_offset, const std::vector< SegmentedIntersectionLine > &segs, Polylines &polylines_out)
Definition FillRectilinear.cpp:2598
static std::vector< SegmentedIntersectionLine > slice_region_by_vertical_lines(const ExPolygonWithOffset &poly_with_offset, size_t n_vlines, coord_t x0, coord_t line_spacing)
Definition FillRectilinear.cpp:777
T unscale(Q v)
Definition libslic3r.h:138
static std::vector< MonotonicRegionLink > chain_monotonic_regions(std::vector< MonotonicRegion > &regions, const ExPolygonWithOffset &poly_with_offset, const std::vector< SegmentedIntersectionLine > &segs, std::mt19937_64 &rng)
Definition FillRectilinear.cpp:2238
static void connect_monotonic_regions(std::vector< MonotonicRegion > &regions, const ExPolygonWithOffset &poly_with_offset, std::vector< SegmentedIntersectionLine > &segs)
Definition FillRectilinear.cpp:2097
static void connect_segment_intersections_by_contours(const ExPolygonWithOffset &poly_with_offset, std::vector< SegmentedIntersectionLine > &segs, const FillParams &params, const coord_t link_max_length)
Definition FillRectilinear.cpp:1068
static void pinch_contours_insert_phony_outer_intersections(std::vector< SegmentedIntersectionLine > &segs)
Definition FillRectilinear.cpp:1234
coord_t align_to_grid(const coord_t coord, const coord_t spacing)
Definition Point.hpp:718
static std::vector< MonotonicRegion > generate_montonous_regions(std::vector< SegmentedIntersectionLine > &segs)
Definition FillRectilinear.cpp:1873

References Slic3r::Fill::_adjust_solid_spacing(), Slic3r::Fill::_infill_direction(), Slic3r::align_to_grid(), Slic3r::Fill::bounding_box, Slic3r::ExPolygonWithOffset::bounding_box_outer(), Slic3r::ExPolygonWithOffset::bounding_box_src(), Slic3r::BoundingBoxBase< PointType, APointsType >::center(), Slic3r::chain_monotonic_regions(), Slic3r::SVG::Close(), Slic3r::connect_monotonic_regions(), Slic3r::connect_segment_intersections_by_contours(), Slic3r::debug_out_path(), Slic3r::FillParams::density, Slic3r::FillParams::dont_adjust, Slic3r::SVG::draw(), Slic3r::Surface::expolygon, Slic3r::Fill::extended_object_bounding_box(), Slic3r::FillParams::full_infill(), Slic3r::generate_montonous_regions(), Slic3r::Fill::has_consistent_pattern(), Slic3r::FillParams::horiz_move, Slic3r::SegmentedIntersectionLine::intersections, Slic3r::Fill::link_max_length, Slic3r::FillParams::locked_zag, M_PI, Slic3r::FillParams::monotonic, Slic3r::ExPolygonWithOffset::n_contours_inner, Slic3r::Fill::overlap, Slic3r::pinch_contours_insert_phony_outer_intersections(), Slic3r::polylines_from_paths(), Slic3r::SegmentedIntersectionLine::pos, Slic3r::Point::rotated(), scale_, SCALED_EPSILON, Slic3r::BoundingBoxBase< PointType, APointsType >::size(), Slic3r::slice_region_by_vertical_lines(), Slic3r::Fill::spacing, Slic3r::FillParams::symmetric_infill_y_axis, Slic3r::FillParams::symmetric_y_axis, Slic3r::BoundingBoxBase< PointType, APointsType >::translate(), Slic3r::traverse_graph_generate_polylines(), and Slic3r::unscale().

Referenced by Slic3r::FillMonotonic::fill_surface(), Slic3r::FillMonotonicLine::fill_surface(), Slic3r::FillMonotonicLines::fill_surface(), and fill_surface().

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

◆ fill_surface_by_multilines()

bool Slic3r::FillRectilinear::fill_surface_by_multilines ( const Surface * surface,
FillParams params,
const std::initializer_list< SweepParams > & sweep_params,
Polylines & polylines_out )
protectedinherited
3005{
3006 assert(sweep_params.size() >= 1);
3007 assert(!params.full_infill());
3008 params.density /= double(sweep_params.size());
3009 assert(params.density > 0.0001f && params.density <= 1.f);
3010
3011 ExPolygonWithOffset poly_with_offset_base(surface->expolygon, 0, float(scale_(this->overlap + 0.5 * params.multiline * this->spacing)));//increase offset to crop infill lines when using multiline infill
3012 if (poly_with_offset_base.n_contours == 0)
3013 // Not a single infill line fits.
3014 return true;
3015
3016 Polylines fill_lines;
3017 coord_t line_width = coord_t(scale_(this->spacing));
3018 coord_t line_spacing = coord_t(scale_(this->spacing) * params.multiline / params.density);
3019 std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
3020 for (const SweepParams &sweep : sweep_params) {
3021 // Rotate polygons so that we can work with vertical lines here
3022 float angle = rotate_vector.first + sweep.angle_base;
3023
3024 make_fill_lines(ExPolygonWithOffset(poly_with_offset_base, -angle), rotate_vector.second.rotated(-angle), angle,
3025 line_width + coord_t(SCALED_EPSILON), line_spacing, coord_t(scale_(sweep.pattern_shift)), fill_lines);
3026 }
3027
3028 // Apply multiline offset if needed
3029 multiline_fill(fill_lines, params, spacing);
3030
3031 // Contract surface polygon by half line width to avoid excesive overlap with perimeter
3032 const ExPolygons contracted = offset_ex(surface->expolygon, -float(scale_(0.5 * this->spacing)));
3033
3034 // if contraction results in empty ExPolygons, use original surface
3035 const ExPolygons& intersection_surface = contracted.empty() ? ExPolygons{surface->expolygon} : contracted;
3036
3037 // Intersect polylines with perimeter
3038 fill_lines = intersection_pl(std::move(fill_lines), intersection_surface);
3039
3040 if ((params.pattern == ipLateralLattice || params.pattern == ipLateralHoneycomb) && params.multiline > 1)
3041 remove_overlapped(fill_lines, line_width);
3042
3043 if (!fill_lines.empty()) {
3044 if (params.dont_connect()) {
3045 if (fill_lines.size() > 1)
3046 fill_lines = chain_polylines(std::move(fill_lines));
3047 append(polylines_out, std::move(fill_lines));
3048 } else
3049 connect_infill(std::move(fill_lines), to_polygons(intersection_surface), get_extents(surface->expolygon.contour), polylines_out,
3050 this->spacing, params);
3051 }
3052
3053 return true;
3054}
Definition FillRectilinear.hpp:39
@ ipLateralLattice
Definition PrintConfig.hpp:132
@ ipLateralHoneycomb
Definition PrintConfig.hpp:132
static void remove_overlapped(Polylines &polylines, coord_t line_width)
Definition FillRectilinear.cpp:2968
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:307
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip)
Definition ClipperUtils.cpp:1111
void make_fill_lines(const ExPolygonWithOffset &poly_with_offset, Point refpt, double angle, coord_t x_margin, coord_t line_spacing, coord_t pattern_shift, Polylines &fill_lines)
Definition FillRectilinear.cpp:2928
void multiline_fill(Polylines &polylines, const FillParams &params, float spacing)
Definition FillBase.cpp:2947

References Slic3r::Fill::_infill_direction(), Slic3r::Fill::angle, Slic3r::append(), Slic3r::chain_polylines(), Slic3r::Fill::connect_infill(), Slic3r::ExPolygon::contour, Slic3r::FillParams::density, Slic3r::FillParams::dont_connect(), Slic3r::Surface::expolygon, Slic3r::FillParams::full_infill(), Slic3r::get_extents(), Slic3r::intersection_pl(), Slic3r::ipLateralHoneycomb, Slic3r::ipLateralLattice, Slic3r::make_fill_lines(), Slic3r::FillParams::multiline, Slic3r::multiline_fill(), Slic3r::ExPolygonWithOffset::n_contours, Slic3r::offset_ex(), Slic3r::Fill::overlap, Slic3r::FillParams::pattern, Slic3r::remove_overlapped(), scale_, SCALED_EPSILON, Slic3r::Fill::spacing, and Slic3r::to_polygons().

Referenced by Slic3r::FillCubic::fill_surface(), Slic3r::FillGrid::fill_surface(), Slic3r::FillLateralHoneycomb::fill_surface(), Slic3r::FillLateralLattice::fill_surface(), Slic3r::FillQuarterCubic::fill_surface(), fill_surface(), Slic3r::FillStars::fill_surface(), and Slic3r::FillTriangles::fill_surface().

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:

◆ fill_surface_trapezoidal()

bool Slic3r::FillRectilinear::fill_surface_trapezoidal ( const Surface * surface,
FillParams params,
Polylines & polylines_out,
int Pattern_type )
protectedinherited
3105{
3106 assert(params.multiline > 1);
3107
3108 Polylines polylines;
3109
3110 // Common parameters
3111 const coord_t d1 = coord_t(scale_(this->spacing)) * params.multiline; // Infill total wall thickness
3112
3113 // Pattern-specific parameters
3114 coord_t period;
3115 double base_angle;
3116 std::pair<double, Point> rotate_vector = this->_infill_direction(surface);
3117
3118 if (Pattern_type == 0) {
3119 // Grid pattern parameters
3120 period = coord_t((2.0 * d1 / params.density) * std::sqrt(2.0));
3121 base_angle = rotate_vector.first + M_PI_4; // 45
3122 } else {
3123 // Triangular-family pattern parameters (triangles / stars)
3124 period = coord_t((2.0 * d1 / params.density) * std::sqrt(3.0));
3125 base_angle = rotate_vector.first + M_PI_2; // 90
3126 }
3127
3128 // Obtain the expolygon and rotate to align with pattern base angle
3129 ExPolygon expolygon = surface->expolygon;
3130 if (std::abs(base_angle) >= EPSILON) {
3131 expolygon.rotate(-base_angle, rotate_vector.second);
3132 }
3133
3134 const size_t infill_layer_id = (surface->thickness_layers > 0) ? this->layer_id / surface->thickness_layers : this->layer_id;
3135 // The triangular family turns by 120 degrees every layer, about the origin of the frame it is built in.
3136 const size_t layer_mod = infill_layer_id % 3;
3137 const double angle = layer_mod * 2.0 * M_PI / 3.0;
3138
3139 // Only build the rows over the surface, seen in the frame they are built in.
3140 Polygon local = expolygon.contour;
3141 if (Pattern_type != 0) {
3142 local.translate(-rotate_vector.second.x(), -rotate_vector.second.y());
3143 if (layer_mod)
3144 local.rotate(-angle);
3145 }
3146 BoundingBox cover = get_extents(local);
3147 cover.offset(period);
3148
3149 switch (Pattern_type) {
3150 case 0: // Grid / Trapezoidal
3151 {
3152 // Generate a non-crossing trapezoidal pattern to avoid overextrusion at intersections when `multiline > 1`.
3153 /*
3154 * P2--P3
3155 * / \
3156 * P0_P1/ \P4_
3157 */
3158 // P0xP1x=P4xP0x=d1/2
3159 // P2xP3x=d1
3160 // P1yP2y=P2yP3y=d2
3161
3162 const coord_t d2 = coord_t(0.5 * period - d1);
3163
3164 // Align bounding box to the grid, phased through the box center so separated infills align
3165 // each part on itself (grid_center is the origin for a standalone object / feature off).
3166 // Captured before the merge, which grows bb and would otherwise shift its center.
3167 BoundingBox bb = this->extended_object_bounding_box();
3168 const Point grid_center = bb.center();
3169 bb.merge(align_to_grid(bb.min, Point(period, period), grid_center));
3170 const coord_t xmin = bb.min.x();
3171 const coord_t ymin = bb.min.y();
3172
3173 auto transpose = [&grid_center](const Point &p) {
3174 return Point(grid_center.x() + p.y() - grid_center.y(), grid_center.y() + p.x() - grid_center.x());
3175 };
3176 if (infill_layer_id % 2 == 1)
3177 cover = BoundingBox(transpose(cover.min), transpose(cover.max));
3178 const coord_t row_spacing = period / 2;
3179 const coord_t first_x = xmin + (coord_t(std::floor(double(cover.min.x() - xmin) / period)) - 1) * period;
3180 const coord_t last_x = xmin + (coord_t(std::ceil(double(cover.max.x() - xmin) / period)) + 1) * period;
3181 const coord_t first_row = coord_t(std::floor(double(cover.min.y() - ymin) / row_spacing)) - 1;
3182 const coord_t last_row = coord_t(std::ceil(double(cover.max.y() - ymin) / row_spacing)) + 1;
3183
3184 // Create the two base row patterns once
3185 Polyline base_row_normal;
3186 base_row_normal.points.reserve(((last_x - first_x) / period + 1) * 5); // 5 points per trapezoid
3187 Polyline base_row_flipped;
3188 base_row_flipped.points.reserve(((last_x - first_x) / period + 1) * 5); // 5 points per trapezoid
3189
3190 // Build rows on the same global period grid, limited to the surface cover.
3191 for (coord_t x = first_x; x < last_x; x += period) {
3192 // Normal row
3193 base_row_normal.points.emplace_back(Point(x, d1 / 2)); // P0
3194 base_row_normal.points.emplace_back(Point(x + d1 / 2, d1 / 2)); // P1
3195 base_row_normal.points.emplace_back(Point(x + d1 / 2 + d2, d1 / 2 + d2)); // P2
3196 base_row_normal.points.emplace_back(Point(x + d1 / 2 + d2 + d1, d1 / 2 + d2)); // P3
3197 base_row_normal.points.emplace_back(Point(x + period - d1 / 2, d1 / 2)); // P4
3198 }
3199
3200 // Flipped row (mirrored vertically)
3201 base_row_flipped.points = base_row_normal.points;
3202 for (auto& p : base_row_flipped.points) {
3203 p.y() = period / 2 - p.y();
3204 }
3205
3206 // Pre-allocate polylines
3207 const size_t estimated_rows = size_t(last_row - first_row + 1);
3208 polylines.reserve(estimated_rows);
3209
3210 bool flip_vertical = (first_row % 2) != 0;
3211
3212 // Copy and translate only rows intersecting the surface cover.
3213 for (coord_t row = first_row; row <= last_row; ++row) {
3214 const coord_t y = ymin + row * row_spacing;
3215 Polyline pl_row = flip_vertical ? base_row_flipped : base_row_normal;
3216
3217 // Translate all points vertically
3218 for (Point& p : pl_row.points) {
3219 p.y() += y;
3220 }
3221
3222 polylines.emplace_back(std::move(pl_row));
3223 flip_vertical = !flip_vertical;
3224 }
3225
3226 // transpose points for odd infill layers (taking infill combination into account).
3227 // Orca: mirror across the diagonal through grid_center (not the origin), so the swapped
3228 // layers stay aligned with the center-phased grid. For a standalone object / feature off,
3229 // grid_center is the origin and this is a plain x/y swap.
3230 if (infill_layer_id % 2 == 1)
3231 for (Polyline& pl : polylines)
3232 for (Point& p : pl.points)
3233 p = transpose(p);
3234 break;
3235 }
3236
3237 case 1: // Triangular
3238 {
3239 // Generate a non-crossing trapezoidal pattern with a base line below.
3240 /*
3241 * P1-P2
3242 * / \
3243 * P0/ \P3_P4
3244 * ----------------
3245 */
3246 // P1xP2x=P3xP4x=d2
3247 // P0yP1y=P2yP3y=h-2d1
3248 //
3249
3250 // Triangular pattern density adjustment:
3251 const coord_t d2_tri = coord_t(2.0 / std::sqrt(3.0) * d1);
3252 const coord_t h = coord_t(0.5 * std::sqrt(3.0) * period); // height of triangle
3253
3254 // Keep the existing origin-anchored lattice, but generate only nearby tiles.
3255 const coord_t x_min_aligned = (coord_t(std::floor(double(cover.min.x()) / period)) - 1) * period;
3256 const coord_t x_max_aligned = (coord_t(std::ceil(double(cover.max.x()) / period)) + 1) * period;
3257 const coord_t first_row = coord_t(std::floor(double(cover.min.y()) / h)) - 1;
3258 const coord_t last_row = coord_t(std::ceil(double(cover.max.y()) / h)) + 1;
3259
3260 // Pre-allocate estimated number of polylines
3261 const size_t estimated_rows = size_t(last_row - first_row + 1);
3262 const size_t estimated_polylines = estimated_rows * 2; // base line + trapezoid line per row
3263 polylines.reserve(estimated_polylines);
3264
3265 // Create the two base row templates once
3266 Polyline base_line_template;
3267 base_line_template.points.reserve(2); // 2 points for base line
3268 Polyline trapezoid_row_normal;
3269 trapezoid_row_normal.points.reserve(((x_max_aligned - x_min_aligned) / period) * 5); // 5 points per trapezoid
3270 Polyline trapezoid_row_shifted;
3271 trapezoid_row_shifted.points.reserve(((x_max_aligned - x_min_aligned) / period) * 5); // 5 points per trapezoid
3272 // Build base line template (from x_min_aligned to x_max_aligned)
3273 base_line_template.points.emplace_back(Point(x_min_aligned, 0));
3274 base_line_template.points.emplace_back(Point(x_max_aligned, 0));
3275
3276 // Build complete trapezoid rows once
3277 // Normal row (no shift)
3278 for (coord_t x = x_min_aligned; x < x_max_aligned; x += period) {
3279 trapezoid_row_normal.points.emplace_back(Point(x + d2_tri / 2, d1)); // P0
3280 trapezoid_row_normal.points.emplace_back(Point(x + period / 2 - d2_tri / 2, h - d1)); // P1
3281 trapezoid_row_normal.points.emplace_back(Point(x + period / 2 + d2_tri / 2, h - d1)); // P2
3282 trapezoid_row_normal.points.emplace_back(Point(x + period - d2_tri / 2, d1)); // P3
3283 trapezoid_row_normal.points.emplace_back(Point(x + period, d1)); // P4
3284 }
3285
3286 // Shifted row (mirrored vertically)
3287 trapezoid_row_shifted.points = trapezoid_row_normal.points;
3288 for (auto& p : trapezoid_row_shifted.points)
3289 p.y() = h - p.y();
3290
3291 // Generate pattern by copying and translating templates vertically
3292 bool shift_row = (first_row % 2) != 0;
3293 for (coord_t row = first_row; row <= last_row; ++row) {
3294 const coord_t y = row * h;
3295 // Base line - copy and translate
3296 Polyline base_line = base_line_template;
3297 for (Point& p : base_line.points) {
3298 p.y() += y;
3299 }
3300 polylines.emplace_back(std::move(base_line));
3301
3302 // Trapezoid line - copy and translate the appropriate template
3303 Polyline trapezoid_line = shift_row ? trapezoid_row_shifted : trapezoid_row_normal;
3304 for (Point& p : trapezoid_line.points) {
3305 p.y() += y;
3306 }
3307
3308 if (!trapezoid_line.points.empty()) {
3309 polylines.emplace_back(std::move(trapezoid_line));
3310 }
3311
3312 shift_row = !shift_row;
3313 }
3314 break;
3315 }
3316
3317 case 2: // Tri-hexagon / FillStars
3318 {
3319 // Pattern parameters
3320 const coord_t hex_height = coord_t(0.5 * std::sqrt(3.0) * period);
3321 const coord_t tri_height = hex_height / 2;
3322 const coord_t d1_half = d1 / 2;
3323 const coord_t chamfer_height = std::sqrt(3.0) * d1_half;
3324 const coord_t d1_half_base = d1_half / std::sqrt(3.0);
3325 const coord_t half_period = period / 2;
3326 const coord_t quarter_period = period / 4;
3327 const coord_t row_y_offset = tri_height - (2 * tri_height) / 3;
3328
3329 // Keep the lattice anchored at the origin while generating only tiles around this surface.
3330 const int64_t first_tile = int64_t(std::floor(double(cover.min.x()) / period)) - 1;
3331 const int64_t last_tile = int64_t(std::ceil(double(cover.max.x()) / period)) + 1;
3332 const int64_t first_row = int64_t(std::floor(double(cover.min.y() - row_y_offset) / hex_height)) - 1;
3333 const int64_t last_row = int64_t(std::ceil(double(cover.max.y() - row_y_offset) / hex_height)) + 1;
3334
3335 const size_t estimated_rows = size_t(last_row - first_row + 1);
3336 const size_t estimated_polylines = estimated_rows * 2;
3337 polylines.reserve(estimated_polylines);
3338
3339 Polyline star_row_normal;
3340 star_row_normal.points.reserve(size_t(last_tile - first_tile) * 7);
3341 Polyline star_row_mirrored;
3342 star_row_mirrored.points.reserve(size_t(last_tile - first_tile) * 7);
3343
3344 for (int64_t tile = first_tile; tile < last_tile; ++tile) {
3345 const coord_t x = coord_t(tile * period) - half_period;
3346 star_row_normal.points.emplace_back(Point(x, hex_height)); // P0
3347 star_row_normal.points.emplace_back(Point(x + quarter_period - d1, hex_height)); // P1
3348 star_row_normal.points.emplace_back(Point(x + quarter_period + d1_half, hex_height - chamfer_height)); // P2
3349 star_row_normal.points.emplace_back(Point(x + half_period - d1_half_base, tri_height + d1_half)); // P3
3350 star_row_normal.points.emplace_back(Point(x + half_period + d1_half_base, tri_height + d1_half)); // P4
3351 star_row_normal.points.emplace_back(Point(x + (period * 3) / 4 - d1_half, hex_height - chamfer_height)); // P5
3352 star_row_normal.points.emplace_back(Point(x + (period * 3) / 4 + d1, hex_height)); // P6
3353 }
3354
3355 star_row_mirrored.points = star_row_normal.points;
3356 for (auto& p : star_row_mirrored.points)
3357 p.y() = hex_height - p.y();
3358
3359 const coord_t global_x_shift = half_period;
3360 auto append_row_with_shift = [&polylines](const Polyline& row_template, coord_t x_shift, coord_t y_shift) {
3361 Polyline row = row_template;
3362 for (Point& p : row.points) {
3363 p.x() += x_shift;
3364 p.y() += y_shift;
3365 }
3366 if (!row.points.empty())
3367 polylines.emplace_back(std::move(row));
3368 };
3369
3370 for (int64_t row = first_row; row <= last_row; ++row) {
3371 const coord_t y = coord_t(row * hex_height) + row_y_offset;
3372 const coord_t x_shift = (row % 2 == 0) ? 0 : half_period;
3373 append_row_with_shift(star_row_normal, x_shift + global_x_shift, y);
3374 append_row_with_shift(star_row_mirrored, x_shift + global_x_shift, y);
3375 }
3376 break;
3377 }
3378
3379 case 3: // Cubic
3380 {
3381 // Same z shifted lines as the single-line cubic; the slanted ones cross tau above the horizontal ones.
3382 auto pos_mod = [](double a, double m) { const double r = std::fmod(a, m); return r < 0. ? r + m : r; };
3383 const double h = 0.5 * std::sqrt(3.0) * period;
3384 const double shift = scale_(std::sqrt(0.5) * this->z);
3385 const double tau = pos_mod(-3. * shift, h);
3386 const double y0 = pos_mod(-2. * shift, 2. * h);
3387
3388 std::array<std::vector<Vec2d>, 2> levels{ cubic_upper_level(h - tau, h, period, d1), cubic_upper_level(tau, h, period, d1) };
3389 for (Vec2d &p : levels.front())
3390 p.y() = h - p.y();
3391
3392 const int64_t n_min = int64_t(std::floor((cover.min.y() - y0) / h)) - 1;
3393 const int64_t n_max = int64_t(std::ceil((cover.max.y() - y0) / h)) + 1;
3394 polylines.reserve(size_t(n_max - n_min + 1) * levels.size());
3395 for (int64_t n = n_min; n <= n_max; ++n) {
3396 const double x_off = (n & 1) ? 0.5 * period : 0.;
3397 const double base = y0 + double(n) * h - tau;
3398 const int64_t j_min = int64_t(std::floor((cover.min.x() - x_off) / period)) - 1;
3399 const int64_t j_max = int64_t(std::ceil((cover.max.x() - x_off) / period));
3400 for (const std::vector<Vec2d> &level : levels) {
3401 Polyline row;
3402 row.points.reserve(size_t(j_max - j_min + 1) * level.size());
3403 for (int64_t j = j_min; j <= j_max; ++j)
3404 for (size_t i = (j == j_min) ? 0 : 1; i < level.size(); ++i)
3405 row.points.emplace_back(coord_t(std::round(x_off + double(j * period) + level[i].x())),
3406 coord_t(std::round(base + level[i].y())));
3407 polylines.emplace_back(std::move(row));
3408 }
3409 }
3410 break;
3411 }
3412
3413 default:
3414 // Handle unknown pattern type
3415 break;
3416 }
3417
3418 // Orca: cases 1 to 3 anchor the pattern at the origin, so on their own they phase to the global
3419 // origin and every part shares one grid. Shift the pattern onto the box center
3420 // this->bounding_box carries, so separated infills align each part on itself. The center is the
3421 // origin for a standalone object (or when the feature is off), making the shift a no-op there.
3422 if (Pattern_type != 0)
3423 for (Polyline &pl : polylines) {
3424 if (layer_mod)
3425 pl.rotate(angle, Point(0, 0));
3426 pl.translate(rotate_vector.second);
3427 }
3428
3429 // Orca: round the corners of the trapezoids. The straight base lines of the triangular family
3430 // have no corner to round.
3431 smooth_polylines_corners(polylines, params.corner_smoothing());
3432
3433 // Only the centerlines within d1 / 2 of the surface have outlines reaching it.
3434 polylines = intersection_pl(std::move(polylines), offset(expolygon, float(d1 / 2)));
3435
3436 // Apply multiline fill
3437 multiline_fill(polylines, params, spacing);
3438
3439 // Start each outline on the cap at the first end of its path, outside the surface, so clipping splits it only there.
3440 const Vec2d row_dir = Pattern_type != 0 ? Vec2d(std::cos(angle), std::sin(angle)) : infill_layer_id % 2 ? Vec2d::UnitY() : Vec2d::UnitX();
3441 for (Polyline &pl : polylines)
3442 if (pl.size() > 3 && pl.first_point() == pl.last_point()) {
3443 pl.points.pop_back();
3444 std::rotate(pl.points.begin(), std::min_element(pl.points.begin(), pl.points.end(), [&row_dir](const Point &a, const Point &b) {
3445 return row_dir.dot(a.cast<double>()) < row_dir.dot(b.cast<double>());
3446 }), pl.points.end());
3447 pl.points.emplace_back(pl.points.front());
3448 }
3449
3450 // Contract surface polygon by half line width to avoid excesive overlap with perimeter
3451 ExPolygons contracted = offset_ex(expolygon, -float(scale_(0.5 * this->spacing)));
3452
3453 // if contraction results in empty polygon, use original surface
3454 const ExPolygons& intersection_surface = contracted.empty() ? ExPolygons{expolygon} : contracted;
3455
3456 // Intersect polylines with offset expolygon
3457 polylines = intersection_pl(std::move(polylines), intersection_surface);
3458
3459 // Remove very short segments that may cause connection issues
3460 const double minlength = scale_(0.8 * this->spacing);
3461 if (minlength > 0 && !polylines.empty()) {
3462 polylines.erase(std::remove_if(polylines.begin(), polylines.end(),
3463 [minlength](const Polyline& pl) { return pl.length() < minlength; }),
3464 polylines.end());
3465 }
3466
3467 // Connect infill lines using offset expolygon
3468 int infill_start_idx = polylines_out.size();
3469 if (!polylines.empty()) {
3470 if (params.dont_connect()) {
3471 if (polylines.size() > 1)
3472 polylines = chain_polylines(std::move(polylines));
3473 append(polylines_out, std::move(polylines));
3474 } else {
3475 connect_infill(std::move(polylines), to_polygons(intersection_surface), get_extents(intersection_surface), polylines_out,
3476 this->spacing, params);
3477 }
3478
3479 // Rotate back the infill lines to original orientation
3480 if (std::abs(base_angle) >= EPSILON) {
3481 for (auto it = polylines_out.begin() + infill_start_idx; it != polylines_out.end(); ++it) {
3482 it->rotate(base_angle, rotate_vector.second);
3483 }
3484 }
3485 }
3486
3487 return true;
3488}
coordf_t z
Definition FillBase.hpp:145
@ local
Definition Time.hpp:13
static std::vector< Vec2d > cubic_upper_level(double tau, double h, double period, double d1)
Definition FillRectilinear.cpp:3058
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
void smooth_polylines_corners(Polylines &polylines, const CornerSmoothing &smoothing, const double max_corner_distance, const CornerFilter &corner_filter)
Definition FillCornerSmoothing.cpp:296
Slic3r::Polygon Polygon
Definition Emboss.cpp:101

References Slic3r::Fill::_infill_direction(), Slic3r::align_to_grid(), Slic3r::Fill::angle, Slic3r::append(), Slic3r::BoundingBoxBase< PointType, APointsType >::center(), Slic3r::chain_polylines(), Slic3r::Fill::connect_infill(), Slic3r::ExPolygon::contour, Slic3r::FillParams::corner_smoothing(), Slic3r::cubic_upper_level(), Slic3r::FillParams::density, Slic3r::FillParams::dont_connect(), EPSILON, Slic3r::Surface::expolygon, Slic3r::Fill::extended_object_bounding_box(), Slic3r::get_extents(), Slic3r::intersection_pl(), Slic3r::Fill::layer_id, M_PI, Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::merge(), Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::FillParams::multiline, Slic3r::multiline_fill(), Slic3r::BoundingBoxBase< PointType, APointsType >::offset(), Slic3r::offset(), Slic3r::offset_ex(), Slic3r::MultiPoint::points, Slic3r::ExPolygon::rotate(), scale_, Slic3r::smooth_polylines_corners(), Slic3r::Fill::spacing, Slic3r::Surface::thickness_layers, Slic3r::to_polygons(), and Slic3r::Fill::z.

Referenced by Slic3r::FillCubic::fill_surface(), Slic3r::FillGrid::fill_surface(), Slic3r::FillStars::fill_surface(), and Slic3r::FillTriangles::fill_surface().

Here is the call graph for this function:
Here is the caller 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::FillRectilinear::is_self_crossing ( )
inlineoverridevirtualinherited

Implements Slic3r::Fill.

Reimplemented in Slic3r::FillStars, and Slic3r::FillTriangles.

31{ 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
@ 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
@ 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::FillMonotonicLine::no_sort ( ) const
inlineoverridevirtual

Reimplemented from Slic3r::Fill.

73{ 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: