Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
stlinit.cpp File Reference
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <boost/log/trivial.hpp>
#include <boost/nowide/cstdio.hpp>
#include <boost/predef/other/endian.h>
#include "stl.h"
#include "libslic3r/LocalesUtils.hpp"
+ Include dependency graph for stlinit.cpp:

Go to the source code of this file.

Functions

static FILE * stl_open_count_facets (stl_file *stl, const char *file)
 
static bool stl_read (stl_file *stl, FILE *fp, int first_facet, bool first)
 
bool stl_open (stl_file *stl, const char *file)
 
void stl_allocate (stl_file *stl)
 
void stl_reallocate (stl_file *stl)
 
void stl_facet_stats (stl_file *stl, stl_facet facet, bool &first)
 

Function Documentation

◆ 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
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
Definition stl.h:72
uint32_t number_of_facets
Definition stl.h:95

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_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 vertex[3]
Definition stl.h:50
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_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}
Definition LocalesUtils.hpp:18
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_open_count_facets()

static FILE * stl_open_count_facets ( stl_file stl,
const char *  file 
)
static
46{
47 // Open the file in binary mode first.
48 FILE *fp = boost::nowide::fopen(file, "rb");
49 if (fp == nullptr) {
50 BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading";
51 return nullptr;
52 }
53 // Find size of file.
54 fseek(fp, 0, SEEK_END);
55 long file_size = ftell(fp);
56
57 // Check for binary or ASCII file.
58 fseek(fp, HEADER_SIZE, SEEK_SET);
59 unsigned char chtest[128];
60 if (! fread(chtest, sizeof(chtest), 1, fp)) {
61 BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The input is an empty file: " << file;
62 fclose(fp);
63 return nullptr;
64 }
65 stl->stats.type = ascii;
66 for (size_t s = 0; s < sizeof(chtest); s++) {
67 if (chtest[s] > 127) {
68 stl->stats.type = binary;
69 break;
70 }
71 }
72 rewind(fp);
73
74 uint32_t num_facets = 0;
75
76 // Get the header and the number of facets in the .STL file.
77 // If the .STL file is binary, then do the following:
78 if (stl->stats.type == binary) {
79 // Test if the STL file has the right size.
80 if (((file_size - HEADER_SIZE) % SIZEOF_STL_FACET != 0) || (file_size < STL_MIN_FILE_SIZE)) {
81 BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: The file " << file << " has the wrong size.";
82 fclose(fp);
83 return nullptr;
84 }
85 num_facets = (file_size - HEADER_SIZE) / SIZEOF_STL_FACET;
86
87 // Read the header.
88 if (fread(stl->stats.header, LABEL_SIZE, 1, fp) > 79)
89 stl->stats.header[80] = '\0';
90
91 // Read the int following the header. This should contain # of facets.
92 uint32_t header_num_facets;
93 bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, fp) != 0;
94#if BOOST_ENDIAN_BIG_BYTE
95 // Convert from little endian to big endian.
96 stl_internal_reverse_quads((char*)&header_num_facets, 4);
97#endif /* BOOST_ENDIAN_BIG_BYTE */
98 if (! header_num_faces_read || num_facets != header_num_facets)
99 BOOST_LOG_TRIVIAL(info) << "stl_open_count_facets: Warning: File size doesn't match number of facets in the header: " << file;
100 }
101 // Otherwise, if the .STL file is ASCII, then do the following:
102 else
103 {
104 // Reopen the file in text mode (for getting correct newlines on Windows)
105 // fix to silence a warning about unused return value.
106 // obviously if it fails we have problems....
107 fp = boost::nowide::freopen(file, "r", fp);
108
109 // do another null check to be safe
110 if (fp == nullptr) {
111 BOOST_LOG_TRIVIAL(error) << "stl_open_count_facets: Couldn't open " << file << " for reading";
112 fclose(fp);
113 return nullptr;
114 }
115
116 // Find the number of facets.
117 char linebuf[100];
118 int num_lines = 1;
119 while (fgets(linebuf, 100, fp) != nullptr) {
120 // Don't count short lines.
121 if (strlen(linebuf) <= 4)
122 continue;
123 // Skip solid/endsolid lines as broken STL file generators may put several of them.
124 if (strncmp(linebuf, "solid", 5) == 0 || strncmp(linebuf, "endsolid", 8) == 0)
125 continue;
126 ++ num_lines;
127 }
128
129 rewind(fp);
130
131 // Get the header.
132 int i = 0;
133 for (; i < 80 && (stl->stats.header[i] = getc(fp)) != '\n'; ++ i) ;
134 stl->stats.header[i] = '\0'; // Lose the '\n'
135 stl->stats.header[80] = '\0';
136
137 num_facets = num_lines / ASCII_LINES_PER_FACET;
138 }
139
140 stl->stats.number_of_facets += num_facets;
142 return fp;
143}
@ ascii
Definition stl.h:70
@ binary
Definition stl.h:70
#define HEADER_SIZE
Definition stl.h:38
#define SIZEOF_STL_FACET
Definition stl.h:63
#define STL_MIN_FILE_SIZE
Definition stl.h:39
#define ASCII_LINES_PER_FACET
Definition stl.h:40
#define LABEL_SIZE
Definition stl.h:34
#define SEEK_SET
stl_type type
Definition stl.h:93
char header[81]
Definition stl.h:92
int original_num_facets
Definition stl.h:116
static char error[256]
Definition tga.cpp:50
unsigned __int32 uint32_t
Definition unistd.h:79

References ascii, ASCII_LINES_PER_FACET, binary, error, stl_stats::header, HEADER_SIZE, LABEL_SIZE, stl_stats::number_of_facets, stl_stats::original_num_facets, SEEK_SET, SIZEOF_STL_FACET, stl_file::stats, STL_MIN_FILE_SIZE, and stl_stats::type.

Referenced by stl_open().

+ Here is the caller graph for this function:

◆ stl_read()

static bool stl_read ( stl_file stl,
FILE *  fp,
int  first_facet,
bool  first 
)
static
149{
150 if (stl->stats.type == binary)
151 fseek(fp, HEADER_SIZE, SEEK_SET);
152 else
153 rewind(fp);
154
155 char normal_buf[3][32];
156 for (uint32_t i = first_facet; i < stl->stats.number_of_facets; ++ i) {
157 stl_facet facet;
158
159 if (stl->stats.type == binary) {
160 // Read a single facet from a binary .STL file. We assume little-endian architecture!
161 if (fread(&facet, 1, SIZEOF_STL_FACET, fp) != SIZEOF_STL_FACET)
162 return false;
163#if BOOST_ENDIAN_BIG_BYTE
164 // Convert the loaded little endian data to big endian.
165 stl_internal_reverse_quads((char*)&facet, 48);
166#endif /* BOOST_ENDIAN_BIG_BYTE */
167 } else {
168 // Read a single facet from an ASCII .STL file
169 // skip solid/endsolid
170 // (in this order, otherwise it won't work when they are paired in the middle of a file)
171 fscanf(fp, " endsolid%*[^\n]\n");
172 fscanf(fp, " solid%*[^\n]\n"); // name might contain spaces so %*s doesn't work and it also can be empty (just "solid")
173 // Leading space in the fscanf format skips all leading white spaces including numerous new lines and tabs.
174 int res_normal = fscanf(fp, " facet normal %31s %31s %31s", normal_buf[0], normal_buf[1], normal_buf[2]);
175 assert(res_normal == 3);
176 int res_outer_loop = fscanf(fp, " outer loop");
177 assert(res_outer_loop == 0);
178 int res_vertex1 = fscanf(fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
179 assert(res_vertex1 == 3);
180 int res_vertex2 = fscanf(fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
181 assert(res_vertex2 == 3);
182 // Trailing whitespace is there to eat all whitespaces and empty lines up to the next non-whitespace.
183 int res_vertex3 = fscanf(fp, " vertex %f %f %f ", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
184 assert(res_vertex3 == 3);
185 // Some G-code generators tend to produce text after "endloop" and "endfacet". Just ignore it.
186 char buf[2048];
187 fgets(buf, 2047, fp);
188 bool endloop_ok = strncmp(buf, "endloop", 7) == 0 && (buf[7] == '\r' || buf[7] == '\n' || buf[7] == ' ' || buf[7] == '\t');
189 assert(endloop_ok);
190 // Skip the trailing whitespaces and empty lines.
191 fscanf(fp, " ");
192 fgets(buf, 2047, fp);
193 bool endfacet_ok = strncmp(buf, "endfacet", 8) == 0 && (buf[8] == '\r' || buf[8] == '\n' || buf[8] == ' ' || buf[8] == '\t');
194 assert(endfacet_ok);
195 if (res_normal != 3 || res_outer_loop != 0 || res_vertex1 != 3 || res_vertex2 != 3 || res_vertex3 != 3 || ! endloop_ok || ! endfacet_ok) {
196 BOOST_LOG_TRIVIAL(error) << "Something is syntactically very wrong with this ASCII STL! ";
197 return false;
198 }
199
200 // The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
201 if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
202 sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
203 sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
204 // Normal was mangled. Maybe denormals or "not a number" were stored?
205 // Just reset the normal and silently ignore it.
206 memset(&facet.normal, 0, sizeof(facet.normal));
207 }
208 }
209
210#if 0
211 // Report close to zero vertex coordinates. Due to the nature of the floating point numbers,
212 // close to zero values may be represented with singificantly higher precision than the rest of the vertices.
213 // It may be worth to round these numbers to zero during loading to reduce the number of errors reported
214 // during the STL import.
215 for (size_t j = 0; j < 3; ++ j) {
216 if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f)
217 printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0));
218 if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f)
219 printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1));
220 if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f)
221 printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2));
222 }
223#endif
224
225 // Write the facet into memory.
226 stl->facet_start[i] = facet;
227 stl_facet_stats(stl, facet, first);
228 }
229
230 stl->stats.size = stl->stats.max - stl->stats.min;
231 stl->stats.bounding_diameter = stl->stats.size.norm();
232 return true;
233}
void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first)
Definition stlinit.cpp:262
stl_normal normal
Definition stl.h:49
stl_vertex size
Definition stl.h:99
float bounding_diameter
Definition stl.h:100

References binary, stl_stats::bounding_diameter, error, stl_file::facet_start, HEADER_SIZE, stl_stats::max, stl_stats::min, stl_facet::normal, stl_stats::number_of_facets, SEEK_SET, stl_stats::size, SIZEOF_STL_FACET, stl_file::stats, stl_facet_stats(), stl_stats::type, and stl_facet::vertex.

Referenced by stl_open().

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

◆ stl_reallocate()

void stl_reallocate ( stl_file stl)