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