Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
stl.h File Reference
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <vector>
#include <Eigen/Geometry>
+ Include dependency graph for stl.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  stl_facet
 
struct  stl_neighbors
 
struct  stl_stats
 
struct  stl_file
 
struct  indexed_triangle_set
 

Macros

#define LABEL_SIZE   80
 
#define NUM_FACET_SIZE   4
 
#define HEADER_SIZE   84
 
#define STL_MIN_FILE_SIZE   284
 
#define ASCII_LINES_PER_FACET   7
 
#define SIZEOF_STL_FACET   50
 

Typedefs

typedef Eigen::Matrix< float, 3, 1, Eigen::DontAlignstl_vertex
 
typedef Eigen::Matrix< float, 3, 1, Eigen::DontAlignstl_normal
 
typedef Eigen::Matrix< int, 3, 1, Eigen::DontAlignstl_triangle_vertex_indices
 
typedef Eigen::Matrix< float, 3, 1, Eigen::DontAlignobj_color
 

Enumerations

enum  stl_type { binary , ascii , inmemory }
 

Functions

bool stl_open (stl_file *stl, const char *file)
 
void stl_stats_out (stl_file *stl, FILE *file, char *input_file)
 
bool stl_print_neighbors (stl_file *stl, char *file)
 
bool stl_write_ascii (stl_file *stl, const char *file, const char *label)
 
bool stl_write_binary (stl_file *stl, const char *file, const char *label)
 
void stl_check_facets_exact (stl_file *stl)
 
void stl_check_facets_nearby (stl_file *stl, float tolerance)
 
void stl_remove_unconnected_facets (stl_file *stl)
 
void stl_write_vertex (stl_file *stl, int facet, int vertex)
 
void stl_write_facet (stl_file *stl, char *label, int facet)
 
void stl_write_neighbor (stl_file *stl, int facet)
 
bool stl_write_quad_object (stl_file *stl, char *file)
 
void stl_verify_neighbors (stl_file *stl)
 
void stl_fill_holes (stl_file *stl)
 
void stl_fix_normal_directions (stl_file *stl)
 
void stl_fix_normal_values (stl_file *stl)
 
void stl_reverse_all_facets (stl_file *stl)
 
void stl_translate (stl_file *stl, float x, float y, float z)
 
void stl_translate_relative (stl_file *stl, float x, float y, float z)
 
void stl_scale_versor (stl_file *stl, const stl_vertex &versor)
 
void stl_scale (stl_file *stl, float factor)
 
void stl_rotate_x (stl_file *stl, float angle)
 
void stl_rotate_y (stl_file *stl, float angle)
 
void stl_rotate_z (stl_file *stl, float angle)
 
void stl_mirror_xy (stl_file *stl)
 
void stl_mirror_yz (stl_file *stl)
 
void stl_mirror_xz (stl_file *stl)
 
void stl_get_size (stl_file *stl)
 
template<typename T >
void stl_transform (stl_file *stl, const Eigen::Transform< T, 3, Eigen::Affine, Eigen::DontAlign > &t)
 
template<typename T >
void stl_transform (stl_file *stl, const Eigen::Matrix< T, 3, 3, Eigen::DontAlign > &m)
 
template<typename V >
void its_translate (indexed_triangle_set &its, const V v)
 
template<typename T >
void its_transform (indexed_triangle_set &its, T *trafo3x4)
 
template<typename T >
void its_transform (indexed_triangle_set &its, const Eigen::Transform< T, 3, Eigen::Affine, Eigen::DontAlign > &t, bool fix_left_handed=false)
 
template<typename T >
void its_transform (indexed_triangle_set &its, const Eigen::Matrix< T, 3, 3, Eigen::DontAlign > &m, bool fix_left_handed=false)
 
void its_rotate_x (indexed_triangle_set &its, float angle)
 
void its_rotate_y (indexed_triangle_set &its, float angle)
 
void its_rotate_z (indexed_triangle_set &its, float angle)
 
void stl_generate_shared_vertices (stl_file *stl, indexed_triangle_set &its)
 
bool its_write_obj (const indexed_triangle_set &its, const char *file)
 
bool its_write_off (const indexed_triangle_set &its, const char *file)
 
bool its_write_vrml (const indexed_triangle_set &its, const char *file)
 
bool its_write_obj (const indexed_triangle_set &its, const std::vector< obj_color > &color, const char *file)
 write idexed triangle set into obj file with color
 
bool stl_write_dxf (stl_file *stl, const char *file, char *label)
 
void stl_calculate_normal (stl_normal &normal, stl_facet *facet)
 
void stl_normalize_vector (stl_normal &normal)
 
void stl_calculate_volume (stl_file *stl)
 
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)
 
void stl_allocate (stl_file *stl)
 
void stl_read (stl_file *stl, int first_facet, bool first)
 
void stl_facet_stats (stl_file *stl, stl_facet facet, bool &first)
 
void stl_reallocate (stl_file *stl)
 
void stl_add_facet (stl_file *stl, const stl_facet *new_facet)
 
bool stl_validate (const stl_file *stl)
 
bool stl_validate (const stl_file *stl, const indexed_triangle_set &its)
 

Macro Definition Documentation

◆ ASCII_LINES_PER_FACET

#define ASCII_LINES_PER_FACET   7

◆ HEADER_SIZE

#define HEADER_SIZE   84

◆ LABEL_SIZE

#define LABEL_SIZE   80

◆ NUM_FACET_SIZE

#define NUM_FACET_SIZE   4

◆ SIZEOF_STL_FACET

#define SIZEOF_STL_FACET   50

◆ STL_MIN_FILE_SIZE

#define STL_MIN_FILE_SIZE   284

Typedef Documentation

◆ obj_color

typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> obj_color

◆ stl_normal

typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_normal

◆ stl_triangle_vertex_indices

◆ stl_vertex

typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_vertex

Enumeration Type Documentation

◆ stl_type

enum stl_type
Enumerator
binary 
ascii 
inmemory 
stl_type
Definition stl.h:70
@ ascii
Definition stl.h:70
@ inmemory
Definition stl.h:70
@ binary
Definition stl.h:70

Function Documentation

◆ its_rotate_x()

void its_rotate_x ( indexed_triangle_set its,
float  angle 
)
163{
164 double radian_angle = (angle / 180.0) * M_PI;
165 double c = cos(radian_angle);
166 double s = sin(radian_angle);
167 for (stl_vertex &v : its.vertices)
168 rotate_point_2d(v(1), v(2), c, s);
169}
EIGEN_DEVICE_FUNC const CosReturnType cos() const
Definition ArrayCwiseUnaryOps.h:202
EIGEN_DEVICE_FUNC const SinReturnType sin() const
Definition ArrayCwiseUnaryOps.h:220
#define M_PI
Definition ExtrusionSimulator.cpp:20
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:112
static void rotate_point_2d(float &x, float &y, const double c, const double s)
Definition util.cpp:118

References cos(), M_PI, rotate_point_2d(), sin(), and indexed_triangle_set::vertices.

Referenced by Slic3r::TriangleMesh::rotate().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ its_rotate_y()

void its_rotate_y ( indexed_triangle_set its,
float  angle 
)
172{
173 double radian_angle = (angle / 180.0) * M_PI;
174 double c = cos(radian_angle);
175 double s = sin(radian_angle);
176 for (stl_vertex& v : its.vertices)
177 rotate_point_2d(v(2), v(0), c, s);
178}

References cos(), M_PI, rotate_point_2d(), sin(), and indexed_triangle_set::vertices.

Referenced by Slic3r::TriangleMesh::rotate().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ its_rotate_z()

void its_rotate_z ( indexed_triangle_set its,
float  angle 
)
181{
182 double radian_angle = (angle / 180.0) * M_PI;
183 double c = cos(radian_angle);
184 double s = sin(radian_angle);
185 for (stl_vertex& v : its.vertices)
186 rotate_point_2d(v(0), v(1), c, s);
187}

References cos(), M_PI, rotate_point_2d(), sin(), and indexed_triangle_set::vertices.

Referenced by Slic3r::TriangleMesh::rotate(), and Slic3r::TriangleMesh::rotate().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ its_transform() [1/3]

template<typename T >
void its_transform ( indexed_triangle_set its,
const Eigen::Matrix< T, 3, 3, Eigen::DontAlign > &  m,
bool  fix_left_handed = false 
)
inline
289{
290 for (stl_vertex &v : its.vertices)
291 v = (m * v.template cast<T>()).template cast<float>().eval();
292 if (fix_left_handed && m.determinant() < 0.)
293 for (stl_triangle_vertex_indices &i : its.indices)
294 std::swap(i[0], i[1]);
295}
EIGEN_DEVICE_FUNC CastXpr< NewType >::Type cast() const
Definition CommonCwiseUnaryOps.h:62
void swap(scoped_array< T > &a, scoped_array< T > &b)
Definition Memory.h:602
STL namespace.

References indexed_triangle_set::indices, and indexed_triangle_set::vertices.

◆ its_transform() [2/3]

template<typename T >
void its_transform ( indexed_triangle_set its,
const Eigen::Transform< T, 3, Eigen::Affine, Eigen::DontAlign > &  t,
bool  fix_left_handed = false 
)
inline
278{
279 //const Eigen::Matrix<double, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0);
280 for (stl_vertex &v : its.vertices)
281 v = (t * v.template cast<T>()).template cast<float>().eval();
282 if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.)
283 for (stl_triangle_vertex_indices &i : its.indices)
284 std::swap(i[0], i[1]);
285}
EIGEN_DEVICE_FUNC const MatrixType & matrix() const
Definition Transform.h:395

References indexed_triangle_set::indices, Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::matrix(), and indexed_triangle_set::vertices.

+ Here is the call graph for this function:

◆ its_transform() [3/3]

template<typename T >
void its_transform ( indexed_triangle_set its,
T *  trafo3x4 
)
inline
267{
268 for (stl_vertex &v_dst : its.vertices) {
269 stl_vertex v_src = v_dst;
270 v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]);
271 v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]);
272 v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]);
273 }
274}

References indexed_triangle_set::vertices.

Referenced by Slic3r::SeamPlacerImpl::compute_global_occlusion(), priv::create_emboss_projection(), Slic3r::csgmesh_merge_positive_parts(), priv::cut_surface(), Slic3r::SeamPlacerImpl::gather_enforcers_blockers(), Slic3r::csg::get_cgalmesh(), Slic3r::GUI::GLGizmoCut3D::is_outside_of_cut_contour(), Slic3r::PrintObject::prepare_adaptive_infill_data(), Slic3r::TriangleMesh::rotate(), Slic3r::slice_volumes(), Slic3r::TriangleMesh::transform(), and Slic3r::TriangleMesh::transform().

+ Here is the caller graph for this function:

◆ its_translate()

template<typename V >
void its_translate ( indexed_triangle_set its,
const v 
)
inline
260{
261 for (stl_vertex &v_dst : its.vertices)
262 v_dst += v;
263}

References indexed_triangle_set::vertices.

Referenced by Slic3r::GUI::GLGizmoBase::Grabber::render().

+ Here is the caller graph for this function:

◆ its_write_obj() [1/2]

bool its_write_obj ( const indexed_triangle_set its,
const char *  file 
)
194{
195 Slic3r::CNumericLocalesSetter locales_setter;
196 FILE *fp = boost::nowide::fopen(file, "w");
197 if (fp == nullptr) {
198 BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing";
199 return false;
200 }
201
202 for (size_t i = 0; i < its.vertices.size(); ++ i)
203 fprintf(fp, "v %f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
204 for (size_t i = 0; i < its.indices.size(); ++ i)
205 fprintf(fp, "f %d %d %d\n", its.indices[i][0]+1, its.indices[i][1]+1, its.indices[i][2]+1);
206 fclose(fp);
207 return true;
208}
Definition LocalesUtils.hpp:18
std::vector< stl_vertex > vertices
Definition stl.h:165
std::vector< stl_triangle_vertex_indices > indices
Definition stl.h:164
static char error[256]
Definition tga.cpp:50

References error, indexed_triangle_set::indices, and indexed_triangle_set::vertices.

Referenced by Slic3r::its_store_triangle_to_obj(), Slic3r::its_store_triangles_to_obj(), Slic3r::mmu_segmentation_top_and_bottom_layers(), and Slic3r::TriangleMesh::WriteOBJFile().

+ Here is the caller graph for this function:

◆ its_write_obj() [2/2]

bool its_write_obj ( const indexed_triangle_set its,
const std::vector< obj_color > &  color,
const char *  file 
)

write idexed triangle set into obj file with color

Parameters
itsinput model
colorcolor of stored model
filedefine place to store
Returns
True on success otherwise FALSE
211{
212 Slic3r::CNumericLocalesSetter locales_setter;
213 FILE* fp = boost::nowide::fopen(file, "w");
214 if (fp == nullptr) {
215 BOOST_LOG_TRIVIAL(error) << "stl_write_obj: Couldn't open " << file << " for writing";
216 return false;
217 }
218
219 for (size_t i = 0; i < its.vertices.size(); ++i)
220 fprintf(fp, "v %f %f %f %f %f %f\n",
221 its.vertices[i](0),
222 its.vertices[i](1),
223 its.vertices[i](2),
224 color[i](0),
225 color[i](1),
226 color[i](2));
227 for (size_t i = 0; i < its.indices.size(); ++i)
228 fprintf(fp, "f %d %d %d\n",
229 its.indices[i][0] + 1,
230 its.indices[i][1] + 1,
231 its.indices[i][2] + 1);
232 fclose(fp);
233 return true;
234}

References error, indexed_triangle_set::indices, and indexed_triangle_set::vertices.

◆ its_write_off()

bool its_write_off ( const indexed_triangle_set its,
const char *  file 
)
131{
132 Slic3r::CNumericLocalesSetter locales_setter;
133 /* Open the file */
134 FILE *fp = boost::nowide::fopen(file, "w");
135 if (fp == nullptr) {
136 BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing";
137 return false;
138 }
139
140 fprintf(fp, "OFF\n");
141 fprintf(fp, "%d %d 0\n", (int)its.vertices.size(), (int)its.indices.size());
142 for (int i = 0; i < its.vertices.size(); ++ i)
143 fprintf(fp, "\t%f %f %f\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
144 for (uint32_t i = 0; i < its.indices.size(); ++ i)
145 fprintf(fp, "\t3 %d %d %d\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
146 fclose(fp);
147 return true;
148}
unsigned __int32 uint32_t
Definition unistd.h:79

References error, indexed_triangle_set::indices, and indexed_triangle_set::vertices.

◆ its_write_vrml()

bool its_write_vrml ( const indexed_triangle_set its,
const char *  file 
)
151{
152 Slic3r::CNumericLocalesSetter locales_setter;
153 /* Open the file */
154 FILE *fp = boost::nowide::fopen(file, "w");
155 if (fp == nullptr) {
156 BOOST_LOG_TRIVIAL(error) << "stl_write_vrml: Couldn't open " << file << " for writing";
157 return false;
158 }
159
160 fprintf(fp, "#VRML V1.0 ascii\n\n");
161 fprintf(fp, "Separator {\n");
162 fprintf(fp, "\tDEF STLShape ShapeHints {\n");
163 fprintf(fp, "\t\tvertexOrdering COUNTERCLOCKWISE\n");
164 fprintf(fp, "\t\tfaceType CONVEX\n");
165 fprintf(fp, "\t\tshapeType SOLID\n");
166 fprintf(fp, "\t\tcreaseAngle 0.0\n");
167 fprintf(fp, "\t}\n");
168 fprintf(fp, "\tDEF STLModel Separator {\n");
169 fprintf(fp, "\t\tDEF STLColor Material {\n");
170 fprintf(fp, "\t\t\temissiveColor 0.700000 0.700000 0.000000\n");
171 fprintf(fp, "\t\t}\n");
172 fprintf(fp, "\t\tDEF STLVertices Coordinate3 {\n");
173 fprintf(fp, "\t\t\tpoint [\n");
174
175 int i = 0;
176 for (; i + 1 < its.vertices.size(); ++ i)
177 fprintf(fp, "\t\t\t\t%f %f %f,\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
178 fprintf(fp, "\t\t\t\t%f %f %f]\n", its.vertices[i](0), its.vertices[i](1), its.vertices[i](2));
179 fprintf(fp, "\t\t}\n");
180 fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
181 fprintf(fp, "\t\t\tcoordIndex [\n");
182
183 for (size_t i = 0; i + 1 < its.indices.size(); ++ i)
184 fprintf(fp, "\t\t\t\t%d, %d, %d, -1,\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
185 fprintf(fp, "\t\t\t\t%d, %d, %d, -1]\n", its.indices[i][0], its.indices[i][1], its.indices[i][2]);
186 fprintf(fp, "\t\t}\n");
187 fprintf(fp, "\t}\n");
188 fprintf(fp, "}\n");
189 fclose(fp);
190 return true;
191}

References error, indexed_triangle_set::indices, and indexed_triangle_set::vertices.

◆ stl_add_facet()

void stl_add_facet ( stl_file stl,
const stl_facet new_facet 
)
734{
735 assert(stl->facet_start.size() == stl->stats.number_of_facets);
736 assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
737 stl->facet_start.emplace_back(*new_facet);
738 // note that the normal vector is not set here, just initialized to 0.
739 stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero();
740 stl->neighbors_start.emplace_back();
741 ++ stl->stats.facets_added;
742 ++ stl->stats.number_of_facets;
743}
std::vector< stl_facet > facet_start
Definition stl.h:150
stl_stats stats
Definition stl.h:153
std::vector< stl_neighbors > neighbors_start
Definition stl.h:151
uint32_t number_of_facets
Definition stl.h:95
int facets_added
Definition stl.h:124

References stl_file::facet_start, stl_stats::facets_added, stl_file::neighbors_start, stl_stats::number_of_facets, and stl_file::stats.

Referenced by stl_fill_holes().

+ Here is the caller graph for this function:

◆ stl_allocate()

void stl_allocate ( stl_file stl)
249{
250 // Allocate memory for the entire .STL file.
251 stl->facet_start.assign(stl->stats.number_of_facets, stl_facet());
252 // Allocate memory for the neighbors list.
254}
Definition stl.h:48
Definition stl.h:72

References stl_file::facet_start, stl_file::neighbors_start, stl_stats::number_of_facets, and stl_file::stats.

Referenced by stl_open().

+ Here is the caller graph for this function:

◆ stl_calculate_normal()

void stl_calculate_normal ( stl_normal normal,
stl_facet facet 
)
inline
318 {
319 normal = (facet->vertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]);
320}
Vec< 3, T > normal(const std::array< Vec< 3, T >, 3 > &tri)
Definition Rotfinder.cpp:43
IGL_INLINE void cross(const double *a, const double *b, double *out)
Definition cross.cpp:11
stl_vertex vertex[3]
Definition stl.h:50

References stl_facet::vertex.

Referenced by calculate_normals(), check_normal_vector(), get_area(), and stl_reverse_all_facets().

+ Here is the caller graph for this function:

◆ stl_calculate_volume()

void stl_calculate_volume ( stl_file stl)
291{
292 stl->stats.volume = get_volume(stl);
293 if (stl->stats.volume < 0.0) {
295 stl->stats.volume = -stl->stats.volume;
296 }
297}
void stl_reverse_all_facets(stl_file *stl)
Definition normals.cpp:230
float volume
Definition stl.h:103
static float get_volume(stl_file *stl)
Definition util.cpp:276

References get_volume(), stl_file::stats, stl_reverse_all_facets(), and stl_stats::volume.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_check_facets_exact()

void stl_check_facets_exact ( stl_file stl)
433{
434 assert(stl->facet_start.size() == stl->neighbors_start.size());
435
436 stl->stats.connected_edges = 0;
440
441 // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
442 // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet
443 // will break the references.
444 for (uint32_t i = 0; i < stl->stats.number_of_facets;) {
445 stl_facet &facet = stl->facet_start[i];
446 if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) {
447 // Remove the degenerate facet.
448 facet = stl->facet_start[-- stl->stats.number_of_facets];
449 stl->facet_start.pop_back();
450 stl->neighbors_start.pop_back();
451 stl->stats.facets_removed += 1;
452 stl->stats.degenerate_facets += 1;
453 } else
454 ++ i;
455 }
456
457 // Initialize hash table.
458 HashTableEdges hash_table(stl->stats.number_of_facets);
459 for (auto &neighbor : stl->neighbors_start)
460 neighbor.reset();
461
462 // Connect neighbor edges.
463 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
464 const stl_facet &facet = stl->facet_start[i];
465 for (int j = 0; j < 3; ++ j) {
466 HashEdge edge;
467 edge.facet_number = i;
468 edge.which_edge = j;
469 edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
470 hash_table.insert_edge_exact(stl, edge);
471 }
472 }
473
474#if 0
475 printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n",
478#endif
479}
Definition connect.cpp:39
int facet_number
Definition connect.cpp:48
int which_edge
Definition connect.cpp:51
void load_exact(stl_file *stl, const stl_vertex *a, const stl_vertex *b)
Definition connect.cpp:54
Definition connect.cpp:123
int connected_facets_1_edge
Definition stl.h:108
int connected_edges
Definition stl.h:106
int degenerate_facets
Definition stl.h:120
int facets_removed
Definition stl.h:122
int connected_facets_2_edge
Definition stl.h:109
int connected_facets_3_edge
Definition stl.h:110

References stl_stats::connected_edges, stl_stats::connected_facets_1_edge, stl_stats::connected_facets_2_edge, stl_stats::connected_facets_3_edge, stl_stats::degenerate_facets, HashEdge::facet_number, stl_file::facet_start, stl_stats::facets_removed, HashTableEdges::insert_edge_exact(), HashEdge::load_exact(), stl_file::neighbors_start, stl_stats::number_of_facets, stl_file::stats, stl_facet::vertex, and HashEdge::which_edge.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_check_facets_nearby()

void stl_check_facets_nearby ( stl_file stl,
float  tolerance 
)
482{
486
488 // No need to check any further. All facets are connected.
489 return;
490
491 HashTableEdges hash_table(stl->stats.number_of_facets);
492 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
493 //FIXME is the copy necessary?
494 stl_facet facet = stl->facet_start[i];
495 for (int j = 0; j < 3; j++) {
496 if (stl->neighbors_start[i].neighbor[j] == -1) {
497 HashEdge edge;
498 edge.facet_number = i;
499 edge.which_edge = j;
500 if (edge.load_nearby(stl, facet.vertex[j], facet.vertex[(j + 1) % 3], tolerance))
501 // Only insert edges that have different keys.
502 hash_table.insert_edge_nearby(stl, edge);
503 }
504 }
505 }
506}
bool load_nearby(const stl_file *stl, const stl_vertex &a, const stl_vertex &b, float tolerance)
Definition connect.cpp:87

References stl_stats::connected_facets_1_edge, stl_stats::connected_facets_2_edge, stl_stats::connected_facets_3_edge, HashEdge::facet_number, stl_file::facet_start, HashTableEdges::insert_edge_nearby(), HashEdge::load_nearby(), stl_file::neighbors_start, stl_stats::number_of_facets, stl_file::stats, stl_facet::vertex, and HashEdge::which_edge.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_facet_stats()

void stl_facet_stats ( stl_file stl,
stl_facet  facet,
bool &  first 
)
263{
264 // While we are going through all of the facets, let's find the
265 // maximum and minimum values for x, y, and z
266
267 if (first) {
268 // Initialize the max and min values the first time through
269 stl->stats.min = facet.vertex[0];
270 stl->stats.max = facet.vertex[0];
271 stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs();
272 stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2)));
273 first = false;
274 }
275
276 // Now find the max and min values.
277 for (size_t i = 0; i < 3; ++ i) {
278 stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]);
279 stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
280 }
281}
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const CwiseAbsReturnType cwiseAbs() const
Definition MatrixCwiseUnaryOps.h:32
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:672
stl_vertex max
Definition stl.h:97
stl_vertex min
Definition stl.h:98
float shortest_edge
Definition stl.h:101

References cwiseAbs(), stl_stats::max, stl_stats::min, stl_stats::shortest_edge, stl_file::stats, and stl_facet::vertex.

Referenced by stl_read().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_fill_holes()

void stl_fill_holes ( stl_file stl)
653{
654 // Insert all unconnected edges into hash list.
655 HashTableEdges hash_table(stl->stats.number_of_facets);
656 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
657 stl_facet facet = stl->facet_start[i];
658 for (int j = 0; j < 3; ++ j) {
659 if(stl->neighbors_start[i].neighbor[j] != -1)
660 continue;
661 HashEdge edge;
662 edge.facet_number = i;
663 edge.which_edge = j;
664 edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
665 hash_table.insert_edge_exact(stl, edge);
666 }
667 }
668
669 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
670 stl_facet facet = stl->facet_start[i];
671 int neighbors_initial[3] = { stl->neighbors_start[i].neighbor[0], stl->neighbors_start[i].neighbor[1], stl->neighbors_start[i].neighbor[2] };
672 int first_facet = i;
673 for (int j = 0; j < 3; ++ j) {
674 if (stl->neighbors_start[i].neighbor[j] != -1)
675 continue;
676
677 stl_facet new_facet;
678 new_facet.vertex[0] = facet.vertex[j];
679 new_facet.vertex[1] = facet.vertex[(j + 1) % 3];
680 bool direction = neighbors_initial[(j + 2) % 3] == -1;
681 int facet_num = i;
682 int vnot = (j + 2) % 3;
683
684 for (;;) {
685 int pivot_vertex = 0;
686 int next_edge = 0;
687 if (vnot > 2) {
688 if (direction) {
689 pivot_vertex = (vnot + 1) % 3;
690 next_edge = vnot % 3;
691 } else {
692 pivot_vertex = (vnot + 2) % 3;
693 next_edge = pivot_vertex;
694 }
695 direction = ! direction;
696 } else {
697 if(direction == 0) {
698 pivot_vertex = (vnot + 1) % 3;
699 next_edge = vnot;
700 } else {
701 pivot_vertex = (vnot + 2) % 3;
702 next_edge = pivot_vertex;
703 }
704 }
705
706 int next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
707 if (next_facet == -1) {
708 new_facet.vertex[2] = stl->facet_start[facet_num].vertex[vnot % 3];
709 stl_add_facet(stl, &new_facet);
710 for (int k = 0; k < 3; ++ k) {
711 HashEdge edge;
712 edge.facet_number = stl->stats.number_of_facets - 1;
713 edge.which_edge = k;
714 edge.load_exact(stl, &new_facet.vertex[k], &new_facet.vertex[(k + 1) % 3]);
715 hash_table.insert_edge_exact(stl, edge);
716 }
717 break;
718 }
719
720 vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
721 facet_num = next_facet;
722
723 if (facet_num == first_facet) {
724 // back to the beginning
725 BOOST_LOG_TRIVIAL(info) << "Back to the first facet filling holes: probably a mobius part. Try using a smaller tolerance or don't do a nearby check.";
726 return;
727 }
728 }
729 }
730 }
731}
void stl_add_facet(stl_file *stl, const stl_facet *new_facet)
Definition connect.cpp:733

References HashEdge::facet_number, stl_file::facet_start, HashTableEdges::insert_edge_exact(), HashEdge::load_exact(), stl_file::neighbors_start, stl_stats::number_of_facets, stl_file::stats, stl_add_facet(), stl_facet::vertex, and HashEdge::which_edge.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_fix_normal_directions()

void stl_fix_normal_directions ( stl_file stl)
116{
117 // This may happen for malformed models, see: https://github.com/prusa3d/PrusaSlicer/issues/2209
118 if (stl->stats.number_of_facets == 0)
119 return;
120
121 struct stl_normal {
122 int facet_num;
123 stl_normal *next;
124 };
125
126 // Initialize linked list.
127 boost::object_pool<stl_normal> pool;
128 stl_normal *head = pool.construct();
129 stl_normal *tail = pool.construct();
130 head->next = tail;
131 tail->next = tail;
132
133 // Initialize list that keeps track of already fixed facets.
134 std::vector<char> norm_sw(stl->stats.number_of_facets, 0);
135 // Initialize list that keeps track of reversed facets.
136 std::vector<int> reversed_ids;
137 reversed_ids.reserve(stl->stats.number_of_facets);
138
139 int facet_num = 0;
140 // If normal vector is not within tolerance and backwards:
141 // Arbitrarily starts at face 0. If this one is wrong, we're screwed. Thankfully, the chances
142 // of it being wrong randomly are low if most of the triangles are right:
143 if (check_normal_vector(stl, 0, 0)) {
144 reverse_facet(stl, 0);
145 reversed_ids.emplace_back(0);
146 }
147
148 // Say that we've fixed this facet:
149 norm_sw[facet_num] = 1;
150 int checked = 1;
151
152 for (;;) {
153 // Add neighbors_to_list. Add unconnected neighbors to the list.
154 bool force_exit = false;
155 for (int j = 0; j < 3; ++ j) {
156 // Reverse the neighboring facets if necessary.
157 if (stl->neighbors_start[facet_num].which_vertex_not[j] > 2) {
158 // If the facet has a neighbor that is -1, it means that edge isn't shared by another facet
159 if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
160 if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] == 1) {
161 // trying to modify a facet already marked as fixed, revert all changes made until now and exit (fixes: #716, #574, #413, #269, #262, #259, #230, #228, #206)
162 for (int id = int(reversed_ids.size()) - 1; id >= 0; -- id)
163 reverse_facet(stl, reversed_ids[id]);
164 force_exit = true;
165 break;
166 }
167 reverse_facet(stl, stl->neighbors_start[facet_num].neighbor[j]);
168 reversed_ids.emplace_back(stl->neighbors_start[facet_num].neighbor[j]);
169 }
170 }
171 // If this edge of the facet is connected:
172 if (stl->neighbors_start[facet_num].neighbor[j] != -1) {
173 // If we haven't fixed this facet yet, add it to the list:
174 if (norm_sw[stl->neighbors_start[facet_num].neighbor[j]] != 1) {
175 // Add node to beginning of list.
176 stl_normal *newn = pool.construct();
177 newn->facet_num = stl->neighbors_start[facet_num].neighbor[j];
178 newn->next = head->next;
179 head->next = newn;
180 }
181 }
182 }
183
184 // an error occourred, quit the for loop and exit
185 if (force_exit)
186 break;
187
188 // Get next facet to fix from top of list.
189 if (head->next != tail) {
190 facet_num = head->next->facet_num;
191 assert(facet_num < stl->stats.number_of_facets);
192 if (norm_sw[facet_num] != 1) { // If facet is in list mutiple times
193 norm_sw[facet_num] = 1; // Record this one as being fixed.
194 ++ checked;
195 }
196 stl_normal *temp = head->next; // Delete this facet from the list.
197 head->next = head->next->next;
198 // pool.destroy(temp);
199 } else { // If we ran out of facets to fix: All of the facets in this part have been fixed.
200 ++ stl->stats.number_of_parts;
201 if (checked >= int(stl->stats.number_of_facets))
202 // All of the facets have been checked. Bail out.
203 break;
204 // There is another part here. Find it and continue.
205 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
206 if (norm_sw[i] == 0) {
207 // This is the first facet of the next part.
208 facet_num = i;
209 if (check_normal_vector(stl, i, 0)) {
210 reverse_facet(stl, i);
211 reversed_ids.emplace_back(i);
212 }
213 norm_sw[facet_num] = 1;
214 ++ checked;
215 break;
216 }
217 }
218 }
219
220 // pool.destroy(head);
221 // pool.destroy(tail);
222}
EIGEN_DEVICE_FUNC SegmentReturnType tail(Index n)
This is the const version of tail(Index).
Definition BlockMethods.h:949
EIGEN_DEVICE_FUNC SegmentReturnType head(Index n)
This is the const version of head(Index).
Definition BlockMethods.h:919
static void reverse_facet(stl_file *stl, int facet_num)
Definition normals.cpp:34
static bool check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag)
Definition normals.cpp:69
int number_of_parts
Definition stl.h:132

References check_normal_vector(), head(), stl_file::neighbors_start, stl_stats::number_of_facets, stl_stats::number_of_parts, reverse_facet(), stl_file::stats, and tail().

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_fix_normal_values()

void stl_fix_normal_values ( stl_file stl)
225{
226 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
227 check_normal_vector(stl, i, 1);
228}

References check_normal_vector(), stl_stats::number_of_facets, and stl_file::stats.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_generate_shared_vertices()

void stl_generate_shared_vertices ( stl_file stl,
indexed_triangle_set its 
)
36{
37 // 3 indices to vertex per face
38 its.indices.assign(stl->stats.number_of_facets, stl_triangle_vertex_indices(-1, -1, -1));
39 // Shared vertices (3D coordinates)
40 its.vertices.clear();
41 its.vertices.reserve(stl->stats.number_of_facets / 2);
42
43 // A degenerate mesh may contain loops: Traversing a fan will end up in an endless loop
44 // while never reaching the starting face. To avoid these endless loops, traversed faces at each fan traversal
45 // are marked with a unique fan_traversal_stamp.
46 unsigned int fan_traversal_stamp = 0;
47 std::vector<unsigned int> fan_traversal_facet_visited(stl->stats.number_of_facets, 0);
48
49 for (uint32_t facet_idx = 0; facet_idx < stl->stats.number_of_facets; ++ facet_idx) {
50 for (int j = 0; j < 3; ++ j) {
51 if (its.indices[facet_idx][j] != -1)
52 // Shared vertex was already assigned.
53 continue;
54 // Create a new shared vertex.
55 its.vertices.emplace_back(stl->facet_start[facet_idx].vertex[j]);
56 // Traverse the fan around the j-th vertex of the i-th face, assign the newly created shared vertex index to all the neighboring triangles in the triangle fan.
57 int facet_in_fan_idx = facet_idx;
58 bool edge_direction = false;
59 bool traversal_reversed = false;
60 int vnot = (j + 2) % 3;
61 // Increase the
62 ++ fan_traversal_stamp;
63 for (;;) {
64 // Next edge on facet_in_fan_idx to be traversed. The edge is indexed by its starting vertex index.
65 int next_edge = 0;
66 // Vertex index in facet_in_fan_idx, which is being pivoted around, and which is being assigned a new shared vertex.
67 int pivot_vertex = 0;
68 if (vnot > 2) {
69 // The edge of facet_in_fan_idx opposite to vnot is equally oriented, therefore
70 // the neighboring facet is flipped.
71 if (! edge_direction) {
72 pivot_vertex = (vnot + 2) % 3;
73 next_edge = pivot_vertex;
74 } else {
75 pivot_vertex = (vnot + 1) % 3;
76 next_edge = vnot % 3;
77 }
79 } else {
80 // The neighboring facet is correctly oriented.
81 if (! edge_direction) {
82 pivot_vertex = (vnot + 1) % 3;
83 next_edge = vnot;
84 } else {
85 pivot_vertex = (vnot + 2) % 3;
86 next_edge = pivot_vertex;
87 }
88 }
89 its.indices[facet_in_fan_idx][pivot_vertex] = its.vertices.size() - 1;
90 fan_traversal_facet_visited[facet_in_fan_idx] = fan_traversal_stamp;
91
92 // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
93 int next_facet = stl->neighbors_start[facet_in_fan_idx].neighbor[next_edge];
94 if (next_facet == -1) {
95 // No neighbor going in the current direction.
96 if (traversal_reversed) {
97 // Went to one limit, then turned back and reached the other limit. Quit the fan traversal.
98 break;
99 } else {
100 // Reached the first limit. Now try to reverse and traverse up to the other limit.
101 edge_direction = true;
102 vnot = (j + 1) % 3;
103 traversal_reversed = true;
104 facet_in_fan_idx = facet_idx;
105 }
106 } else if (next_facet == facet_idx) {
107 // Traversed a closed fan all around.
108// assert(! traversal_reversed);
109 break;
110 } else if (next_facet >= (int)stl->stats.number_of_facets) {
111 // The mesh is not valid!
112 // assert(false);
113 break;
114 } else if (fan_traversal_facet_visited[next_facet] == fan_traversal_stamp) {
115 // Traversed a closed fan all around, but did not reach the starting face.
116 // This indicates an invalid geometry (non-manifold).
117 //assert(false);
118 break;
119 } else {
120 // Continue traversal.
121 // next_edge is an index of the starting vertex of the edge, not an index of the opposite vertex to the edge!
122 vnot = stl->neighbors_start[facet_in_fan_idx].which_vertex_not[next_edge];
123 facet_in_fan_idx = next_facet;
124 }
125 }
126 }
127 }
128}
Vec3d edge_direction(const Vec3d &from, const Vec3d &to)
Definition Measure.hpp:157

References stl_file::facet_start, indexed_triangle_set::indices, stl_file::neighbors_start, stl_stats::number_of_facets, stl_file::stats, and indexed_triangle_set::vertices.

Referenced by Slic3r::TriangleMesh::ReadSTLFile().

+ Here is the caller graph for this function:

◆ stl_get_size()

void stl_get_size ( stl_file stl)
190{
191 if (stl->stats.number_of_facets == 0)
192 return;
193 stl->stats.min = stl->facet_start[0].vertex[0];
194 stl->stats.max = stl->stats.min;
195 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
196 const stl_facet &face = stl->facet_start[i];
197 for (int j = 0; j < 3; ++ j) {
198 stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]);
199 stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]);
200 }
201 }
202 stl->stats.size = stl->stats.max - stl->stats.min;
203 stl->stats.bounding_diameter = stl->stats.size.norm();
204}
stl_vertex size
Definition stl.h:99
float bounding_diameter
Definition stl.h:100

References stl_stats::bounding_diameter, stl_file::facet_start, stl_stats::max, stl_stats::min, stl_stats::number_of_facets, stl_stats::size, stl_file::stats, and stl_facet::vertex.

Referenced by stl_rotate_x(), stl_rotate_y(), stl_rotate_z(), stl_transform(), and stl_transform().

+ Here is the caller graph for this function:

◆ stl_mirror_xy()

void stl_mirror_xy ( stl_file stl)
207{
208 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
209 for (int j = 0; j < 3; ++ j)
210 stl->facet_start[i].vertex[j](2) *= -1.0;
211 float temp_size = stl->stats.min(2);
212 stl->stats.min(2) = stl->stats.max(2);
213 stl->stats.max(2) = temp_size;
214 stl->stats.min(2) *= -1.0;
215 stl->stats.max(2) *= -1.0;
217 stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
218}
int facets_reversed
Definition stl.h:126

References stl_file::facet_start, stl_stats::facets_reversed, stl_stats::max, stl_stats::min, stl_stats::number_of_facets, stl_file::stats, and stl_reverse_all_facets().

+ Here is the call graph for this function:

◆ stl_mirror_xz()

void stl_mirror_xz ( stl_file stl)
235{
236 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
237 for (int j = 0; j < 3; ++ j)
238 stl->facet_start[i].vertex[j](1) *= -1.0;
239 float temp_size = stl->stats.min(1);
240 stl->stats.min(1) = stl->stats.max(1);
241 stl->stats.max(1) = temp_size;
242 stl->stats.min(1) *= -1.0;
243 stl->stats.max(1) *= -1.0;
245 stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats
246}

References stl_file::facet_start, stl_stats::facets_reversed, stl_stats::max, stl_stats::min, stl_stats::number_of_facets, stl_file::stats, and stl_reverse_all_facets().

+ Here is the call graph for this function:

◆ stl_mirror_yz()

void stl_mirror_yz ( stl_file stl)
221{
222 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
223 for (int j = 0; j < 3; j++)
224 stl->facet_start[i].vertex[j](0) *= -1.0;
225 float temp_size = stl->stats.min(0);
226 stl->stats.min(0) = stl->stats.max(0);
227 stl->stats.max(0) = temp_size;
228 stl->stats.min(0) *= -1.0;
229 stl->stats.max(0) *= -1.0;
231 stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
232}

References stl_file::facet_start, stl_stats::facets_reversed, stl_stats::max, stl_stats::min, stl_stats::number_of_facets, stl_file::stats, and stl_reverse_all_facets().

+ Here is the call graph for this function:

◆ stl_normalize_vector()

void stl_normalize_vector ( stl_normal normal)
inline
321 {
322 double length = normal.cast<double>().norm();
323 if (length < 0.000000000001)
324 normal = stl_normal::Zero();
325 else
326 normal *= float(1.0 / length);
327}
double length(std::vector< SurfacePoint > &path)
Definition exact_geodesic.cpp:1682

Referenced by calculate_normals(), check_normal_vector(), get_area(), and stl_reverse_all_facets().

+ Here is the caller graph for this function:

◆ stl_open()

bool stl_open ( stl_file stl,
const char *  file 
)
236{
237 Slic3r::CNumericLocalesSetter locales_setter;
238 stl->clear();
239 FILE *fp = stl_open_count_facets(stl, file);
240 if (fp == nullptr)
241 return false;
242 stl_allocate(stl);
243 bool result = stl_read(stl, fp, 0, true);
244 fclose(fp);
245 return result;
246}
void stl_allocate(stl_file *stl)
Definition stlinit.cpp:248
static bool stl_read(stl_file *stl, FILE *fp, int first_facet, bool first)
Definition stlinit.cpp:148
static FILE * stl_open_count_facets(stl_file *stl, const char *file)
Definition stlinit.cpp:45
void clear()
Definition stl.h:140

References stl_file::clear(), stl_allocate(), stl_open_count_facets(), and stl_read().

Referenced by Slic3r::TriangleMesh::ReadSTLFile().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_print_neighbors()

bool stl_print_neighbors ( stl_file stl,
char *  file 
)
96{
97 FILE *fp = boost::nowide::fopen(file, "w");
98 if (fp == nullptr) {
99 BOOST_LOG_TRIVIAL(error) << "stl_print_neighbors: Couldn't open " << file << " for writing";
100 return false;
101 }
102
103 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
104 fprintf(fp, "%d, %d,%d, %d,%d, %d,%d\n",
105 i,
106 stl->neighbors_start[i].neighbor[0],
107 (int)stl->neighbors_start[i].which_vertex_not[0],
108 stl->neighbors_start[i].neighbor[1],
109 (int)stl->neighbors_start[i].which_vertex_not[1],
110 stl->neighbors_start[i].neighbor[2],
111 (int)stl->neighbors_start[i].which_vertex_not[2]);
112 }
113 fclose(fp);
114 return true;
115}

References error, stl_file::neighbors_start, stl_stats::number_of_facets, and stl_file::stats.

◆ stl_read()

void stl_read ( stl_file stl,
int  first_facet,
bool  first 
)

◆ stl_reallocate()

void stl_reallocate ( stl_file stl)

◆ stl_remove_unconnected_facets()

void stl_remove_unconnected_facets ( stl_file stl)
509{
510 // A couple of things need to be done here. One is to remove any completely unconnected facets (0 edges connected) since these are
511 // useless and could be completely wrong. The second thing that needs to be done is to remove any degenerate facets that were created during
512 // stl_check_facets_nearby().
513 auto remove_facet = [stl](int facet_number)
514 {
515 ++ stl->stats.facets_removed;
516 /* Update list of connected edges */
517 stl_neighbors &neighbors = stl->neighbors_start[facet_number];
518 // Update statistics on unconnected triangle edges.
519 switch (neighbors.num_neighbors()) {
520 case 3: -- stl->stats.connected_facets_3_edge; // fall through
521 case 2: -- stl->stats.connected_facets_2_edge; // fall through
522 case 1: -- stl->stats.connected_facets_1_edge; // fall through
523 case 0: break;
524 default: assert(false);
525 }
526
527 if (facet_number < int(-- stl->stats.number_of_facets)) {
528 // Removing a face, which was not the last one.
529 // Copy the face and neighborship from the last face to facet_number.
530 stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets];
531 neighbors = stl->neighbors_start[stl->stats.number_of_facets];
532 // Update neighborship of faces, which used to point to the last face, now moved to facet_number.
533 for (int i = 0; i < 3; ++ i)
534 if (neighbors.neighbor[i] != -1) {
535 int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3];
536 if (other_face_idx != stl->stats.number_of_facets) {
537 BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong";
538 return;
539 }
540 other_face_idx = facet_number;
541 }
542 }
543
544 stl->facet_start.pop_back();
545 stl->neighbors_start.pop_back();
546 };
547
548 auto remove_degenerate = [stl, remove_facet](int facet)
549 {
550 // Update statistics on face connectivity after one edge was disconnected on the facet "facet_num".
551 auto update_connects_remove_1 = [stl](int facet_num) {
552 switch (stl->neighbors_start[facet_num].num_neighbors()) {
553 case 0: assert(false); break;
554 case 1: -- stl->stats.connected_facets_1_edge; break;
555 case 2: -- stl->stats.connected_facets_2_edge; break;
556 case 3: -- stl->stats.connected_facets_3_edge; break;
557 default: assert(false);
558 }
559 };
560
561 int edge_to_collapse = 0;
562 if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) {
563 if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
564 // All 3 vertices are equal. Collapse the edge with no neighbor if it exists.
565 const int *nbr = stl->neighbors_start[facet].neighbor;
566 edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2;
567 } else {
568 edge_to_collapse = 0;
569 }
570 } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
571 edge_to_collapse = 1;
572 } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) {
573 edge_to_collapse = 2;
574 } else {
575 // No degenerate. Function shouldn't have been called.
576 return;
577 }
578
579 int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse };
580 int neighbor[] = {
581 stl->neighbors_start[facet].neighbor[edge[0]],
582 stl->neighbors_start[facet].neighbor[edge[1]],
583 stl->neighbors_start[facet].neighbor[edge[2]]
584 };
585 int vnot[] = {
586 stl->neighbors_start[facet].which_vertex_not[edge[0]],
587 stl->neighbors_start[facet].which_vertex_not[edge[1]],
588 stl->neighbors_start[facet].which_vertex_not[edge[2]]
589 };
590
591 // Update statistics on edge connectivity.
592 if ((neighbor[0] == -1) && (neighbor[1] != -1))
593 update_connects_remove_1(neighbor[1]);
594 if ((neighbor[1] == -1) && (neighbor[0] != -1))
595 update_connects_remove_1(neighbor[0]);
596
597 if (neighbor[0] >= 0) {
598 if (neighbor[1] >= 0) {
599 // Adjust the "flip" flag for the which_vertex_not values.
600 if (vnot[0] > 2) {
601 if (vnot[1] > 2) {
602 // The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face
603 // the two remaining neighbors will be oriented correctly.
604 vnot[0] -= 3;
605 vnot[1] -= 3;
606 } else
607 // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
608 // After removal, the two neighbors will have their normals flipped.
609 vnot[1] += 3;
610 } else if (vnot[1] > 2)
611 // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
612 // After removal, the two neighbors will have their normals flipped.
613 vnot[0] += 3;
614 }
615 stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1];
616 stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1];
617 }
618 if (neighbor[1] >= 0) {
619 stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0];
620 stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = vnot[0];
621 }
622 if (neighbor[2] >= 0) {
623 update_connects_remove_1(neighbor[2]);
624 stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1;
625 }
626
627 remove_facet(facet);
628 };
629
630 // remove degenerate facets
631 for (uint32_t i = 0; i < stl->stats.number_of_facets;)
632 if (stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] ||
633 stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] ||
634 stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) {
636// assert(stl_validate(stl));
637 } else
638 ++ i;
639
641 // There are some faces with no connected edge at all. Remove completely unconnected facets.
642 for (uint32_t i = 0; i < stl->stats.number_of_facets;)
643 if (stl->neighbors_start[i].num_neighbors() == 0) {
644 // This facet is completely unconnected. Remove it.
645 remove_facet(i);
646 assert(stl_validate(stl));
647 } else
648 ++ i;
649 }
650}
bool remove_degenerate(Polygons &polys)
Definition Polygon.cpp:505
bool stl_validate(const stl_file *stl, const indexed_triangle_set &its)
Definition shared.cpp:237
char which_vertex_not[3]
Definition stl.h:87
int neighbor[3]
Definition stl.h:85
int num_neighbors() const
Definition stl.h:82

References stl_stats::connected_facets_1_edge, stl_stats::connected_facets_2_edge, stl_stats::connected_facets_3_edge, stl_file::facet_start, stl_stats::facets_removed, stl_neighbors::neighbor, stl_file::neighbors_start, stl_neighbors::num_neighbors(), stl_stats::number_of_facets, stl_file::stats, stl_validate(), and stl_neighbors::which_vertex_not.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_repair()

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 
)
315{
316 if (exact_flag || fixall_flag || nearby_flag || remove_unconnected_flag || fill_holes_flag || normal_directions_flag) {
317 if (verbose_flag)
318 printf("Checking exact...\n");
319 exact_flag = true;
324 }
325
326 if (nearby_flag || fixall_flag) {
327 if (! tolerance_flag)
328 tolerance = stl->stats.shortest_edge;
329 if (! increment_flag)
330 increment = stl->stats.bounding_diameter / 10000.0;
331 }
332
334 int last_edges_fixed = 0;
335 for (int i = 0; i < iterations; ++ i) {
337 if (verbose_flag)
338 printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations);
339 stl_check_facets_nearby(stl, tolerance);
340 if (verbose_flag)
341 printf(" Fixed %d edges.\n", stl->stats.edges_fixed - last_edges_fixed);
342 last_edges_fixed = stl->stats.edges_fixed;
343 tolerance += increment;
344 } else {
345 if (verbose_flag)
346 printf("All facets connected. No further nearby check necessary.\n");
347 break;
348 }
349 }
350 } else if (verbose_flag)
351 printf("All facets connected. No nearby check necessary.\n");
352
353 if (remove_unconnected_flag || fixall_flag || fill_holes_flag) {
355 if (verbose_flag)
356 printf("Removing unconnected facets...\n");
358 } else if (verbose_flag)
359 printf("No unconnected need to be removed.\n");
360 }
361
362 if (fill_holes_flag || fixall_flag) {
364 if (verbose_flag)
365 printf("Filling holes...\n");
366 stl_fill_holes(stl);
367 } else if (verbose_flag)
368 printf("No holes need to be filled.\n");
369 }
370
371 if (reverse_all_flag) {
372 if (verbose_flag)
373 printf("Reversing all facets...\n");
375 }
376
377 if (normal_directions_flag || fixall_flag) {
378 if (verbose_flag)
379 printf("Checking normal directions...\n");
381 }
382
383 if (normal_values_flag || fixall_flag) {
384 if (verbose_flag)
385 printf("Checking normal values...\n");
387 }
388
389 // Always calculate the volume. It shouldn't take too long.
390 if (verbose_flag)
391 printf("Calculating volume...\n");
393
394 if (exact_flag) {
395 if (verbose_flag)
396 printf("Verifying neighbors...\n");
398 }
399}
void stl_check_facets_nearby(stl_file *stl, float tolerance)
Definition connect.cpp:481
void stl_fill_holes(stl_file *stl)
Definition connect.cpp:652
void stl_remove_unconnected_facets(stl_file *stl)
Definition connect.cpp:508
void stl_check_facets_exact(stl_file *stl)
Definition connect.cpp:432
void stl_fix_normal_values(stl_file *stl)
Definition normals.cpp:224
void stl_fix_normal_directions(stl_file *stl)
Definition normals.cpp:115
int facets_w_3_bad_edge
Definition stl.h:114
int facets_w_2_bad_edge
Definition stl.h:113
int facets_w_1_bad_edge
Definition stl.h:112
int edges_fixed
Definition stl.h:118
void stl_verify_neighbors(stl_file *stl)
Definition util.cpp:32
void stl_calculate_volume(stl_file *stl)
Definition util.cpp:290

References stl_stats::bounding_diameter, stl_stats::connected_facets_1_edge, stl_stats::connected_facets_2_edge, stl_stats::connected_facets_3_edge, stl_stats::edges_fixed, stl_stats::facets_w_1_bad_edge, stl_stats::facets_w_2_bad_edge, stl_stats::facets_w_3_bad_edge, stl_stats::number_of_facets, stl_stats::shortest_edge, stl_file::stats, stl_calculate_volume(), stl_check_facets_exact(), stl_check_facets_nearby(), stl_fill_holes(), stl_fix_normal_directions(), stl_fix_normal_values(), stl_remove_unconnected_facets(), stl_reverse_all_facets(), and stl_verify_neighbors().

+ Here is the call graph for this function:

◆ stl_reverse_all_facets()

void stl_reverse_all_facets ( stl_file stl)
231{
233 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
234 reverse_facet(stl, i);
235 stl_calculate_normal(normal, &stl->facet_start[i]);
236 stl_normalize_vector(normal);
237 stl->facet_start[i].normal = normal;
238 }
239}
void stl_calculate_normal(stl_normal &normal, stl_facet *facet)
Definition stl.h:318
void stl_normalize_vector(stl_normal &normal)
Definition stl.h:321

References stl_file::facet_start, stl_stats::number_of_facets, reverse_facet(), stl_file::stats, stl_calculate_normal(), and stl_normalize_vector().

Referenced by stl_calculate_volume(), stl_mirror_xy(), stl_mirror_xz(), stl_mirror_yz(), and stl_repair().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_rotate_x()

void stl_rotate_x ( stl_file stl,
float  angle 
)
127{
128 double radian_angle = (angle / 180.0) * M_PI;
129 double c = cos(radian_angle);
130 double s = sin(radian_angle);
131 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
132 for (int j = 0; j < 3; ++ j)
133 rotate_point_2d(stl->facet_start[i].vertex[j](1), stl->facet_start[i].vertex[j](2), c, s);
134 stl_get_size(stl);
136}
static void calculate_normals(stl_file *stl)
Definition util.cpp:108
void stl_get_size(stl_file *stl)
Definition util.cpp:189

References calculate_normals(), cos(), stl_file::facet_start, M_PI, stl_stats::number_of_facets, rotate_point_2d(), sin(), stl_file::stats, and stl_get_size().

+ Here is the call graph for this function:

◆ stl_rotate_y()

void stl_rotate_y ( stl_file stl,
float  angle 
)
139{
140 double radian_angle = (angle / 180.0) * M_PI;
141 double c = cos(radian_angle);
142 double s = sin(radian_angle);
143 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
144 for (int j = 0; j < 3; ++ j)
145 rotate_point_2d(stl->facet_start[i].vertex[j](2), stl->facet_start[i].vertex[j](0), c, s);
146 stl_get_size(stl);
148}

References calculate_normals(), cos(), stl_file::facet_start, M_PI, stl_stats::number_of_facets, rotate_point_2d(), sin(), stl_file::stats, and stl_get_size().

+ Here is the call graph for this function:

◆ stl_rotate_z()

void stl_rotate_z ( stl_file stl,
float  angle 
)
151{
152 double radian_angle = (angle / 180.0) * M_PI;
153 double c = cos(radian_angle);
154 double s = sin(radian_angle);
155 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
156 for (int j = 0; j < 3; ++ j)
157 rotate_point_2d(stl->facet_start[i].vertex[j](0), stl->facet_start[i].vertex[j](1), c, s);
158 stl_get_size(stl);
160}

References calculate_normals(), cos(), stl_file::facet_start, M_PI, stl_stats::number_of_facets, rotate_point_2d(), sin(), stl_file::stats, and stl_get_size().

+ Here is the call graph for this function:

◆ stl_scale()

void stl_scale ( stl_file stl,
float  factor 
)
inline
190{ stl_scale_versor(stl, stl_vertex(factor, factor, factor)); }
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > stl_vertex
Definition stl.h:42
void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
Definition util.cpp:91

References stl_scale_versor().

+ Here is the call graph for this function:

◆ stl_scale_versor()

void stl_scale_versor ( stl_file stl,
const stl_vertex versor 
)
92{
93 // Scale extents.
94 auto s = versor.array();
95 stl->stats.min.array() *= s;
96 stl->stats.max.array() *= s;
97 // Scale size.
98 stl->stats.size.array() *= s;
99 // Scale volume.
100 if (stl->stats.volume > 0.0)
101 stl->stats.volume *= versor(0) * versor(1) * versor(2);
102 // Scale the mesh.
103 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
104 for (int j = 0; j < 3; ++ j)
105 stl->facet_start[i].vertex[j].array() *= s;
106}

References stl_file::facet_start, stl_stats::max, stl_stats::min, stl_stats::number_of_facets, stl_stats::size, stl_file::stats, and stl_stats::volume.

Referenced by stl_scale().

+ Here is the caller graph for this function:

◆ stl_stats_out()

void stl_stats_out ( stl_file stl,
FILE *  file,
char *  input_file 
)
33{
34 // This is here for Slic3r, without our config.h it won't use this part of the code anyway.
35#ifndef VERSION
36#define VERSION "unknown"
37#endif
38 fprintf(file, "\n================= Results produced by ADMesh version " VERSION " ================\n");
39 fprintf(file, "Input file : %s\n", input_file);
40 if (stl->stats.type == binary)
41 fprintf(file, "File type : Binary STL file\n");
42 else
43 fprintf(file, "File type : ASCII STL file\n");
44 fprintf(file, "Header : %s\n", stl->stats.header);
45 fprintf(file, "============== Size ==============\n");
46 fprintf(file, "Min X = % f, Max X = % f\n", stl->stats.min(0), stl->stats.max(0));
47 fprintf(file, "Min Y = % f, Max Y = % f\n", stl->stats.min(1), stl->stats.max(1));
48 fprintf(file, "Min Z = % f, Max Z = % f\n", stl->stats.min(2), stl->stats.max(2));
49 fprintf(file, "========= Facet Status ========== Original ============ Final ====\n");
50 fprintf(file, "Number of facets : %5d %5d\n", stl->stats.original_num_facets, stl->stats.number_of_facets);
51 fprintf(file, "Facets with 1 disconnected edge : %5d %5d\n",
53 fprintf(file, "Facets with 2 disconnected edges : %5d %5d\n",
55 fprintf(file, "Facets with 3 disconnected edges : %5d %5d\n",
57 fprintf(file, "Total disconnected facets : %5d %5d\n",
59 fprintf(file, "=== Processing Statistics === ===== Other Statistics =====\n");
60 fprintf(file, "Number of parts : %5d Volume : %f\n", stl->stats.number_of_parts, stl->stats.volume);
61 fprintf(file, "Degenerate facets : %5d\n", stl->stats.degenerate_facets);
62 fprintf(file, "Edges fixed : %5d\n", stl->stats.edges_fixed);
63 fprintf(file, "Facets removed : %5d\n", stl->stats.facets_removed);
64 fprintf(file, "Facets added : %5d\n", stl->stats.facets_added);
65 fprintf(file, "Facets reversed : %5d\n", stl->stats.facets_reversed);
66 fprintf(file, "Backwards edges : %5d\n", stl->stats.backwards_edges);
67 fprintf(file, "Normals fixed : %5d\n", stl->stats.normals_fixed);
68}
#define VERSION
int backwards_edges
Definition stl.h:128
stl_type type
Definition stl.h:93
char header[81]
Definition stl.h:92
int normals_fixed
Definition stl.h:130
int original_num_facets
Definition stl.h:116

References stl_stats::backwards_edges, binary, stl_stats::connected_facets_1_edge, stl_stats::connected_facets_2_edge, stl_stats::connected_facets_3_edge, stl_stats::degenerate_facets, stl_stats::edges_fixed, stl_stats::facets_added, stl_stats::facets_removed, stl_stats::facets_reversed, stl_stats::facets_w_1_bad_edge, stl_stats::facets_w_2_bad_edge, stl_stats::facets_w_3_bad_edge, stl_stats::header, stl_stats::max, stl_stats::min, stl_stats::normals_fixed, stl_stats::number_of_facets, stl_stats::number_of_parts, stl_stats::original_num_facets, stl_file::stats, stl_stats::type, VERSION, and stl_stats::volume.

◆ stl_transform() [1/2]

template<typename T >
void stl_transform ( stl_file stl,
const Eigen::Matrix< T, 3, 3, Eigen::DontAlign > &  m 
)
inline
246{
247 const Eigen::Matrix<T, 3, 3, Eigen::DontAlign> r = m.inverse().transpose();
248 for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
249 stl_facet &f = stl->facet_start[i];
250 for (size_t j = 0; j < 3; ++j)
251 f.vertex[j] = (m * f.vertex[j].template cast<T>()).template cast<float>().eval();
252 f.normal = (r * f.normal.template cast<T>()).template cast<float>().eval();
253 }
254
255 stl_get_size(stl);
256}
void stl_get_size(stl_file *stl)
Definition util.cpp:189
stl_normal normal
Definition stl.h:49

References stl_file::facet_start, stl_facet::normal, stl_stats::number_of_facets, stl_file::stats, stl_get_size(), and stl_facet::vertex.

+ Here is the call graph for this function:

◆ stl_transform() [2/2]

template<typename T >
void stl_transform ( stl_file stl,
const Eigen::Transform< T, 3, Eigen::Affine, Eigen::DontAlign > &  t 
)
inline
232{
233 const Eigen::Matrix<T, 3, 3, Eigen::DontAlign> r = t.matrix().template block<3, 3>(0, 0).inverse().transpose();
234 for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) {
235 stl_facet &f = stl->facet_start[i];
236 for (size_t j = 0; j < 3; ++j)
237 f.vertex[j] = (t * f.vertex[j].template cast<T>()).template cast<float>().eval();
238 f.normal = (r * f.normal.template cast<T>()).template cast<float>().eval();
239 }
240
241 stl_get_size(stl);
242}

References stl_file::facet_start, Eigen::Transform< _Scalar, _Dim, _Mode, _Options >::matrix(), stl_facet::normal, stl_stats::number_of_facets, stl_file::stats, stl_get_size(), and stl_facet::vertex.

+ Here is the call graph for this function:

◆ stl_translate()

void stl_translate ( stl_file stl,
float  x,
float  y,
float  z 
)
70{
71 stl_vertex new_min(x, y, z);
72 stl_vertex shift = new_min - stl->stats.min;
73 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
74 for (int j = 0; j < 3; ++ j)
75 stl->facet_start[i].vertex[j] += shift;
76 stl->stats.min = new_min;
77 stl->stats.max += shift;
78}

References stl_file::facet_start, stl_stats::max, stl_stats::min, stl_stats::number_of_facets, and stl_file::stats.

◆ stl_translate_relative()

void stl_translate_relative ( stl_file stl,
float  x,
float  y,
float  z 
)
82{
83 stl_vertex shift(x, y, z);
84 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i)
85 for (int j = 0; j < 3; ++ j)
86 stl->facet_start[i].vertex[j] += shift;
87 stl->stats.min += shift;
88 stl->stats.max += shift;
89}

References stl_file::facet_start, stl_stats::max, stl_stats::min, stl_stats::number_of_facets, and stl_file::stats.

◆ stl_validate() [1/2]

bool stl_validate ( const stl_file stl)
285{
287 return stl_validate(stl, its);
288}
Definition stl.h:157

References stl_validate().

+ Here is the call graph for this function:

◆ stl_validate() [2/2]

bool stl_validate ( const stl_file stl,
const indexed_triangle_set its 
)
238{
239 assert(! stl->facet_start.empty());
240 assert(stl->facet_start.size() == stl->stats.number_of_facets);
241 assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
242 assert(stl->facet_start.size() == stl->neighbors_start.size());
243 assert(! stl->neighbors_start.empty());
244 assert((its.indices.empty()) == (its.vertices.empty()));
245 assert(stl->stats.number_of_facets > 0);
246 assert(its.vertices.empty() || its.indices.size() == stl->stats.number_of_facets);
247
248#ifdef _DEBUG
249 // Verify validity of neighborship data.
250 for (int facet_idx = 0; facet_idx < (int)stl->stats.number_of_facets; ++ facet_idx) {
251 const stl_neighbors &nbr = stl->neighbors_start[facet_idx];
252 const int *vertices = its.indices.empty() ? nullptr : its.indices[facet_idx].data();
253 for (int nbr_idx = 0; nbr_idx < 3; ++ nbr_idx) {
254 int nbr_face = stl->neighbors_start[facet_idx].neighbor[nbr_idx];
255 assert(nbr_face < (int)stl->stats.number_of_facets);
256 if (nbr_face != -1) {
257 int nbr_vnot = nbr.which_vertex_not[nbr_idx];
258 assert(nbr_vnot >= 0 && nbr_vnot < 6);
259 // Neighbor of the neighbor is the original face.
260 assert(stl->neighbors_start[nbr_face].neighbor[(nbr_vnot + 1) % 3] == facet_idx);
261 int vnot_back = stl->neighbors_start[nbr_face].which_vertex_not[(nbr_vnot + 1) % 3];
262 assert(vnot_back >= 0 && vnot_back < 6);
263 assert((nbr_vnot < 3) == (vnot_back < 3));
264 assert(vnot_back % 3 == (nbr_idx + 2) % 3);
265 if (vertices != nullptr) {
266 // Has shared vertices.
267 if (nbr_vnot < 3) {
268 // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are correctly oriented.
269 assert((its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[nbr_idx]));
270 } else {
271 // Faces facet_idx and nbr_face share two vertices accross the common edge. Faces are incorrectly oriented, one of them is flipped.
272 assert((its.indices[nbr_face][(nbr_vnot + 2) % 3] == vertices[(nbr_idx + 1) % 3] && its.indices[nbr_face][(nbr_vnot + 1) % 3] == vertices[nbr_idx]));
273 }
274 }
275 }
276 }
277 }
278#endif /* _DEBUG */
279
280 return true;
281}

References stl_file::facet_start, indexed_triangle_set::indices, stl_file::neighbors_start, stl_stats::number_of_facets, stl_file::stats, indexed_triangle_set::vertices, and stl_neighbors::which_vertex_not.

Referenced by stl_remove_unconnected_facets(), stl_validate(), and Slic3r::trianglemesh_repair_on_import().

+ Here is the caller graph for this function:

◆ stl_verify_neighbors()

void stl_verify_neighbors ( stl_file stl)
33{
34 stl->stats.backwards_edges = 0;
35
36 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
37 for (int j = 0; j < 3; ++ j) {
38 struct stl_edge {
39 stl_vertex p1;
40 stl_vertex p2;
41 int facet_number;
42 };
43 stl_edge edge_a;
44 edge_a.p1 = stl->facet_start[i].vertex[j];
45 edge_a.p2 = stl->facet_start[i].vertex[(j + 1) % 3];
46 int neighbor = stl->neighbors_start[i].neighbor[j];
47 if (neighbor == -1)
48 continue; // this edge has no neighbor... Continue.
49 int vnot = stl->neighbors_start[i].which_vertex_not[j];
50 stl_edge edge_b;
51 if (vnot < 3) {
52 edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
53 edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
54 } else {
55 stl->stats.backwards_edges += 1;
56 edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
57 edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
58 }
59 if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
60 // These edges should match but they don't. Print results.
61 BOOST_LOG_TRIVIAL(info) << "edge " << j << " of facet " << i << " doesn't match edge " << (vnot + 1) << " of facet " << neighbor;
62 stl_write_facet(stl, (char*)"first facet", i);
63 stl_write_facet(stl, (char*)"second facet", neighbor);
64 }
65 }
66 }
67}
void stl_write_facet(stl_file *stl, char *label, int facet)
Definition stl_io.cpp:173

References stl_stats::backwards_edges, stl_file::facet_start, stl_file::neighbors_start, stl_stats::number_of_facets, stl_file::stats, and stl_write_facet().

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_write_ascii()

bool stl_write_ascii ( stl_file stl,
const char *  file,
const char *  label 
)
71{
72 FILE *fp = boost::nowide::fopen(file, "w");
73 if (fp == nullptr) {
74 BOOST_LOG_TRIVIAL(error) << "stl_write_ascii: Couldn't open " << file << " for writing";
75 return false;
76 }
77
78 fprintf(fp, "solid %s\n", label);
79
80 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
81 fprintf(fp, " facet normal % .8E % .8E % .8E\n", stl->facet_start[i].normal(0), stl->facet_start[i].normal(1), stl->facet_start[i].normal(2));
82 fprintf(fp, " outer loop\n");
83 fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2));
84 fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2));
85 fprintf(fp, " vertex % .8E % .8E % .8E\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
86 fprintf(fp, " endloop\n");
87 fprintf(fp, " endfacet\n");
88 }
89
90 fprintf(fp, "endsolid %s\n", label);
91 fclose(fp);
92 return true;
93}

References error, stl_file::facet_start, stl_stats::number_of_facets, and stl_file::stats.

◆ stl_write_binary()

bool stl_write_binary ( stl_file stl,
const char *  file,
const char *  label 
)
129{
130 FILE *fp = boost::nowide::fopen(file, "wb");
131 if (fp == nullptr) {
132 BOOST_LOG_TRIVIAL(error) << "stl_write_binary: Couldn't open " << file << " for writing";
133 return false;
134 }
135
136 fprintf(fp, "%s", label);
137 for (size_t i = strlen(label); i < LABEL_SIZE; ++ i)
138 putc(0, fp);
139
140#if !defined(SEEK_SET)
141 #define SEEK_SET 0
142#endif
143 fseek(fp, LABEL_SIZE, SEEK_SET);
144#if BOOST_ENDIAN_LITTLE_BYTE
145 fwrite(&stl->stats.number_of_facets, 4, 1, fp);
146 for (const stl_facet &facet : stl->facet_start)
147 fwrite(&facet, SIZEOF_STL_FACET, 1, fp);
148#else /* BOOST_ENDIAN_LITTLE_BYTE */
149 char buffer[50];
150 // Convert the number of facets to little endian.
151 memcpy(buffer, &stl->stats.number_of_facets, 4);
152 stl_internal_reverse_quads(buffer, 4);
153 fwrite(buffer, 4, 1, fp);
154 for (const stl_facet &facet : stl->facet_start) {
155 memcpy(buffer, &facet, 50);
156 // Convert to little endian.
157 stl_internal_reverse_quads(buffer, 48);
158 fwrite(buffer, SIZEOF_STL_FACET, 1, fp);
159 }
160#endif /* BOOST_ENDIAN_LITTLE_BYTE */
161 fclose(fp);
162 return true;
163}
#define SIZEOF_STL_FACET
Definition stl.h:63
#define LABEL_SIZE
Definition stl.h:34
#define SEEK_SET

References error, stl_file::facet_start, LABEL_SIZE, stl_stats::number_of_facets, SEEK_SET, SIZEOF_STL_FACET, and stl_file::stats.

◆ stl_write_dxf()

bool stl_write_dxf ( stl_file stl,
const char *  file,
char *  label 
)
225{
226 FILE *fp = boost::nowide::fopen(file, "w");
227 if (fp == nullptr) {
228 BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
229 return false;
230 }
231
232 fprintf(fp, "999\n%s\n", label);
233 fprintf(fp, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n");
234 fprintf(fp, "0\nSECTION\n2\nTABLES\n0\nTABLE\n2\nLAYER\n70\n1\n\
235 0\nLAYER\n2\n0\n70\n0\n62\n7\n6\nCONTINUOUS\n0\nENDTAB\n0\nENDSEC\n");
236 fprintf(fp, "0\nSECTION\n2\nBLOCKS\n0\nENDSEC\n");
237
238 fprintf(fp, "0\nSECTION\n2\nENTITIES\n");
239
240 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
241 fprintf(fp, "0\n3DFACE\n8\n0\n");
242 fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2));
243 fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2));
244 fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
245 fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2));
246 }
247
248 fprintf(fp, "0\nENDSEC\n0\nEOF\n");
249 fclose(fp);
250 return true;
251}

References error, stl_file::facet_start, stl_stats::number_of_facets, and stl_file::stats.

◆ stl_write_facet()

void stl_write_facet ( stl_file stl,
char *  label,
int  facet 
)
174{
175 printf("facet (%d)/ %s\n", facet, label);
176 stl_write_vertex(stl, facet, 0);
177 stl_write_vertex(stl, facet, 1);
178 stl_write_vertex(stl, facet, 2);
179}
void stl_write_vertex(stl_file *stl, int facet, int vertex)
Definition stl_io.cpp:165

References stl_write_vertex().

Referenced by stl_verify_neighbors().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ stl_write_neighbor()

void stl_write_neighbor ( stl_file stl,
int  facet 
)
182{
183 printf("Neighbors %d: %d, %d, %d ; %d, %d, %d\n", facet,
184 stl->neighbors_start[facet].neighbor[0],
185 stl->neighbors_start[facet].neighbor[1],
186 stl->neighbors_start[facet].neighbor[2],
187 stl->neighbors_start[facet].which_vertex_not[0],
188 stl->neighbors_start[facet].which_vertex_not[1],
189 stl->neighbors_start[facet].which_vertex_not[2]);
190}

References stl_file::neighbors_start.

◆ stl_write_quad_object()

bool stl_write_quad_object ( stl_file stl,
char *  file 
)
193{
194 stl_vertex connect_color = stl_vertex::Zero();
195 stl_vertex uncon_1_color = stl_vertex::Zero();
196 stl_vertex uncon_2_color = stl_vertex::Zero();
197 stl_vertex uncon_3_color = stl_vertex::Zero();
198 stl_vertex color;
199
200 FILE *fp = boost::nowide::fopen(file, "w");
201 if (fp == nullptr) {
202 BOOST_LOG_TRIVIAL(error) << "stl_write_quad_object: Couldn't open " << file << " for writing";
203 return false;
204 }
205
206 fprintf(fp, "CQUAD\n");
207 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
208 switch (stl->neighbors_start[i].num_neighbors()) {
209 case 0:
210 default: color = uncon_3_color; break;
211 case 1: color = uncon_2_color; break;
212 case 2: color = uncon_1_color; break;
213 case 3: color = connect_color; break;
214 }
215 fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1), stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
216 fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1), stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
217 fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
218 fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n", stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1), stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
219 }
220 fclose(fp);
221 return true;
222}

References error, stl_file::facet_start, stl_file::neighbors_start, stl_stats::number_of_facets, and stl_file::stats.

◆ stl_write_vertex()

void stl_write_vertex ( stl_file stl,
int  facet,
int  vertex 
)
166{
167 printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
168 stl->facet_start[facet].vertex[vertex](0),
169 stl->facet_start[facet].vertex[vertex](1),
170 stl->facet_start[facet].vertex[vertex](2));
171}

References stl_file::facet_start.

Referenced by stl_write_facet().

+ Here is the caller graph for this function: