1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
#ifndef slic3r_FillBase_hpp_
#define slic3r_FillBase_hpp_
#include <assert.h>
#include <memory.h>
#include <float.h>
#include <stdint.h>
#include <stdexcept>
#include <type_traits>
#include <boost/log/trivial.hpp>
#include "../libslic3r.h"
#include "../BoundingBox.hpp"
#include "../PrintConfig.hpp"
#include "../Exception.hpp"
#include "../Utils.hpp"
#include "../Flow.hpp"
#include "../ExtrusionEntity.hpp"
#include "../ExtrusionEntityCollection.hpp"
namespace Slic3r {
class ExPolygon;
class Surface;
namespace FillAdaptive {
struct Octree;
};
// Infill shall never fail, therefore the error is classified as RuntimeError, not SlicingError.
class InfillFailedException : public Slic3r::RuntimeError {
public:
InfillFailedException() : Slic3r::RuntimeError("Infill failed") {}
};
struct FillParams
{
// Allways consider bridge as full infill, whatever the density is.
bool full_infill() const { return flow.bridge || (density > 0.9999f && density < 1.0001f); }
// Don't connect the fill lines around the inner perimeter.
bool dont_connect() const { return connection == InfillConnection::icNotConnected; }
// Fill density, fraction in <0, 1>
float density { 0.f };
// Fill extruding flow multiplier, fraction in <0, 1>. Used by "over bridge compensation"
float flow_mult { 1.0f };
// Don't connect the fill lines around the inner perimeter.
InfillConnection connection{ icConnected };
// Length of an infill anchor along the perimeter.
// 1000mm is roughly the maximum length line that fits into a 32bit coord_t.
float anchor_length { 1000.f };
float anchor_length_max { 1000.f };
// Don't adjust spacing to fill the space evenly.
bool dont_adjust { true };
// Monotonic infill - strictly left to right for better surface quality of top infills.
bool monotonic { false };
// Try to extrude the exact amount of plastic to fill the volume requested
bool fill_exactly{ false };
// For Honeycomb.
// we were requested to complete each loop;
// in this case we don't try to make more continuous paths
bool complete { false };
// if role == erNone or ERCustom, this method have to choose the best role itself, else it must use the argument's role.
ExtrusionRole role { erNone };
// flow to use
Flow flow = Flow(0.f, 0.f, 0.f, 1.f, false);
// to order the fills by priority
int32_t priority = 0;
//full configuration for the region, to avoid copying every bit that is needed. Use this for process-specific parameters.
PrintRegionConfig const *config{ nullptr };
};
static_assert(IsTriviallyCopyable<FillParams>::value, "FillParams class is not POD (and it should be - see constructor).");
class Fill
{
public:
// Index of the layer.
size_t layer_id;
// Z coordinate of the top print surface, in unscaled coordinates
double z;
// infill / perimeter overlap, in unscaled coordinates
double overlap;
ExPolygons no_overlap_expolygons;
// in radians, ccw, 0 = East
float angle;
// In scaled coordinates. Maximum lenght of a perimeter segment connecting two infill lines.
// Used by the FillRectilinear2, FillGrid2, FillTriangles, FillStars and FillCubic.
// If left to zero, the links will not be limited.
coord_t link_max_length;
// In scaled coordinates. Used by the concentric infill pattern to clip the loops to create extrusion paths.
coord_t loop_clipping;
// In scaled coordinates. Bounding box of the 2D projection of the object.
BoundingBox bounding_box;
// Octree builds on mesh for usage in the adaptive cubic infill
FillAdaptive::Octree* adapt_fill_octree = nullptr;
protected:
// in unscaled coordinates, please use init (after settings all others settings) as some algos want to modify the value
coordf_t spacing_priv;
public:
virtual ~Fill() {}
virtual Fill* clone() const = 0;
static Fill* new_from_type(const InfillPattern type);
static Fill* new_from_type(const std::string &type);
void set_bounding_box(const Slic3r::BoundingBox &bbox) { bounding_box = bbox; }
virtual void init_spacing(coordf_t spacing, const FillParams ¶ms) { this->spacing_priv = spacing; }
coordf_t get_spacing() const { return spacing_priv; }
// Do not sort the fill lines to optimize the print head path?
virtual bool no_sort() const { return false; }
// This method have to fill the ExtrusionEntityCollection. It call fill_surface by default
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const;
// Perform the fill.
virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms) const;
protected:
Fill() :
layer_id(size_t(-1)),
z(0.),
spacing_priv(0.),
// Infill / perimeter overlap.
overlap(0.),
// Initial angle is undefined.
angle(FLT_MAX),
link_max_length(0),
loop_clipping(0),
// The initial bounding box is empty, therefore undefined.
bounding_box(Point(0, 0), Point(-1, -1))
{}
// The expolygon may be modified by the method to avoid a copy.
virtual void _fill_surface_single(
const FillParams & /* params */,
unsigned int /* thickness_layers */,
const std::pair<float, Point> & /* direction */,
ExPolygon /* expolygon */,
Polylines & /* polylines_out */) const {
BOOST_LOG_TRIVIAL(error)<<"Error, the fill isn't implemented";
};
virtual float _layer_angle(size_t idx) const { return (idx & 1) ? float(M_PI/2.) : 0; }
virtual coord_t _line_spacing_for_density(float density) const;
virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;
void do_gap_fill(const ExPolygons& gapfill_areas, const FillParams& params, ExtrusionEntitiesPtr& coll_out) const;
double compute_unscaled_volume_to_fill(const Surface* surface, const FillParams& params) const;
ExtrusionRole getRoleFromSurfaceType(const FillParams ¶ms, const Surface *surface) const {
if (params.role == erNone || params.role == erCustom) {
return params.flow.bridge ?
(surface->has_pos_bottom() ? erBridgeInfill : erInternalBridgeInfill) :
(surface->has_fill_solid() ?
((surface->has_pos_top()) ? erTopSolidInfill : erSolidInfill) :
erInternalInfill);
}
return params.role;
}
public:
static void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params);
//for rectilinear
static void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, const Polygons& polygons_src, Polylines& polylines_out, const double spacing, const FillParams& params);
static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance);
// Align a coordinate to a grid. The coordinate may be negative,
// the aligned value will never be bigger than the original one.
static coord_t _align_to_grid(const coord_t coord, const coord_t spacing) {
// Current C++ standard defines the result of integer division to be rounded to zero,
// for both positive and negative numbers. Here we want to round down for negative
// numbers as well.
coord_t aligned = (coord < 0) ?
((coord - spacing + 1) / spacing) * spacing :
(coord / spacing) * spacing;
assert(aligned <= coord);
return aligned;
}
static Point _align_to_grid(Point coord, Point spacing)
{ return Point(_align_to_grid(coord(0), spacing(0)), _align_to_grid(coord(1), spacing(1))); }
static coord_t _align_to_grid(coord_t coord, coord_t spacing, coord_t base)
{ return base + _align_to_grid(coord - base, spacing); }
static Point _align_to_grid(Point coord, Point spacing, Point base)
{ return Point(_align_to_grid(coord(0), spacing(0), base(0)), _align_to_grid(coord(1), spacing(1), base(1))); }
};
namespace FakePerimeterConnect {
void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params);
void connect_infill(Polylines&& infill_ordered, const Polygons& boundary, const BoundingBox& bbox, Polylines& polylines_out, const double spacing, const FillParams& params);
void connect_infill(Polylines&& infill_ordered, const std::vector<const Polygon*>& boundary, const BoundingBox& bbox, Polylines& polylines_out, double spacing, const FillParams& params);
}
namespace PrusaSimpleConnect {
void connect_infill(Polylines& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params);
}
namespace NaiveConnect {
void connect_infill(Polylines&& infill_ordered, const ExPolygon& boundary, Polylines& polylines_out, const double spacing, const FillParams& params);
}
class ExtrusionSetRole : public ExtrusionVisitor {
ExtrusionRole new_role;
public:
ExtrusionSetRole(ExtrusionRole role) : new_role(role) {}
void use(ExtrusionPath &path) override { path.set_role(new_role); }
void use(ExtrusionPath3D &path3D) override { path3D.set_role(new_role); }
void use(ExtrusionMultiPath &multipath) override { for (ExtrusionPath path : multipath.paths) path.set_role(new_role); }
void use(ExtrusionMultiPath3D &multipath) override { for (ExtrusionPath path : multipath.paths) path.set_role(new_role); }
void use(ExtrusionLoop &loop) override { for (ExtrusionPath path : loop.paths) path.set_role(new_role); }
void use(ExtrusionEntityCollection &collection) override { for (ExtrusionEntity *entity : collection.entities) entity->visit(*this); }
};
} // namespace Slic3r
#endif // slic3r_FillBase_hpp_
|