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 }