1 /* ADMesh -- process triangulated solid meshes
2 * Copyright (C) 1995, 1996 Anthony D. Martin <amartin@engr.csulb.edu>
3 * Copyright (C) 2013, 2014 several contributors, see AUTHORS
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Questions, comments, suggestions, etc to
20 * https://github.com/admesh/admesh/issues
21 */
22
23 #ifndef __admesh_stl__
24 #define __admesh_stl__
25
26 #include <stdio.h>
27 #include <stdint.h>
28 #include <stddef.h>
29
30 #include <vector>
31 #include <Eigen/Geometry>
32
33 // Size of the binary STL header, free form.
34 #define LABEL_SIZE 80
35 // Binary STL, length of the "number of faces" counter.
36 #define NUM_FACET_SIZE 4
37 // Binary STL, sizeof header + number of faces.
38 #define HEADER_SIZE 84
39 #define STL_MIN_FILE_SIZE 284
40 #define ASCII_LINES_PER_FACET 7
41
42 typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_vertex;
43 typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_normal;
44 typedef Eigen::Matrix<int, 3, 1, Eigen::DontAlign> stl_triangle_vertex_indices;
45 static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
46 static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
47
48 struct stl_facet {
49 stl_normal normal;
50 stl_vertex vertex[3];
51 char extra[2];
52
rotatedstl_facet53 stl_facet rotated(const Eigen::Quaternion<float, Eigen::DontAlign> &rot) const {
54 stl_facet out;
55 out.normal = rot * this->normal;
56 out.vertex[0] = rot * this->vertex[0];
57 out.vertex[1] = rot * this->vertex[1];
58 out.vertex[2] = rot * this->vertex[2];
59 return out;
60 }
61 };
62
63 #define SIZEOF_STL_FACET 50
64
65 static_assert(offsetof(stl_facet, normal) == 0, "stl_facet.normal has correct offset");
66 static_assert(offsetof(stl_facet, vertex) == 12, "stl_facet.vertex has correct offset");
67 static_assert(offsetof(stl_facet, extra ) == 48, "stl_facet.extra has correct offset");
68 static_assert(sizeof(stl_facet) >= SIZEOF_STL_FACET, "size of stl_facet incorrect");
69
70 typedef enum {binary, ascii, inmemory} stl_type;
71
72 struct stl_neighbors {
stl_neighborsstl_neighbors73 stl_neighbors() { reset(); }
resetstl_neighbors74 void reset() {
75 neighbor[0] = -1;
76 neighbor[1] = -1;
77 neighbor[2] = -1;
78 which_vertex_not[0] = -1;
79 which_vertex_not[1] = -1;
80 which_vertex_not[2] = -1;
81 }
num_neighbors_missingstl_neighbors82 int num_neighbors_missing() const { return (this->neighbor[0] == -1) + (this->neighbor[1] == -1) + (this->neighbor[2] == -1); }
num_neighborsstl_neighbors83 int num_neighbors() const { return 3 - this->num_neighbors_missing(); }
84
85 // Index of a neighbor facet.
86 int neighbor[3];
87 // Index of an opposite vertex at the neighbor face.
88 char which_vertex_not[3];
89 };
90
91 struct stl_stats {
stl_statsstl_stats92 stl_stats() { memset(&header, 0, 81); }
93 char header[81];
94 stl_type type = (stl_type)0;
95 uint32_t number_of_facets = 0;
96 stl_vertex max = stl_vertex::Zero();
97 stl_vertex min = stl_vertex::Zero();
98 stl_vertex size = stl_vertex::Zero();
99 float bounding_diameter = 0.f;
100 float shortest_edge = 0.f;
101 float volume = -1.f;
102 int connected_edges = 0;
103 int connected_facets_1_edge = 0;
104 int connected_facets_2_edge = 0;
105 int connected_facets_3_edge = 0;
106 int facets_w_1_bad_edge = 0;
107 int facets_w_2_bad_edge = 0;
108 int facets_w_3_bad_edge = 0;
109 int original_num_facets = 0;
110 int edges_fixed = 0;
111 int degenerate_facets = 0;
112 int facets_removed = 0;
113 int facets_added = 0;
114 int facets_reversed = 0;
115 int backwards_edges = 0;
116 int normals_fixed = 0;
117 int number_of_parts = 0;
118
clearstl_stats119 void clear() { *this = stl_stats(); }
120 };
121
122 struct stl_file {
stl_filestl_file123 stl_file() {}
124
clearstl_file125 void clear() {
126 this->facet_start.clear();
127 this->neighbors_start.clear();
128 this->stats.clear();
129 }
130
memsizestl_file131 size_t memsize() const {
132 return sizeof(*this) + sizeof(stl_facet) * facet_start.size() + sizeof(stl_neighbors) * neighbors_start.size();
133 }
134
135 std::vector<stl_facet> facet_start;
136 std::vector<stl_neighbors> neighbors_start;
137 // Statistics
138 stl_stats stats;
139 };
140
141 struct indexed_triangle_set
142 {
indexed_triangle_setindexed_triangle_set143 indexed_triangle_set() {}
144
clearindexed_triangle_set145 void clear() { indices.clear(); vertices.clear(); }
146
memsizeindexed_triangle_set147 size_t memsize() const {
148 return sizeof(*this) + sizeof(stl_triangle_vertex_indices) * indices.size() + sizeof(stl_vertex) * vertices.size();
149 }
150
151 std::vector<stl_triangle_vertex_indices> indices;
152 std::vector<stl_vertex> vertices;
153 //FIXME add normals once we get rid of the stl_file from TriangleMesh completely.
154 //std::vector<stl_normal> normals
155 };
156
157 extern bool stl_open(stl_file *stl, const char *file);
158 extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file);
159 extern bool stl_print_neighbors(stl_file *stl, char *file);
160 extern bool stl_write_ascii(stl_file *stl, const char *file, const char *label);
161 extern bool stl_write_binary(stl_file *stl, const char *file, const char *label);
162 extern void stl_check_facets_exact(stl_file *stl);
163 extern void stl_check_facets_nearby(stl_file *stl, float tolerance);
164 extern void stl_remove_unconnected_facets(stl_file *stl);
165 extern void stl_write_vertex(stl_file *stl, int facet, int vertex);
166 extern void stl_write_facet(stl_file *stl, char *label, int facet);
167 extern void stl_write_neighbor(stl_file *stl, int facet);
168 extern bool stl_write_quad_object(stl_file *stl, char *file);
169 extern void stl_verify_neighbors(stl_file *stl);
170 extern void stl_fill_holes(stl_file *stl);
171 extern void stl_fix_normal_directions(stl_file *stl);
172 extern void stl_fix_normal_values(stl_file *stl);
173 extern void stl_reverse_all_facets(stl_file *stl);
174 extern void stl_translate(stl_file *stl, float x, float y, float z);
175 extern void stl_translate_relative(stl_file *stl, float x, float y, float z);
176 extern void stl_scale_versor(stl_file *stl, const stl_vertex &versor);
stl_scale(stl_file * stl,float factor)177 inline void stl_scale(stl_file *stl, float factor) { stl_scale_versor(stl, stl_vertex(factor, factor, factor)); }
178 extern void stl_rotate_x(stl_file *stl, float angle);
179 extern void stl_rotate_y(stl_file *stl, float angle);
180 extern void stl_rotate_z(stl_file *stl, float angle);
181 extern void stl_mirror_xy(stl_file *stl);
182 extern void stl_mirror_yz(stl_file *stl);
183 extern void stl_mirror_xz(stl_file *stl);
184
185 extern void stl_get_size(stl_file *stl);
186
187 // the following function is not used
188 /*
189 template<typename T>
190 extern void stl_transform(stl_file *stl, T *trafo3x4)
191 {
192 Eigen::Matrix<T, 3, 3, Eigen::DontAlign> trafo3x3;
193 for (int i = 0; i < 3; ++i)
194 {
195 for (int j = 0; j < 3; ++j)
196 {
197 trafo3x3(i, j) = (i * 4) + j;
198 }
199 }
200 Eigen::Matrix<T, 3, 3, Eigen::DontAlign> r = trafo3x3.inverse().transpose();
201 for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) {
202 stl_facet &face = stl->facet_start[i_face];
203 for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) {
204 stl_vertex &v_dst = face.vertex[i_vertex];
205 stl_vertex v_src = v_dst;
206 v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]);
207 v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
208 v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
209 }
210 face.normal = (r * face.normal.template cast<T>()).template cast<float>().eval();
211 }
212
213 stl_get_size(stl);
214 }
215 */
216
217 template<typename T>
stl_transform(stl_file * stl,const Eigen::Transform<T,3,Eigen::Affine,Eigen::DontAlign> & t)218 inline void stl_transform(stl_file *stl, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t)
219 {
220 const Eigen::Matrix<T, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0).inverse().transpose();
221 for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
222 stl_facet &f = stl->facet_start[i];
223 for (size_t j = 0; j < 3; ++j)
224 f.vertex[j] = (t * f.vertex[j].template cast<T>()).template cast<float>().eval();
225 f.normal = (r * f.normal.template cast<T>()).template cast<float>().eval();
226 }
227
228 stl_get_size(stl);
229 }
230
231 template<typename T>
stl_transform(stl_file * stl,const Eigen::Matrix<T,3,3,Eigen::DontAlign> & m)232 inline void stl_transform(stl_file *stl, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m)
233 {
234 const Eigen::Matrix<T, 3, 3, Eigen::DontAlign> r = m.inverse().transpose();
235 for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
236 stl_facet &f = stl->facet_start[i];
237 for (size_t j = 0; j < 3; ++j)
238 f.vertex[j] = (m * f.vertex[j].template cast<T>()).template cast<float>().eval();
239 f.normal = (r * f.normal.template cast<T>()).template cast<float>().eval();
240 }
241
242 stl_get_size(stl);
243 }
244
245
246 template<typename T>
its_transform(indexed_triangle_set & its,T * trafo3x4)247 extern void its_transform(indexed_triangle_set &its, T *trafo3x4)
248 {
249 for (stl_vertex &v_dst : its.vertices) {
250 stl_vertex v_src = v_dst;
251 v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]);
252 v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
253 v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
254 }
255 }
256
257 template<typename T>
258 inline void its_transform(indexed_triangle_set &its, const Eigen::Transform<T, 3, Eigen::Affine, Eigen::DontAlign>& t, bool fix_left_handed = false)
259 {
260 //const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
261 for (stl_vertex &v : its.vertices)
262 v = (t * v.template cast<T>()).template cast<float>().eval();
263 if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.)
264 for (stl_triangle_vertex_indices &i : its.indices)
265 std::swap(i[0], i[1]);
266 }
267
268 template<typename T>
269 inline void its_transform(indexed_triangle_set &its, const Eigen::Matrix<T, 3, 3, Eigen::DontAlign>& m, bool fix_left_handed = false)
270 {
271 for (stl_vertex &v : its.vertices)
272 v = (m * v.template cast<T>()).template cast<float>().eval();
273 if (fix_left_handed && m.determinant() < 0.)
274 for (stl_triangle_vertex_indices &i : its.indices)
275 std::swap(i[0], i[1]);
276 }
277
278 extern void its_rotate_x(indexed_triangle_set &its, float angle);
279 extern void its_rotate_y(indexed_triangle_set &its, float angle);
280 extern void its_rotate_z(indexed_triangle_set &its, float angle);
281
282 extern void stl_generate_shared_vertices(stl_file *stl, indexed_triangle_set &its);
283 extern bool its_write_obj(const indexed_triangle_set &its, const char *file);
284 extern bool its_write_off(const indexed_triangle_set &its, const char *file);
285 extern bool its_write_vrml(const indexed_triangle_set &its, const char *file);
286
287 extern bool stl_write_dxf(stl_file *stl, const char *file, char *label);
stl_calculate_normal(stl_normal & normal,stl_facet * facet)288 inline void stl_calculate_normal(stl_normal &normal, stl_facet *facet) {
289 normal = (facet->vertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]);
290 }
stl_normalize_vector(stl_normal & normal)291 inline void stl_normalize_vector(stl_normal &normal) {
292 double length = normal.cast<double>().norm();
293 if (length < 0.000000000001)
294 normal = stl_normal::Zero();
295 else
296 normal *= float(1.0 / length);
297 }
298 extern void stl_calculate_volume(stl_file *stl);
299
300 extern void stl_repair(stl_file *stl, bool fixall_flag, bool exact_flag, bool tolerance_flag, float tolerance, bool increment_flag, float increment, bool nearby_flag, int iterations, bool remove_unconnected_flag, bool fill_holes_flag, bool normal_directions_flag, bool normal_values_flag, bool reverse_all_flag, bool verbose_flag);
301
302 extern void stl_allocate(stl_file *stl);
303 extern void stl_read(stl_file *stl, int first_facet, bool first);
304 extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first);
305 extern void stl_reallocate(stl_file *stl);
306 extern void stl_add_facet(stl_file *stl, const stl_facet *new_facet);
307
308 // Validate the mesh, assert on error.
309 extern bool stl_validate(const stl_file *stl);
310 extern bool stl_validate(const stl_file *stl, const indexed_triangle_set &its);
311
312 #endif
313