1 //Copyright (C) 2019 Ultimaker B.V.
2 //CuraEngine is released under the terms of the AGPLv3 or higher.
3
4 #include <iterator>
5 #include <algorithm>
6 #include <cmath>
7 #include <limits>
8
9 #include "AdaptiveLayerHeights.h"
10 #include "EnumSettings.h"
11 #include "types/AngleRadians.h"
12 #include "../Application.h"
13 #include "../Slice.h"
14 #include "../utils/floatpoint.h"
15
16 namespace cura
17 {
18
AdaptiveLayer(const coord_t layer_height)19 AdaptiveLayer::AdaptiveLayer(const coord_t layer_height) : layer_height(layer_height) { }
20
AdaptiveLayerHeights(const coord_t base_layer_height,const coord_t variation,const coord_t step_size,const coord_t threshold)21 AdaptiveLayerHeights::AdaptiveLayerHeights(const coord_t base_layer_height, const coord_t variation,
22 const coord_t step_size, const coord_t threshold)
23 : base_layer_height(base_layer_height)
24 , max_variation(variation)
25 , step_size(step_size)
26 , threshold(threshold)
27 {
28 layers = {};
29
30 calculateAllowedLayerHeights();
31 calculateMeshTriangleSlopes();
32 calculateLayers();
33 }
34
getLayerCount()35 int AdaptiveLayerHeights::getLayerCount()
36 {
37 return layers.size();
38 }
39
getLayers()40 std::vector<AdaptiveLayer>* AdaptiveLayerHeights::getLayers()
41 {
42 return &layers;
43 }
44
calculateAllowedLayerHeights()45 void AdaptiveLayerHeights::calculateAllowedLayerHeights()
46 {
47 // calculate the allowed layer heights from variation and step size
48 // note: the order is from thickest to thinnest height!
49 for (int allowed_layer_height = base_layer_height + max_variation; allowed_layer_height >= base_layer_height - max_variation; allowed_layer_height -= step_size)
50 {
51 // we should only consider using layer_heights that are > 0
52 if (allowed_layer_height <= 0)
53 {
54 break;
55 }
56 allowed_layer_heights.push_back(allowed_layer_height);
57 }
58 }
59
calculateLayers()60 void AdaptiveLayerHeights::calculateLayers()
61 {
62 const coord_t minimum_layer_height = *std::min_element(allowed_layer_heights.begin(), allowed_layer_heights.end());
63 Settings& mesh_group_settings = Application::getInstance().current_slice->scene.current_mesh_group->settings;
64 SlicingTolerance slicing_tolerance = mesh_group_settings.get<SlicingTolerance>("slicing_tolerance");
65 std::vector<size_t> triangles_of_interest;
66 coord_t z_level = 0;
67 coord_t previous_layer_height = 0;
68
69 // the first layer has it's own independent height set, so we always add that
70 const coord_t initial_layer_height = mesh_group_settings.get<coord_t>("layer_height_0");
71 z_level += initial_layer_height;
72
73 AdaptiveLayer adaptive_layer(initial_layer_height);
74 adaptive_layer.z_position = z_level;
75 previous_layer_height = adaptive_layer.layer_height;
76 layers.push_back(adaptive_layer);
77
78 // loop while triangles are found
79 while (!triangles_of_interest.empty() || layers.size() < 2)
80 {
81 double global_min_slope = std::numeric_limits<double>::max();
82 int layer_height_for_global_min_slope = 0;
83 // loop over all allowed layer heights starting with the largest
84 bool has_added_layer = false;
85 for (auto & layer_height : allowed_layer_heights)
86 {
87 // use lower and upper bounds to filter on triangles that are interesting for this potential layer
88 const coord_t lower_bound = z_level;
89 // if slicing tolerance "middle" is used, a layer is interpreted as the middle of the upper and lower bounds.
90 const coord_t upper_bound = z_level + ((slicing_tolerance == SlicingTolerance::MIDDLE) ? (layer_height / 2) : layer_height);
91
92 if (layer_height == allowed_layer_heights[0])
93 {
94 // this is the max layer thickness, search through all of the triangles in the mesh to find those
95 // that intersect with a layer this thick
96 triangles_of_interest.clear();
97
98 for (size_t i = 0; i < face_min_z_values.size(); ++i)
99 {
100 if (face_min_z_values[i] <= upper_bound && face_max_z_values[i] >= lower_bound)
101 {
102 triangles_of_interest.push_back(i);
103 }
104 }
105 }
106 else
107 {
108 // this is a reduced thickness layer, just search those triangles that intersected with the layer
109 // in the previous iteration
110 std::vector<size_t> last_triangles_of_interest = triangles_of_interest;
111
112 triangles_of_interest.clear();
113
114 for (size_t i : last_triangles_of_interest)
115 {
116 if (face_min_z_values[i] <= upper_bound)
117 {
118 triangles_of_interest.push_back(i);
119 }
120 }
121 }
122
123 // when there not interesting triangles in this potential layer go to the next one
124 if (triangles_of_interest.empty())
125 {
126 break;
127 }
128
129 // find the minimum slope of all the interesting triangles
130 double minimum_slope = std::numeric_limits<double>::max();
131 for (const int& triangle_index : triangles_of_interest)
132 {
133 const double slope = face_slopes.at(triangle_index);
134 if (minimum_slope > slope)
135 {
136 minimum_slope = slope;
137 }
138 }
139 if (global_min_slope > minimum_slope)
140 {
141 global_min_slope = minimum_slope;
142 layer_height_for_global_min_slope = layer_height;
143 }
144
145 // check if the maximum step size has been exceeded depending on layer height direction
146 bool has_exceeded_step_size = false;
147 if (previous_layer_height > layer_height && previous_layer_height - layer_height > step_size)
148 {
149 has_exceeded_step_size = true;
150 }
151 else if (layer_height - previous_layer_height > step_size && layer_height > minimum_layer_height)
152 {
153 continue;
154 }
155
156 // we add the layer in the following cases:
157 // 1) the layer angle is below the threshold and the layer height difference with the previous layer is the maximum allowed step size
158 // 2) the layer height is the smallest it is allowed
159 // 3) the layer is a flat surface (we can't divide by 0)
160 const double minimum_slope_tan = std::tan(minimum_slope);
161 if (minimum_slope_tan == 0.0
162 || (layer_height / minimum_slope_tan) <= threshold
163 || layer_height == minimum_layer_height
164 || has_exceeded_step_size)
165 {
166 z_level += layer_height;
167 AdaptiveLayer adaptive_layer(layer_height);
168 adaptive_layer.z_position = z_level;
169 previous_layer_height = adaptive_layer.layer_height;
170 layers.push_back(adaptive_layer);
171 has_added_layer = true;
172 break;
173 }
174 }
175
176 // stop calculating when we're out of triangles (e.g. above the mesh)
177 if (triangles_of_interest.empty())
178 {
179 break;
180 }
181 // this means we cannot find a layer height that has an angle lower than the threshold.
182 // in this case, we use the layer height with the lowest
183 if (!has_added_layer)
184 {
185 z_level += layer_height_for_global_min_slope;
186 AdaptiveLayer adaptive_layer(layer_height_for_global_min_slope);
187 adaptive_layer.z_position = z_level;
188 previous_layer_height = adaptive_layer.layer_height;
189 layers.push_back(adaptive_layer);
190 }
191 }
192 }
193
calculateMeshTriangleSlopes()194 void AdaptiveLayerHeights::calculateMeshTriangleSlopes()
195 {
196 // loop over all mesh faces (triangles) and find their slopes
197 for (const Mesh& mesh : Application::getInstance().current_slice->scene.current_mesh_group->meshes)
198 {
199 // Skip meshes that are not printable
200 if (mesh.settings.get<bool>("infill_mesh") || mesh.settings.get<bool>("cutting_mesh") || mesh.settings.get<bool>("anti_overhang_mesh"))
201 {
202 continue;
203 }
204
205 for (const MeshFace& face : mesh.faces)
206 {
207 const MeshVertex& v0 = mesh.vertices[face.vertex_index[0]];
208 const MeshVertex& v1 = mesh.vertices[face.vertex_index[1]];
209 const MeshVertex& v2 = mesh.vertices[face.vertex_index[2]];
210
211 const FPoint3 p0 = v0.p;
212 const FPoint3 p1 = v1.p;
213 const FPoint3 p2 = v2.p;
214
215 float min_z = p0.z;
216 min_z = std::min(min_z, p1.z);
217 min_z = std::min(min_z, p2.z);
218 float max_z = p0.z;
219 max_z = std::max(max_z, p1.z);
220 max_z = std::max(max_z, p2.z);
221
222 // calculate the angle of this triangle in the z direction
223 const FPoint3 n = FPoint3(p1 - p0).cross(p2 - p0);
224 const FPoint3 normal = n.normalized();
225 AngleRadians z_angle = std::acos(std::abs(normal.z));
226
227 // prevent flat surfaces from influencing the algorithm
228 if (z_angle == 0)
229 {
230 z_angle = M_PI;
231 }
232
233 face_min_z_values.push_back(min_z * 1000);
234 face_max_z_values.push_back(max_z * 1000);
235 face_slopes.push_back(z_angle);
236 }
237 }
238 }
239
240 }