Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::Fill Class Referenceabstract

#include <src/libslic3r/Fill/FillBase.hpp>

+ Inheritance diagram for Slic3r::Fill:
+ Collaboration diagram for Slic3r::Fill:

Public Member Functions

virtual ~Fill ()
 
virtual Fillclone () const =0
 
void set_bounding_box (const Slic3r::BoundingBox &bbox)
 
virtual bool use_bridge_flow () const
 
virtual bool no_sort () const
 
virtual Polylines fill_surface (const Surface *surface, const FillParams &params)
 
virtual ThickPolylines fill_surface_arachne (const Surface *surface, const FillParams &params)
 
virtual std::pair< float, Point_infill_direction (const Surface *surface) const
 

Static Public Member Functions

static Fillnew_from_type (const InfillPattern type)
 
static Fillnew_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 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
 
coord_t link_max_length
 
coord_t loop_clipping
 
BoundingBox bounding_box
 
FillAdaptive::Octreeadapt_fill_octree = nullptr
 
const PrintConfig * print_config = nullptr
 
const PrintObjectConfigprint_object_config = nullptr
 

Protected Member Functions

 Fill ()
 
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
 

Detailed Description

Constructor & Destructor Documentation

◆ ~Fill()

virtual Slic3r::Fill::~Fill ( )
inlinevirtual
99{}

◆ Fill()

Slic3r::Fill::Fill ( )
inlineprotected
119 :
120 layer_id(size_t(-1)),
121 z(0.),
122 spacing(0.),
123 // Infill / perimeter overlap.
124 overlap(0.),
125 // Initial angle is undefined.
126 angle(FLT_MAX),
128 loop_clipping(0),
129 // The initial bounding box is empty, therefore undefined.
130 bounding_box(Point(0, 0), Point(-1, -1))
131 {}
coord_t loop_clipping
Definition FillBase.hpp:87
coordf_t z
Definition FillBase.hpp:75
coordf_t spacing
Definition FillBase.hpp:77
coord_t link_max_length
Definition FillBase.hpp:85
BoundingBox bounding_box
Definition FillBase.hpp:89
float angle
Definition FillBase.hpp:81
size_t layer_id
Definition FillBase.hpp:73
coordf_t overlap
Definition FillBase.hpp:79
Kernel::Point_2 Point
Definition point_areas.cpp:20

Member Function Documentation

◆ _adjust_solid_spacing()

coord_t Slic3r::Fill::_adjust_solid_spacing ( const coord_t  width,
const coord_t  distance 
)
static
112{
113 assert(width >= 0);
114 assert(distance > 0);
115 // floor(width / distance)
116 const auto number_of_intervals = coord_t((width - EPSILON) / distance);
117 coord_t distance_new = (number_of_intervals == 0) ?
118 distance :
119 coord_t((width - EPSILON) / number_of_intervals);
120 const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
121 assert(factor > 1. - 1e-5);
122 // How much could the extrusion width be increased? By 20%.
123 const coordf_t factor_max = 1.2;
124 if (factor > factor_max)
125 distance_new = coord_t(floor((coordf_t(distance) * factor_max + 0.5)));
126 return distance_new;
127}
EIGEN_DEVICE_FUNC const FloorReturnType floor() const
Definition ArrayCwiseUnaryOps.h:388
static constexpr double EPSILON
Definition libslic3r.h:51
int32_t coord_t
Definition libslic3r.h:39
double coordf_t
Definition libslic3r.h:45
coord_t width(const BoundingBox &box)
Definition Arrange.cpp:539
double coordf_t
Definition GUI_ObjectList.hpp:36

References EPSILON, and floor().

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

+ 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  
)
inlineprotectedvirtual

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

139 {}

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 
)
inlineprotectedvirtual

Reimplemented in Slic3r::FillConcentric.

146 {}

◆ _infill_direction()

std::pair< float, Point > Slic3r::Fill::_infill_direction ( const Surface surface) const
virtual
132{
133 // set infill angle
134 float out_angle = this->angle;
135
136 if (out_angle == FLT_MAX) {
137 assert(false);
138 BOOST_LOG_TRIVIAL(error) << "Using undefined infill angle";
139 out_angle = 0.f;
140 }
141
142 // Bounding box is the bounding box of a perl object Slic3r::Print::Object (c++ object Slic3r::PrintObject)
143 // The bounding box is only undefined in unit tests.
144 Point out_shift = empty(this->bounding_box) ?
145 surface->expolygon.contour.bounding_box().center() :
146 this->bounding_box.center();
147
148#if 0
149 if (empty(this->bounding_box)) {
150 printf("Fill::_infill_direction: empty bounding box!");
151 } else {
152 printf("Fill::_infill_direction: reference point %d, %d\n", out_shift.x, out_shift.y);
153 }
154#endif
155
156 if (surface->bridge_angle >= 0) {
157 // use bridge angle
158 //FIXME Vojtech: Add a debugf?
159 // Slic3r::debugf "Filling bridge with angle %d\n", rad2deg($surface->bridge_angle);
160#ifdef SLIC3R_DEBUG
161 printf("Filling bridge with angle %f\n", surface->bridge_angle);
162#endif /* SLIC3R_DEBUG */
163 out_angle = float(surface->bridge_angle);
164 } else if (this->layer_id != size_t(-1)) {
165 // alternate fill direction
166 out_angle += this->_layer_angle(this->layer_id / surface->thickness_layers);
167 } else {
168// printf("Layer_ID undefined!\n");
169 }
170
171 out_angle += float(M_PI/2.);
172 return std::pair<float, Point>(out_angle, out_shift);
173}
#define M_PI
Definition ExtrusionSimulator.cpp:20
PointType center() const
Definition BoundingBox.cpp:194
virtual float _layer_angle(size_t idx) const
Definition FillBase.hpp:148
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:229
static char error[256]
Definition tga.cpp:50

References _layer_angle(), angle, bounding_box, Slic3r::MultiPoint::bounding_box(), Slic3r::Surface::bridge_angle, Slic3r::BoundingBoxBase< PointType, APointsType >::center(), Slic3r::ExPolygon::contour, Slic3r::empty(), error, Slic3r::Surface::expolygon, 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::make_fill_polylines().

+ 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
inlineprotectedvirtual

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

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

References M_PI.

Referenced by _infill_direction().

+ Here is the caller graph for this function:

◆ clone()

◆ 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 
)
static
2524{
2525 auto polygons_src = reserve_vector<const Polygon*>(boundary_src.size());
2526 for (const Polygon &polygon : boundary_src)
2527 polygons_src.emplace_back(&polygon);
2528
2529 connect_base_support(std::move(infill_ordered), polygons_src, bbox, polylines_out, spacing, params);
2530}
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:2068

◆ 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 
)
static
2069{
2070// assert(! infill_ordered.empty());
2071 assert(params.anchor_length >= 0.);
2072 assert(params.anchor_length_max >= 0.01f);
2073 assert(params.anchor_length_max >= params.anchor_length);
2074
2075 BoundaryInfillGraph graph = create_boundary_infill_graph(infill_ordered, boundary_src, bbox, spacing);
2076
2077#ifdef INFILL_DEBUG_OUTPUT
2078 static int iRun = 0;
2079 ++ iRun;
2080 export_partial_infill_to_svg(debug_out_path("connect_base_support-initial-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2081#endif // INFILL_DEBUG_OUTPUT
2082
2083 const double line_half_width = 0.5 * scale_(spacing);
2084 const double line_spacing = scale_(spacing) / params.density;
2085 const double min_arch_length = 1.3 * line_spacing;
2086 const double trim_length = line_half_width * 0.3;
2087
2088// After mark_boundary_segments_touching_infill() marks boundary segments overlapping trimmed infill lines,
2089// there are possibly some very short boundary segments unmarked, but overlapping the untrimmed infill lines fully.
2090// Mark those short boundary segments.
2092
2093#ifdef INFILL_DEBUG_OUTPUT
2094 export_partial_infill_to_svg(debug_out_path("connect_base_support-marked-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2095#endif // INFILL_DEBUG_OUTPUT
2096
2097 // Detect loops with zero infill end points connected.
2098 // Extrude these loops as perimeters.
2099 {
2100 std::vector<size_t> num_boundary_contour_infill_points(graph.boundary.size(), 0);
2101 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary)
2102 ++ num_boundary_contour_infill_points[cp.contour_idx];
2103 for (size_t i = 0; i < num_boundary_contour_infill_points.size(); ++ i)
2104 if (num_boundary_contour_infill_points[i] == 0 && graph.boundary_params[i].back() > trim_length + 0.5 * line_spacing) {
2105 // Emit a perimeter.
2106 Polyline pl(graph.boundary[i]);
2107 pl.points.emplace_back(pl.points.front());
2108 pl.clip_end(trim_length);
2109 if (pl.size() > 1)
2110 polylines_out.emplace_back(std::move(pl));
2111 }
2112 }
2113
2114 // Before processing the boundary arches, emit those arches, which were trimmed by the infill lines at both sides, but which
2115 // depart from the infill line at least once after touching the infill line.
2116 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2117 if (cp.next_on_contour && cp.next_trimmed && cp.next_on_contour->prev_trimmed) {
2118 // The arch is leaving one infill line to end up at the same infill line or at the neighbouring one.
2119 // The arch is touching one of those infill lines at least once.
2120 // 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.
2121 bool first = graph.first(cp);
2122 coord_t left = graph.point(cp).x();
2123 coord_t right = left;
2124 if (first) {
2125 left += line_half_width;
2126 right += line_spacing - line_half_width;
2127 } else {
2128 left -= line_spacing - line_half_width;
2129 right -= line_half_width;
2130 }
2131 double param_start = cp.param + cp.contour_not_taken_length_next;
2132 double param_end = cp.next_on_contour->param - cp.next_on_contour->contour_not_taken_length_prev;
2133 double contour_length = graph.boundary_params[cp.contour_idx].back();
2134 if (param_start >= contour_length)
2135 param_start -= contour_length;
2136 if (param_end < 0)
2137 param_end += contour_length;
2138 // Verify that the interval (param_overlap1, param_overlap2) is inside the interval (ip_low->param, ip_high->param).
2139 assert(cyclic_interval_inside_interval(cp.param, cp.next_on_contour->param, param_start, param_end, contour_length));
2140 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);
2141 }
2142 }
2143#ifdef INFILL_DEBUG_OUTPUT
2144 export_partial_infill_to_svg(debug_out_path("connect_base_support-excess-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2145#endif // INFILL_DEBUG_OUTPUT
2146
2147 base_support_extend_infill_lines(infill_ordered, graph, spacing, params);
2148
2149#ifdef INFILL_DEBUG_OUTPUT
2150 export_partial_infill_to_svg(debug_out_path("connect_base_support-extended-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2151#endif // INFILL_DEBUG_OUTPUT
2152
2153 std::vector<size_t> merged_with(infill_ordered.size());
2154 std::iota(merged_with.begin(), merged_with.end(), 0);
2155 auto get_and_update_merged_with = [&graph, &merged_with](const ContourIntersectionPoint *cp) -> size_t {
2156 size_t polyline_idx = (cp - graph.map_infill_end_point_to_boundary.data()) / 2;
2157 for (size_t last = polyline_idx;;) {
2158 size_t lower = merged_with[last];
2159 assert(lower <= last);
2160 if (lower == last) {
2161 merged_with[polyline_idx] = last;
2162 return last;
2163 }
2164 last = lower;
2165 }
2166 assert(false);
2167 return std::numeric_limits<size_t>::max();
2168 };
2169
2170 auto vertical = [](BoundaryInfillGraph::Direction dir) {
2171 return dir == BoundaryInfillGraph::Up || dir == BoundaryInfillGraph::Down;
2172 };
2173 // When both left / right arch connected to cp is vertical (ends up at the same vertical infill line), which one to take?
2174 auto take_vertical_prev = [](const ContourIntersectionPoint &cp) {
2175 return cp.prev_trimmed == cp.next_trimmed ?
2176 // Both are either trimmed or not trimmed. Take the longer contour.
2177 cp.contour_not_taken_length_prev > cp.contour_not_taken_length_next :
2178 // One is trimmed, the other is not trimmed. Take the not trimmed.
2179 ! cp.prev_trimmed && cp.next_trimmed;
2180 };
2181
2182 // Connect infill lines at cp and cpo_next_on_contour.
2183 // If the complete arch cannot be taken, then
2184 // if (take_first)
2185 // take the infill line at cp and an arc from cp towards cp.next_on_contour.
2186 // else
2187 // take the infill line at cp_next_on_contour and an arc from cp.next_on_contour towards cp.
2188 // If cp1 == next_on_contour (a single infill line is connected to a contour, this is a valid case for contours with holes),
2189 // then extrude the full circle.
2190 // Nothing is done if the arch could no more be taken (one of it end points were consumed already).
2191 auto take_next = [&graph, &infill_ordered, &merged_with, get_and_update_merged_with, line_half_width, trim_length](ContourIntersectionPoint &cp, bool take_first) {
2192 // Indices of the polylines to be connected by a perimeter segment.
2193 ContourIntersectionPoint *cp1 = &cp;
2194 ContourIntersectionPoint *cp2 = cp.next_on_contour;
2195 assert(cp1->next_trimmed == cp2->prev_trimmed);
2196 //assert(cp1->next_trimmed || cp1->consumed == cp2->consumed);
2197 if (take_first ? cp1->consumed : cp2->consumed)
2198 return;
2199 size_t polyline_idx1 = get_and_update_merged_with(cp1);
2200 size_t polyline_idx2 = get_and_update_merged_with(cp2);
2201 Polyline &polyline1 = infill_ordered[polyline_idx1];
2202 Polyline &polyline2 = infill_ordered[polyline_idx2];
2203 const Points &contour = graph.boundary[cp1->contour_idx];
2204 const std::vector<double> &contour_params = graph.boundary_params[cp1->contour_idx];
2205 assert(cp1->consumed || contour[cp1->point_idx] == polyline1.points.front() || contour[cp1->point_idx] == polyline1.points.back());
2206 assert(cp2->consumed || contour[cp2->point_idx] == polyline2.points.front() || contour[cp2->point_idx] == polyline2.points.back());
2207 bool trimmed = take_first ? cp1->next_trimmed : cp2->prev_trimmed;
2208 if (! trimmed) {
2209 // Trim the end if closing a loop or making a T-joint.
2210 trimmed = cp1 == cp2 || polyline_idx1 == polyline_idx2 || (take_first ? cp2->consumed : cp1->consumed);
2211 if (! trimmed) {
2212 const bool cp1_first = ((cp1 - graph.map_infill_end_point_to_boundary.data()) & 1) == 0;
2213 const ContourIntersectionPoint* cp1_other = cp1_first ? cp1 + 1 : cp1 - 1;
2214 // Self loop, connecting the end points of the same infill line.
2215 trimmed = cp2 == cp1_other;
2216 }
2217 if (trimmed) /* [[unlikely]] */ {
2218 // Single end point on a contour. This may happen on contours with holes. Extrude a loop.
2219 // Or a self loop, connecting the end points of the same infill line.
2220 // Or closing a chain of infill lines. This may happen if infilling a contour with a hole.
2221 double len = cp1 == cp2 ? contour_params.back() : path_length_along_contour_ccw(cp1, cp2, contour_params.back());
2222 if (take_first) {
2223 cp1->trim_next(std::max(0., len - trim_length - SCALED_EPSILON));
2224 cp2->trim_prev(0);
2225 } else {
2226 cp1->trim_next(0);
2227 cp2->trim_prev(std::max(0., len - trim_length - SCALED_EPSILON));
2228 }
2229 }
2230 }
2231 if (trimmed) {
2232 if (take_first)
2233 take_limited(polyline1, contour, contour_params, cp1, cp2, false, 1e10, line_half_width);
2234 else
2235 take_limited(polyline2, contour, contour_params, cp2, cp1, true, 1e10, line_half_width);
2236 } else if (! cp1->consumed && ! cp2->consumed) {
2237 if (contour[cp1->point_idx] == polyline1.points.front())
2238 polyline1.reverse();
2239 if (contour[cp2->point_idx] == polyline2.points.back())
2240 polyline2.reverse();
2241 take(polyline1, polyline2, contour, cp1, cp2, false);
2242 // Mark the second polygon as merged with the first one.
2243 if (polyline_idx2 < polyline_idx1) {
2244 polyline2 = std::move(polyline1);
2245 polyline1.points.clear();
2246 merged_with[polyline_idx1] = merged_with[polyline_idx2];
2247 } else {
2248 polyline2.points.clear();
2249 merged_with[polyline_idx2] = merged_with[polyline_idx1];
2250 }
2251 }
2252 };
2253
2254 // Consume all vertical arches. If a vertical arch is touching a neighboring vertical infill line, thus the vertical arch is trimmed,
2255 // only consume the trimmed part if it is longer than min_arch_length.
2256 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2257 assert(cp.contour_idx != boundary_idx_unconnected);
2258 if (cp.consumed)
2259 continue;
2260 const ContourIntersectionPoint &cp_other = graph.other(cp);
2261 assert((cp.next_on_contour == &cp_other) == (cp_other.prev_on_contour == &cp));
2262 assert((cp.prev_on_contour == &cp_other) == (cp_other.next_on_contour == &cp));
2263 BoundaryInfillGraph::Direction dir_prev = graph.dir_prev(cp);
2264 BoundaryInfillGraph::Direction dir_next = graph.dir_next(cp);
2265 // Following code will also consume contours with just a single infill line attached. (cp1->next_on_contour == cp1).
2266 assert((cp.next_on_contour == &cp) == (cp.prev_on_contour == &cp));
2267 bool can_take_prev = vertical(dir_prev) && ! cp.prev_on_contour->consumed && cp.prev_on_contour != &cp_other;
2268 bool can_take_next = vertical(dir_next) && ! cp.next_on_contour->consumed && cp.next_on_contour != &cp_other;
2269 if (can_take_prev && (! can_take_next || take_vertical_prev(cp))) {
2270 if (! cp.prev_trimmed || cp.contour_not_taken_length_prev > min_arch_length)
2271 // take previous
2272 take_next(*cp.prev_on_contour, false);
2273 } else if (can_take_next) {
2274 if (! cp.next_trimmed || cp.contour_not_taken_length_next > min_arch_length)
2275 // take next
2276 take_next(cp, true);
2277 }
2278 }
2279
2280#ifdef INFILL_DEBUG_OUTPUT
2281 export_partial_infill_to_svg(debug_out_path("connect_base_support-vertical-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2282#endif // INFILL_DEBUG_OUTPUT
2283
2284 const std::vector<SupportArcCost> arches = evaluate_support_arches(infill_ordered, graph, spacing, params);
2285 static const double cost_low = line_spacing * 1.3;
2286 static const double cost_high = line_spacing * 2.;
2287 static const double cost_veryhigh = line_spacing * 3.;
2288
2289 {
2290 std::vector<const SupportArcCost*> selected;
2291 selected.reserve(graph.map_infill_end_point_to_boundary.size());
2292 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2293 if (cp.consumed)
2294 continue;
2295 const SupportArcCost &cost_prev = arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2];
2296 const SupportArcCost &cost_next = *(&cost_prev + 1);
2297 double cost_min = cost_prev.cost;
2298 double cost_max = cost_next.cost;
2299 if (cost_min > cost_max)
2300 std::swap(cost_min, cost_max);
2301 if (cost_max < cost_low || cost_min > cost_high)
2302 // Don't take any of the prev / next arches now, take zig-zag instead. It does not matter which one will be taken.
2303 continue;
2304 const double cost_diff_relative = (cost_max - cost_min) / cost_max;
2305 if (cost_diff_relative < 0.25)
2306 // Don't take any of the prev / next arches now, take zig-zag instead. It does not matter which one will be taken.
2307 continue;
2308 if (cost_prev.cost > cost_low)
2309 selected.emplace_back(&cost_prev);
2310 if (cost_next.cost > cost_low)
2311 selected.emplace_back(&cost_next);
2312 }
2313 // Take the longest arch first.
2314 std::sort(selected.begin(), selected.end(), [](const auto *l, const auto *r) { return l->cost > r->cost; });
2315 // And connect along the arches.
2316 for (const SupportArcCost *arc : selected) {
2317 ContourIntersectionPoint &cp = graph.map_infill_end_point_to_boundary[(arc - arches.data()) / 2];
2318 if (! cp.consumed) {
2319 bool prev = ((arc - arches.data()) & 1) == 0;
2320 if (prev)
2321 take_next(*cp.prev_on_contour, false);
2322 else
2323 take_next(cp, true);
2324 }
2325 }
2326 }
2327
2328#if 0
2329 {
2330 // Connect infill lines with long horizontal arches. Only take a horizontal arch, if it will not block
2331 // the end caps (vertical arches) at the other side of the infill line.
2332 struct Arc {
2333 ContourIntersectionPoint *intersection;
2334 double arc_length;
2335 bool take_next;
2336 };
2337 std::vector<Arc> arches;
2338 arches.reserve(graph.map_infill_end_point_to_boundary.size());
2339 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2340 if (cp.consumed)
2341 continue;
2342 // Not a losed loop, such loops should already be consumed.
2343 assert(cp.next_on_contour != &cp);
2344 const bool first = ((&cp - graph.map_infill_end_point_to_boundary.data()) & 1) == 0;
2345 const ContourIntersectionPoint *other_end = first ? &cp + 1 : &cp - 1;
2346 const bool loop_next = cp.next_on_contour == other_end;
2347 if (! loop_next && cp.could_connect_next()) {
2348 if (cp.contour_not_taken_length_next > min_arch_length) {
2349 // Try both directions. This is useful to be able to close a loop back to the same line to take a long arch.
2350 arches.push_back({ &cp, cp.contour_not_taken_length_next, true });
2351 arches.push_back({ cp.next_on_contour, cp.contour_not_taken_length_next, false });
2352 }
2353 } else {
2354 //bool first = ((&cp - graph.map_infill_end_point_to_boundary) & 1) == 0;
2355 if (cp.prev_trimmed && cp.could_take_prev()) {
2356 //FIXME trace the trimmed line to decide what priority to assign to it.
2357 // Is the end point close to the current vertical line or to the other vertical line?
2358 const Point &pt = graph.point(cp);
2359 const Point &prev = graph.point(*cp.prev_on_contour);
2360 if (std::abs(pt.x() - prev.x()) < coord_t(0.5 * line_spacing)) {
2361 // End point on the same line.
2362 // Measure maximum distance from the current vertical line.
2363 if (cp.contour_not_taken_length_prev > 0.5 * line_spacing)
2364 arches.push_back({ &cp, cp.contour_not_taken_length_prev, false });
2365 } else {
2366 // End point on the other line.
2367 if (cp.contour_not_taken_length_prev > min_arch_length)
2368 arches.push_back({ &cp, cp.contour_not_taken_length_prev, false });
2369 }
2370 }
2371 if (cp.next_trimmed && cp.could_take_next()) {
2372 //FIXME trace the trimmed line to decide what priority to assign to it.
2373 const Point &pt = graph.point(cp);
2374 const Point &next = graph.point(*cp.next_on_contour);
2375 if (std::abs(pt.x() - next.x()) < coord_t(0.5 * line_spacing)) {
2376 // End point on the same line.
2377 // Measure maximum distance from the current vertical line.
2378 if (cp.contour_not_taken_length_next > 0.5 * line_spacing)
2379 arches.push_back({ &cp, cp.contour_not_taken_length_next, true });
2380 } else {
2381 // End point on the other line.
2382 if (cp.contour_not_taken_length_next > min_arch_length)
2383 arches.push_back({ &cp, cp.contour_not_taken_length_next, true });
2384 }
2385 }
2386 }
2387 }
2388 // Take the longest arch first.
2389 std::sort(arches.begin(), arches.end(), [](const auto &l, const auto &r) { return l.arc_length > r.arc_length; });
2390 // And connect along the arches.
2391 for (Arc &arc : arches)
2392 if (arc.take_next)
2393 take_next(*arc.intersection, true);
2394 else
2395 take_next(*arc.intersection->prev_on_contour, false);
2396 }
2397#endif
2398
2399#ifdef INFILL_DEBUG_OUTPUT
2400 export_partial_infill_to_svg(debug_out_path("connect_base_support-arches-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2401#endif // INFILL_DEBUG_OUTPUT
2402
2403 // Traverse the unconnected lines in a zig-zag fashion, left to right only.
2404 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2405 assert(cp.contour_idx != boundary_idx_unconnected);
2406 if (cp.consumed)
2407 continue;
2408 bool first = ((&cp - graph.map_infill_end_point_to_boundary.data()) & 1) == 0;
2409 if (first) {
2410 // Only connect if the two lines are not connected by the same line already.
2411 if (get_and_update_merged_with(&cp) != get_and_update_merged_with(cp.next_on_contour))
2412 take_next(cp, true);
2413 } else {
2414 if (get_and_update_merged_with(&cp) != get_and_update_merged_with(cp.prev_on_contour))
2415 take_next(*cp.prev_on_contour, false);
2416 }
2417 }
2418
2419#ifdef INFILL_DEBUG_OUTPUT
2420 export_partial_infill_to_svg(debug_out_path("connect_base_support-zigzag-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2421#endif // INFILL_DEBUG_OUTPUT
2422
2423 // Add the left caps.
2424 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2425 const bool first = ((&cp - graph.map_infill_end_point_to_boundary.data()) & 1) == 0;
2426 const ContourIntersectionPoint *other_end = first ? &cp + 1 : &cp - 1;
2427 const bool loop_next = cp.next_on_contour == other_end;
2428 const bool loop_prev = other_end->next_on_contour == &cp;
2429#ifndef NDEBUG
2430 const SupportArcCost &cost_prev = arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2];
2431 const SupportArcCost &cost_next = *(&cost_prev + 1);
2432 assert(cost_prev.self_loop == loop_prev);
2433 assert(cost_next.self_loop == loop_next);
2434#endif // NDEBUG
2435 if (loop_prev && cp.could_take_prev())
2436 take_next(*cp.prev_on_contour, false);
2437 if (loop_next && cp.could_take_next())
2438 take_next(cp, true);
2439 }
2440
2441#ifdef INFILL_DEBUG_OUTPUT
2442 export_partial_infill_to_svg(debug_out_path("connect_base_support-caps-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2443#endif // INFILL_DEBUG_OUTPUT
2444
2445 // Connect with T joints using long arches. Loops could be created only if a very long arc has to be added.
2446 {
2447 std::vector<const SupportArcCost*> candidates;
2448 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2449 if (cp.could_take_prev())
2450 candidates.emplace_back(&arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2]);
2451 if (cp.could_take_next())
2452 candidates.emplace_back(&arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2 + 1]);
2453 }
2454 std::sort(candidates.begin(), candidates.end(), [](auto *c1, auto *c2) { return c1->cost > c2->cost; });
2455 for (const SupportArcCost *candidate : candidates) {
2456 ContourIntersectionPoint &cp = graph.map_infill_end_point_to_boundary[(candidate - arches.data()) / 2];
2457 bool prev = ((candidate - arches.data()) & 1) == 0;
2458 if (prev) {
2459 if (cp.could_take_prev() && (get_and_update_merged_with(&cp) != get_and_update_merged_with(cp.prev_on_contour) || candidate->cost > cost_high))
2460 take_next(*cp.prev_on_contour, false);
2461 } else {
2462 if (cp.could_take_next() && (get_and_update_merged_with(&cp) != get_and_update_merged_with(cp.next_on_contour) || candidate->cost > cost_high))
2463 take_next(cp, true);
2464 }
2465 }
2466 }
2467
2468#ifdef INFILL_DEBUG_OUTPUT
2469 export_partial_infill_to_svg(debug_out_path("connect_base_support-Tjoints-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2470#endif // INFILL_DEBUG_OUTPUT
2471
2472 // Add very long arches and reasonably long caps even if both of its end points were already consumed.
2473 const double cap_cost = 0.5 * line_spacing;
2474 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
2475 const SupportArcCost &cost_prev = arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2];
2476 const SupportArcCost &cost_next = *(&cost_prev + 1);
2477 if (cp.contour_not_taken_length_prev > SCALED_EPSILON &&
2478 (cost_prev.self_loop ?
2479 cost_prev.cost > cap_cost :
2480 cost_prev.cost > cost_veryhigh)) {
2481 assert(cp.consumed && (cp.prev_on_contour->consumed || cp.prev_trimmed));
2482 Polyline pl { graph.point(cp) };
2483 if (! cp.prev_trimmed) {
2484 cp.trim_prev(cp.contour_not_taken_length_prev - line_half_width);
2485 cp.prev_on_contour->trim_next(0);
2486 }
2487 if (cp.contour_not_taken_length_prev > SCALED_EPSILON) {
2488 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);
2489 cp.trim_prev(0);
2490 pl.clip_start(line_half_width);
2491 polylines_out.emplace_back(std::move(pl));
2492 }
2493 }
2494 if (cp.contour_not_taken_length_next > SCALED_EPSILON &&
2495 (cost_next.self_loop ?
2496 cost_next.cost > cap_cost :
2497 cost_next.cost > cost_veryhigh)) {
2498 assert(cp.consumed && (cp.next_on_contour->consumed || cp.next_trimmed));
2499 Polyline pl { graph.point(cp) };
2500 if (! cp.next_trimmed) {
2501 cp.trim_next(cp.contour_not_taken_length_next - line_half_width);
2502 cp.next_on_contour->trim_prev(0);
2503 }
2504 if (cp.contour_not_taken_length_next > SCALED_EPSILON) {
2505 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);
2506 cp.trim_next(0);
2507 pl.clip_start(line_half_width);
2508 polylines_out.emplace_back(std::move(pl));
2509 }
2510 }
2511 }
2512
2513#ifdef INFILL_DEBUG_OUTPUT
2514 export_partial_infill_to_svg(debug_out_path("connect_base_support-final-%03d.svg", iRun), graph, infill_ordered, polylines_out);
2515#endif // INFILL_DEBUG_OUTPUT
2516
2517 polylines_out.reserve(polylines_out.size() + std::count_if(infill_ordered.begin(), infill_ordered.end(), [](const Polyline &pl) { return ! pl.empty(); }));
2518 for (Polyline &pl : infill_ordered)
2519 if (! pl.empty())
2520 polylines_out.emplace_back(std::move(pl));
2521}
Points points
Definition MultiPoint.hpp:18
if(!(yy_init))
Definition lexer.c:1190
#define SCALED_EPSILON
Definition libslic3r.h:71
#define scale_(val)
Definition libslic3r.h:69
std::string debug_out_path(const char *name,...)
Definition utils.cpp:218
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:343
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:686
static void take(Polyline &pl1, const Polyline &pl2, const Points &contour, size_t idx_start, size_t idx_end, bool clockwise)
Definition FillBase.cpp:384
double path_length_along_contour_ccw(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, double contour_length)
Definition FillBase.cpp:244
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:1776
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:1285
static bool cyclic_interval_inside_interval(double outer_low, double outer_high, double inner_low, double inner_high, double length)
Definition FillBase.cpp:710
static constexpr auto boundary_idx_unconnected
Definition FillBase.cpp:1116
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:430
static std::vector< SupportArcCost > evaluate_support_arches(Polylines &infill, BoundaryInfillGraph &graph, const double spacing, const FillParams &params)
Definition FillBase.cpp:2024
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:287
static void mark_boundary_segments_overlapping_infill(BoundaryInfillGraph &graph, const Polylines &infill, const double spacing)
Definition FillBase.cpp:1205
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:58
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:21
static void base_support_extend_infill_lines(Polylines &infill, BoundaryInfillGraph &graph, const double spacing, const FillParams &params)
Definition FillBase.cpp:1655
STL namespace.
Direction
Definition FillBase.cpp:1151
@ Down
Definition FillBase.cpp:1155
@ Up
Definition FillBase.cpp:1154

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::ContourIntersectionPoint::consumed, Slic3r::ContourIntersectionPoint::contour_idx, Slic3r::SupportArcCost::cost, 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::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::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::MultiPoint::reverse(), scale_, SCALED_EPSILON, Slic3r::SupportArcCost::self_loop, Slic3r::MultiPoint::size(), Slic3r::take(), Slic3r::take_ccw_limited(), Slic3r::take_cw_limited(), Slic3r::take_limited(), Slic3r::ContourIntersectionPoint::trim_next(), and Slic3r::ContourIntersectionPoint::trim_prev().

Referenced by 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 
)
static
1097{
1098 assert(! boundary_src.contour.points.empty());
1099 auto polygons_src = reserve_vector<const Polygon*>(boundary_src.holes.size() + 1);
1100 polygons_src.emplace_back(&boundary_src.contour);
1101 for (const Polygon &polygon : boundary_src.holes)
1102 polygons_src.emplace_back(&polygon);
1103
1104 connect_infill(std::move(infill_ordered), polygons_src, get_extents(boundary_src.contour), polylines_out, spacing, params);
1105}
static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams &params)
Definition FillBase.cpp:1096
BoundingBox get_extents(const ExPolygon &expolygon)
Definition ExPolygon.cpp:352
const Polygons & holes(const ExPolygon &p)
Definition AGGRaster.hpp:22

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

Referenced by Slic3r::Fill3DHoneycomb::_fill_surface_single(), Slic3r::FillGyroid::_fill_surface_single(), Slic3r::FillHoneycomb::_fill_surface_single(), Slic3r::FillLightning::Filler::_fill_surface_single(), Slic3r::FillPlanePath::_fill_surface_single(), connect_infill(), connect_infill(), and Slic3r::FillRectilinear::fill_surface_by_multilines().

+ 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 
)
static
1108{
1109 auto polygons_src = reserve_vector<const Polygon*>(boundary_src.size());
1110 for (const Polygon &polygon : boundary_src)
1111 polygons_src.emplace_back(&polygon);
1112
1113 connect_infill(std::move(infill_ordered), polygons_src, bbox, polylines_out, spacing, params);
1114}

References connect_infill(), 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 
)
static
1422{
1423 assert(! infill_ordered.empty());
1424 assert(params.anchor_length >= 0.);
1425 assert(params.anchor_length_max >= 0.01f);
1426 assert(params.anchor_length_max >= params.anchor_length);
1427 const double anchor_length = scale_(params.anchor_length);
1428 const double anchor_length_max = scale_(params.anchor_length_max);
1429
1430#if 0
1431 append(polylines_out, infill_ordered);
1432 return;
1433#endif
1434
1435 BoundaryInfillGraph graph = create_boundary_infill_graph(infill_ordered, boundary_src, bbox, spacing);
1436
1437 std::vector<size_t> merged_with(infill_ordered.size());
1438 std::iota(merged_with.begin(), merged_with.end(), 0);
1439
1440 auto get_and_update_merged_with = [&merged_with](size_t polyline_idx) -> size_t {
1441 for (size_t last = polyline_idx;;) {
1442 size_t lower = merged_with[last];
1443 assert(lower <= last);
1444 if (lower == last) {
1445 merged_with[polyline_idx] = last;
1446 return last;
1447 }
1448 last = lower;
1449 }
1450 assert(false);
1451 return std::numeric_limits<size_t>::max();
1452 };
1453
1454 const double line_half_width = 0.5 * scale_(spacing);
1455
1456#if 0
1457 // Connection from end of one infill line to the start of another infill line.
1458 //const double length_max = scale_(spacing);
1459// const auto length_max = double(scale_((2. / params.density) * spacing));
1460 const auto length_max = double(scale_((1000. / params.density) * spacing));
1461 struct ConnectionCost {
1462 ConnectionCost(size_t idx_first, double cost, bool reversed) : idx_first(idx_first), cost(cost), reversed(reversed) {}
1463 size_t idx_first;
1464 double cost;
1465 bool reversed;
1466 };
1467 std::vector<ConnectionCost> connections_sorted;
1468 connections_sorted.reserve(infill_ordered.size() * 2 - 2);
1469 for (size_t idx_chain = 1; idx_chain < infill_ordered.size(); ++ idx_chain) {
1470 const ContourIntersectionPoint *cp1 = &graph.map_infill_end_point_to_boundary[(idx_chain - 1) * 2 + 1];
1471 const ContourIntersectionPoint *cp2 = &graph.map_infill_end_point_to_boundary[idx_chain * 2];
1472 if (cp1->contour_idx != boundary_idx_unconnected && cp1->contour_idx == cp2->contour_idx) {
1473 // End points on the same contour. Try to connect them.
1474 std::pair<double, double> len = path_lengths_along_contour(cp1, cp2, graph.boundary_params[cp1->contour_idx].back());
1475 if (len.first < length_max)
1476 connections_sorted.emplace_back(idx_chain - 1, len.first, false);
1477 if (len.second < length_max)
1478 connections_sorted.emplace_back(idx_chain - 1, len.second, true);
1479 }
1480 }
1481 std::sort(connections_sorted.begin(), connections_sorted.end(), [](const ConnectionCost& l, const ConnectionCost& r) { return l.cost < r.cost; });
1482
1483 for (ConnectionCost &connection_cost : connections_sorted) {
1484 ContourIntersectionPoint *cp1 = &graph.map_infill_end_point_to_boundary[connection_cost.idx_first * 2 + 1];
1485 ContourIntersectionPoint *cp2 = &graph.map_infill_end_point_to_boundary[(connection_cost.idx_first + 1) * 2];
1486 assert(cp1 != cp2);
1487 assert(cp1->contour_idx == cp2->contour_idx && cp1->contour_idx != boundary_idx_unconnected);
1488 if (cp1->consumed || cp2->consumed)
1489 continue;
1490 const double length = connection_cost.cost;
1491 bool could_connect;
1492 {
1493 // cp1, cp2 sorted CCW.
1494 ContourIntersectionPoint *cp_low = connection_cost.reversed ? cp2 : cp1;
1495 ContourIntersectionPoint *cp_high = connection_cost.reversed ? cp1 : cp2;
1496 assert(std::abs(length - closed_contour_distance_ccw(cp_low->param, cp_high->param, graph.boundary_params[cp1->contour_idx].back())) < SCALED_EPSILON);
1497 could_connect = ! cp_low->next_trimmed && ! cp_high->prev_trimmed;
1498 if (could_connect && cp_low->next_on_contour != cp_high) {
1499 // Other end of cp1, may or may not be on the same contour as cp1.
1500 const ContourIntersectionPoint *cp1prev = cp1 - 1;
1501 // Other end of cp2, may or may not be on the same contour as cp2.
1502 const ContourIntersectionPoint *cp2next = cp2 + 1;
1503 for (auto *cp = cp_low->next_on_contour; cp != cp_high; cp = cp->next_on_contour)
1504 if (cp->consumed || cp == cp1prev || cp == cp2next || cp->prev_trimmed || cp->next_trimmed) {
1505 could_connect = false;
1506 break;
1507 }
1508 }
1509 }
1510 // Indices of the polylines to be connected by a perimeter segment.
1511 size_t idx_first = connection_cost.idx_first;
1512 size_t idx_second = idx_first + 1;
1513 idx_first = get_and_update_merged_with(idx_first);
1514 assert(idx_first < idx_second);
1515 assert(idx_second == merged_with[idx_second]);
1516 if (could_connect && length < anchor_length_max) {
1517 // Take the complete contour.
1518 // Connect the two polygons using the boundary contour.
1519 take(infill_ordered[idx_first], infill_ordered[idx_second], graph.boundary[cp1->contour_idx], cp1, cp2, connection_cost.reversed);
1520 // Mark the second polygon as merged with the first one.
1521 merged_with[idx_second] = merged_with[idx_first];
1522 infill_ordered[idx_second].points.clear();
1523 } else {
1524 // Try to connect cp1 resp. cp2 with a piece of perimeter line.
1525 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);
1526 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);
1527 }
1528 }
1529#endif
1530
1531 struct Arc {
1532 ContourIntersectionPoint *intersection;
1533 double arc_length;
1534 };
1535 std::vector<Arc> arches;
1536 arches.reserve(graph.map_infill_end_point_to_boundary.size());
1537 for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary)
1538 if (cp.contour_idx != boundary_idx_unconnected && cp.next_on_contour != &cp && cp.could_connect_next())
1539 arches.push_back({ &cp, path_length_along_contour_ccw(&cp, cp.next_on_contour, graph.boundary_params[cp.contour_idx].back()) });
1540 std::sort(arches.begin(), arches.end(), [](const auto &l, const auto &r) { return l.arc_length < r.arc_length; });
1541
1542 //FIXME improve the Traveling Salesman problem with 2-opt and 3-opt local optimization.
1543 for (Arc &arc : arches)
1544 if (! arc.intersection->consumed && ! arc.intersection->next_on_contour->consumed) {
1545 // Indices of the polylines to be connected by a perimeter segment.
1546 ContourIntersectionPoint *cp1 = arc.intersection;
1547 ContourIntersectionPoint *cp2 = arc.intersection->next_on_contour;
1548 size_t polyline_idx1 = get_and_update_merged_with(((cp1 - graph.map_infill_end_point_to_boundary.data()) / 2));
1549 size_t polyline_idx2 = get_and_update_merged_with(((cp2 - graph.map_infill_end_point_to_boundary.data()) / 2));
1550 const Points &contour = graph.boundary[cp1->contour_idx];
1551 const std::vector<double> &contour_params = graph.boundary_params[cp1->contour_idx];
1552 if (polyline_idx1 != polyline_idx2) {
1553 Polyline &polyline1 = infill_ordered[polyline_idx1];
1554 Polyline &polyline2 = infill_ordered[polyline_idx2];
1555 if (arc.arc_length < anchor_length_max) {
1556 // Not closing a loop, connecting the lines.
1557 assert(contour[cp1->point_idx] == polyline1.points.front() || contour[cp1->point_idx] == polyline1.points.back());
1558 if (contour[cp1->point_idx] == polyline1.points.front())
1559 polyline1.reverse();
1560 assert(contour[cp2->point_idx] == polyline2.points.front() || contour[cp2->point_idx] == polyline2.points.back());
1561 if (contour[cp2->point_idx] == polyline2.points.back())
1562 polyline2.reverse();
1563 take(polyline1, polyline2, contour, cp1, cp2, false);
1564 // Mark the second polygon as merged with the first one.
1565 if (polyline_idx2 < polyline_idx1) {
1566 polyline2 = std::move(polyline1);
1567 polyline1.points.clear();
1568 merged_with[polyline_idx1] = merged_with[polyline_idx2];
1569 } else {
1570 polyline2.points.clear();
1571 merged_with[polyline_idx2] = merged_with[polyline_idx1];
1572 }
1573 } else if (anchor_length > SCALED_EPSILON) {
1574 // Move along the perimeter, but don't take the whole arc.
1575 take_limited(polyline1, contour, contour_params, cp1, cp2, false, anchor_length, line_half_width);
1576 take_limited(polyline2, contour, contour_params, cp2, cp1, true, anchor_length, line_half_width);
1577 }
1578 }
1579 }
1580
1581 // Connect the remaining open infill lines to the perimeter lines if possible.
1582 for (ContourIntersectionPoint &contour_point : graph.map_infill_end_point_to_boundary)
1583 if (! contour_point.consumed && contour_point.contour_idx != boundary_idx_unconnected) {
1584 const Points &contour = graph.boundary[contour_point.contour_idx];
1585 const std::vector<double> &contour_params = graph.boundary_params[contour_point.contour_idx];
1586
1587 double lprev = contour_point.could_connect_prev() ?
1588 path_length_along_contour_ccw(contour_point.prev_on_contour, &contour_point, contour_params.back()) :
1589 std::numeric_limits<double>::max();
1590 double lnext = contour_point.could_connect_next() ?
1591 path_length_along_contour_ccw(&contour_point, contour_point.next_on_contour, contour_params.back()) :
1592 std::numeric_limits<double>::max();
1593 size_t polyline_idx = get_and_update_merged_with(((&contour_point - graph.map_infill_end_point_to_boundary.data()) / 2));
1594 Polyline &polyline = infill_ordered[polyline_idx];
1595 assert(! polyline.empty());
1596 assert(contour[contour_point.point_idx] == polyline.points.front() || contour[contour_point.point_idx] == polyline.points.back());
1597 bool connected = false;
1598 for (double l : { std::min(lprev, lnext), std::max(lprev, lnext) }) {
1599 if (l == std::numeric_limits<double>::max() || l > anchor_length_max)
1600 break;
1601 // Take the complete contour.
1602 bool reversed = l == lprev;
1603 ContourIntersectionPoint *cp2 = reversed ? contour_point.prev_on_contour : contour_point.next_on_contour;
1604 // Identify which end of the polyline touches the boundary.
1605 size_t polyline_idx2 = get_and_update_merged_with(((cp2 - graph.map_infill_end_point_to_boundary.data()) / 2));
1606 if (polyline_idx == polyline_idx2)
1607 // Try the other side.
1608 continue;
1609 // Not closing a loop.
1610 if (contour[contour_point.point_idx] == polyline.points.front())
1611 polyline.reverse();
1612 Polyline &polyline2 = infill_ordered[polyline_idx2];
1613 assert(! polyline.empty());
1614 assert(contour[cp2->point_idx] == polyline2.points.front() || contour[cp2->point_idx] == polyline2.points.back());
1615 if (contour[cp2->point_idx] == polyline2.points.back())
1616 polyline2.reverse();
1617 take(polyline, polyline2, contour, &contour_point, cp2, reversed);
1618 if (polyline_idx < polyline_idx2) {
1619 // Mark the second polyline as merged with the first one.
1620 merged_with[polyline_idx2] = polyline_idx;
1621 polyline2.points.clear();
1622 } else {
1623 // Mark the first polyline as merged with the second one.
1624 merged_with[polyline_idx] = polyline_idx2;
1625 polyline2 = std::move(polyline);
1626 polyline.points.clear();
1627 }
1628 connected = true;
1629 break;
1630 }
1631 if (! connected && anchor_length > SCALED_EPSILON) {
1632 // Which to take? One could optimize for:
1633 // 1) Shortest path
1634 // 2) Hook length
1635 // ...
1636 // Let's take the longer now, as this improves the chance of another hook to be placed on the other side of this contour point.
1637 double l = std::max(contour_point.contour_not_taken_length_prev, contour_point.contour_not_taken_length_next);
1638 if (l > SCALED_EPSILON) {
1639 if (contour_point.contour_not_taken_length_prev > contour_point.contour_not_taken_length_next)
1640 take_limited(polyline, contour, contour_params, &contour_point, contour_point.prev_on_contour, true, anchor_length, line_half_width);
1641 else
1642 take_limited(polyline, contour, contour_params, &contour_point, contour_point.next_on_contour, false, anchor_length, line_half_width);
1643 }
1644 }
1645 }
1646
1647 polylines_out.reserve(polylines_out.size() + std::count_if(infill_ordered.begin(), infill_ordered.end(), [](const Polyline &pl) { return ! pl.empty(); }));
1648 for (Polyline &pl : infill_ordered)
1649 if (! pl.empty())
1650 polylines_out.emplace_back(std::move(pl));
1651}
LNODEID lprev(LNODEID)
Definition lists.c:712
LNODEID lnext(LNODEID)
Definition lists.c:704
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC half() max(const half &a, const half &b)
Definition Half.h:516
const Point & contour_point(const VD::cell_type &cell, const Line &line)
Definition VoronoiOffset.hpp:16
static double closed_contour_distance_ccw(double param1, double param2, double contour_length)
Definition FillBase.cpp:227
double length(const Points &pts)
Definition MultiPoint.hpp:116
std::pair< double, double > path_lengths_along_contour(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, double contour_length)
Definition FillBase.cpp:254
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:110

References Slic3r::FillParams::anchor_length, Slic3r::FillParams::anchor_length_max, Slic3r::append(), Slic3r::BoundaryInfillGraph::boundary, Slic3r::boundary_idx_unconnected, Slic3r::BoundaryInfillGraph::boundary_params, Slic3r::closed_contour_distance_ccw(), Slic3r::ContourIntersectionPoint::consumed, Slic3r::ContourIntersectionPoint::contour_idx, Slic3r::create_boundary_infill_graph(), Slic3r::FillParams::density, Slic3r::intersection(), Slic3r::length(), Slic3r::BoundaryInfillGraph::map_infill_end_point_to_boundary, 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::prev_trimmed, scale_, SCALED_EPSILON, spacing, Slic3r::take(), and Slic3r::take_limited().

+ Here is the call graph for this function:

◆ fill_surface()

Polylines Slic3r::Fill::fill_surface ( const Surface surface,
const FillParams params 
)
virtual

Reimplemented in Slic3r::FillEnsuring, Slic3r::FillRectilinear, Slic3r::FillMonotonic, Slic3r::FillMonotonicLines, Slic3r::FillGrid, Slic3r::FillTriangles, Slic3r::FillStars, Slic3r::FillCubic, and Slic3r::FillSupportBase.

85{
86 // Perform offset.
87 Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing)));
88 // Create the infills for each of the regions.
89 Polylines polylines_out;
90 for (ExPolygon &expoly : expp)
91 _fill_surface_single(params, surface->thickness_layers, _infill_direction(surface), std::move(expoly), polylines_out);
92 return polylines_out;
93}
virtual std::pair< float, Point > _infill_direction(const Surface *surface) const
Definition FillBase.cpp:131
virtual void _fill_surface_single(const FillParams &, unsigned int, const std::pair< float, Point > &, ExPolygon, Polylines &)
Definition FillBase.hpp:134
std::vector< Polyline > Polylines
Definition Polyline.hpp:14
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:13
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:421

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

Referenced by Slic3r::FFFSupport::fill_expolygon_generate_paths().

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

◆ fill_surface_arachne()

ThickPolylines Slic3r::Fill::fill_surface_arachne ( const Surface surface,
const FillParams params 
)
virtual

Reimplemented in Slic3r::FillEnsuring.

96{
97 // Perform offset.
98 Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(this->overlap - 0.5 * this->spacing)));
99 // Create the infills for each of the regions.
100 ThickPolylines thick_polylines_out;
101 for (ExPolygon &expoly : expp)
102 _fill_surface_single(params, surface->thickness_layers, _infill_direction(surface), std::move(expoly), thick_polylines_out);
103 return thick_polylines_out;
104}
std::vector< ThickPolyline > ThickPolylines
Definition Polyline.hpp:15

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

+ Here is the call graph for this function:

◆ new_from_type() [1/2]

Fill * Slic3r::Fill::new_from_type ( const InfillPattern  type)
static
32{
33 switch (type) {
34 case ipConcentric: return new FillConcentric();
35 case ipHoneycomb: return new FillHoneycomb();
36 case ip3DHoneycomb: return new Fill3DHoneycomb();
37 case ipGyroid: return new FillGyroid();
38 case ipRectilinear: return new FillRectilinear();
39 case ipAlignedRectilinear: return new FillAlignedRectilinear();
40 case ipMonotonic: return new FillMonotonic();
41 case ipMonotonicLines: return new FillMonotonicLines();
42 case ipLine: return new FillLine();
43 case ipGrid: return new FillGrid();
44 case ipTriangles: return new FillTriangles();
45 case ipStars: return new FillStars();
46 case ipCubic: return new FillCubic();
47 case ipArchimedeanChords: return new FillArchimedeanChords();
48 case ipHilbertCurve: return new FillHilbertCurve();
49 case ipOctagramSpiral: return new FillOctagramSpiral();
50 case ipAdaptiveCubic: return new FillAdaptive::Filler();
51 case ipSupportCubic: return new FillAdaptive::Filler();
52 case ipSupportBase: return new FillSupportBase();
53 case ipLightning: return new FillLightning::Filler();
54 case ipEnsuring: return new FillEnsuring();
55 default: throw Slic3r::InvalidArgument("unknown type");
56 }
57}
@ ipStars
Definition PrintConfig.hpp:61
@ ipHilbertCurve
Definition PrintConfig.hpp:62
@ ipGrid
Definition PrintConfig.hpp:61
@ ipArchimedeanChords
Definition PrintConfig.hpp:62
@ ipConcentric
Definition PrintConfig.hpp:61
@ ipAlignedRectilinear
Definition PrintConfig.hpp:61
@ ipMonotonic
Definition PrintConfig.hpp:61
@ ipEnsuring
Definition PrintConfig.hpp:64
@ ip3DHoneycomb
Definition PrintConfig.hpp:61
@ ipAdaptiveCubic
Definition PrintConfig.hpp:62
@ ipMonotonicLines
Definition PrintConfig.hpp:61
@ ipLine
Definition PrintConfig.hpp:61
@ ipHoneycomb
Definition PrintConfig.hpp:61
@ ipCubic
Definition PrintConfig.hpp:61
@ ipOctagramSpiral
Definition PrintConfig.hpp:62
@ ipTriangles
Definition PrintConfig.hpp:61
@ ipSupportCubic
Definition PrintConfig.hpp:62
@ ipRectilinear
Definition PrintConfig.hpp:61
@ ipGyroid
Definition PrintConfig.hpp:62
@ ipSupportBase
Definition PrintConfig.hpp:62
@ ipLightning
Definition PrintConfig.hpp:63

References Slic3r::ip3DHoneycomb, Slic3r::ipAdaptiveCubic, Slic3r::ipAlignedRectilinear, Slic3r::ipArchimedeanChords, Slic3r::ipConcentric, Slic3r::ipCubic, Slic3r::ipEnsuring, Slic3r::ipGrid, Slic3r::ipGyroid, Slic3r::ipHilbertCurve, Slic3r::ipHoneycomb, Slic3r::ipLightning, Slic3r::ipLine, Slic3r::ipMonotonic, Slic3r::ipMonotonicLines, Slic3r::ipOctagramSpiral, Slic3r::ipRectilinear, Slic3r::ipStars, Slic3r::ipSupportBase, Slic3r::ipSupportCubic, and Slic3r::ipTriangles.

Referenced by Slic3r::WipeTower::finish_layer(), Slic3r::FFFTreeSupport::generate_support_infill_lines(), new_from_type(), and use_bridge_flow().

+ Here is the caller graph for this function:

◆ new_from_type() [2/2]

Fill * Slic3r::Fill::new_from_type ( const std::string &  type)
static
60{
62 t_config_enum_values::const_iterator it = enum_keys_map.find(type);
63 return (it == enum_keys_map.end()) ? nullptr : new_from_type(InfillPattern(it->second));
64}
static const t_config_enum_values & get_enum_values()
static Fill * new_from_type(const InfillPattern type)
Definition FillBase.cpp:31
InfillPattern
Definition PrintConfig.hpp:60
std::map< std::string, int > t_config_enum_values
Definition Config.hpp:1497

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

+ Here is the call graph for this function:

◆ no_sort()

virtual bool Slic3r::Fill::no_sort ( ) const
inlinevirtual

◆ set_bounding_box()

void Slic3r::Fill::set_bounding_box ( const Slic3r::BoundingBox bbox)
inline
106{ bounding_box = bbox; }

References bounding_box.

Referenced by Slic3r::Layer::make_ironing().

+ Here is the caller graph for this function:

◆ use_bridge_flow() [1/2]

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

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

109{ return false; }

Referenced by Slic3r::group_fills().

+ Here is the caller graph for this function:

◆ use_bridge_flow() [2/2]

bool Slic3r::Fill::use_bridge_flow ( const InfillPattern  type)
static
71{
72 static std::vector<unsigned char> cached;
73 if (cached.empty()) {
74 cached.assign(size_t(ipCount), 0);
75 for (size_t i = 0; i < cached.size(); ++ i) {
76 auto *fill = Fill::new_from_type((InfillPattern)i);
77 cached[i] = fill->use_bridge_flow();
78 delete fill;
79 }
80 }
81 return cached[type] != 0;
82}
@ ipCount
Definition PrintConfig.hpp:65

References Slic3r::ipCount, and new_from_type().

+ Here is the call graph for this function:

Member Data Documentation

◆ adapt_fill_octree

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

◆ angle

◆ bounding_box

◆ layer_id

◆ link_max_length

◆ loop_clipping

◆ overlap

◆ print_config

const PrintConfig* Slic3r::Fill::print_config = nullptr

◆ print_object_config

const PrintObjectConfig* Slic3r::Fill::print_object_config = nullptr

◆ spacing

◆ z


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