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
|
#include "../ClipperUtils.hpp"
#include "../ExtrusionEntityCollection.hpp"
#include "../Surface.hpp"
#include <cmath>
#include <algorithm>
#include <iostream>
#include "FillSmooth.hpp"
namespace Slic3r {
Polylines FillSmooth::fill_surface(const Surface *surface, const FillParams ¶ms) const
{
//ERROR: you shouldn't call that. Default to the rectilinear one.
printf("FillSmooth::fill_surface() : you call the wrong method (fill_surface instead of fill_surface_extrusion).\n");
Polylines polylines_out;
return polylines_out;
}
/// @idx: the index of the step (0 = first step, 1 = second step, ...) The first lay down the volume and the others smoothen the surface.
void FillSmooth::perform_single_fill(const int idx, ExtrusionEntityCollection &eecroot, const Surface &srf_source,
const FillParams ¶ms) const {
if (srf_source.expolygon.empty()) return;
// Save into layer smoothing path.
ExtrusionEntityCollection *eec = new ExtrusionEntityCollection();
eec->set_can_sort_reverse(!params.monotonic, !params.monotonic);
FillParams params_modifided = params;
if (params.config != NULL && idx > 0) params_modifided.density /= (float)params.config->fill_smooth_width.get_abs_value(1);
else if (params.config != NULL && idx == 0) params_modifided.density *= 1;
else params_modifided.density *= (float)percentWidth[idx];
// reduce flow for each increase in density
params_modifided.flow_mult *= params.density;
params_modifided.flow_mult /= params_modifided.density;
// split the flow between steps
if (params.config != NULL && idx > 0) params_modifided.flow_mult *= (float)params.config->fill_smooth_distribution.get_abs_value(1);
else if (params.config != NULL && idx == 0) params_modifided.flow_mult *= (1.f - (float)params.config->fill_smooth_distribution.get_abs_value(1));
else params_modifided.flow_mult *= (float)percentFlow[idx];
//set role
if (rolePass[idx] != erNone)
params_modifided.role = rolePass[idx];
//choose if we are going to extrude with or without overlap
if ((params.flow.bridge && idx == 0) || has_overlap[idx] || this->no_overlap_expolygons.empty()){
this->fill_expolygon(idx, *eec, srf_source, params_modifided);
}
else{
Surface surfaceNoOverlap(srf_source);
//use half overlap instead of none.
ExPolygons half_overlap = offset_ex(this->no_overlap_expolygons, scale_(this->overlap / 2));
half_overlap = intersection_ex({ srf_source.expolygon }, half_overlap);
for (const ExPolygon &poly : half_overlap) {
if (poly.empty()) continue;
surfaceNoOverlap.expolygon = poly;
this->fill_expolygon(idx, *eec, surfaceNoOverlap, params_modifided);
}
}
if (eec->entities.empty()) delete eec;
else eecroot.entities.push_back(eec);
}
void FillSmooth::fill_expolygon(const int idx, ExtrusionEntityCollection &eec, const Surface &srf_to_fill,
const FillParams ¶ms_init) const {
FillParams params = params_init;
std::unique_ptr<Fill> f2 = std::unique_ptr<Fill>(Fill::new_from_type(fillPattern[idx]));
f2->bounding_box = this->bounding_box;
f2->init_spacing(this->get_spacing(), params);
f2->layer_id = this->layer_id;
f2->z = this->z;
f2->angle = anglePass[idx] + this->angle;
// Maximum length of the perimeter segment linking two infill lines.
f2->link_max_length = this->link_max_length;
// Used by the concentric infill pattern to clip the loops to create extrusion paths.
f2->loop_clipping = this->loop_clipping;
Polylines polylines_layer = f2->fill_surface(&srf_to_fill, params);
if (!polylines_layer.empty()) {
//get the role
ExtrusionRole good_role = params.role;
if (good_role == erNone || good_role == erCustom) {
good_role = params.flow.bridge && idx == 0 ? erBridgeInfill : rolePass[idx];
}
//get the flow
float mult_flow = 1;
if (params.fill_exactly && idx == 0) {
// compute the volume to extrude
double volume_to_occupy = compute_unscaled_volume_to_fill(&srf_to_fill, params);
//compute the path of the nozzle
double length_tot = 0;
int nb_lines = 0;
for (Polyline& pline : polylines_layer) {
Lines lines = pline.lines();
for (Line& line : lines) {
length_tot += unscaled(line.length());
nb_lines++;
}
}
//compute flow to remove spacing_ratio from the equation
double extruded_volume = 0;
if (params.flow.spacing_ratio < 1.f && !params.flow.bridge) {
// the spacing is larger than usual. get the flow from the current spacing
Flow test_flow = Flow::new_from_spacing(params.flow.spacing(), params.flow.nozzle_diameter, params.flow.height, 1, params.flow.bridge);
extruded_volume = test_flow.mm3_per_mm() * length_tot / params.density;
} else
extruded_volume = params.flow.mm3_per_mm() * length_tot / params.density;
if (extruded_volume == 0) extruded_volume = volume_to_occupy;
// print
mult_flow = (float)std::min(2., volume_to_occupy / extruded_volume);
BOOST_LOG_TRIVIAL(info) << "Layer " << layer_id << " Ironing process " << idx << " extrude " << extruded_volume << " mm3 for a volume of " << volume_to_occupy << " mm3 : we mult the flow by " << mult_flow;
}
extrusion_entities_append_paths(
eec.entities, std::move(polylines_layer),
good_role,
params.flow.mm3_per_mm() * params.flow_mult * mult_flow,
//min-reduced flow width for a better view (it's mostly a gui thing, but some support code can want to mess with it)
(float)(params.flow.width * (params.flow_mult* mult_flow < 0.1 ? 0.1 : params.flow_mult * mult_flow)), (float)params.flow.height);
}
}
void FillSmooth::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const
{
coordf_t init_spacing = this->get_spacing();
//create root node
ExtrusionEntityCollection *eecroot = new ExtrusionEntityCollection();
//you don't want to sort the extrusions: big infill first, small second
eecroot->set_can_sort_reverse(false, false);
// first infill
FillParams first_pass_params = params;
//if(first_pass_params.role != ExtrusionRole::erSupportMaterial && first_pass_params.role != ExtrusionRole::erSupportMaterialInterface)
//s first_pass_params.role = ExtrusionRole::erSolidInfill;
perform_single_fill(0, *eecroot, *surface, first_pass_params);
//use monotonic for ironing pass
FillParams monotonic_params = params;
monotonic_params.monotonic = true;
//second infill
if (nbPass > 1){
perform_single_fill(1, *eecroot, *surface, monotonic_params);
}
// third infill
if (nbPass > 2){
perform_single_fill(2, *eecroot, *surface, monotonic_params);
}
if (!eecroot->entities.empty())
out.push_back(eecroot);
else delete eecroot;
}
} // namespace Slic3r
|