ASCII and Binary Stereo Lithography File readers. More...
#include <ReadSTL.hpp>
Classes | |
struct | Point |
struct | Triangle |
Public Types | |
enum | ByteOrder { STL_BIG_ENDIAN , STL_LITTLE_ENDIAN , STL_UNKNOWN_BYTE_ORDER } |
Public Member Functions | |
ErrorCode | load_file (const char *file_name, const EntityHandle *file_set, const FileOptions &opts, const SubsetList *subset_list=0, const Tag *file_id_tag=0) |
Generic file loading code for both binary and ASCII readers. Calls reader-specific read_triangles function to do actual I/O. More... | |
ErrorCode | read_tag_values (const char *file_name, const char *tag_name, const FileOptions &opts, std::vector< int > &tag_values_out, const SubsetList *subset_list=0) |
Read tag values from a file. More... | |
ReadSTL (Interface *impl=NULL) | |
Constructor. More... | |
virtual | ~ReadSTL () |
Destructor. More... | |
![]() | |
virtual | ~ReaderIface () |
Static Public Member Functions | |
static ReaderIface * | factory (Interface *) |
factory method for STL reader More... | |
Protected Member Functions | |
ErrorCode | ascii_read_triangles (const char *file_name, std::vector< Triangle > &tris_out) |
ErrorCode | binary_read_triangles (const char *file_name, ByteOrder byte_order, std::vector< Triangle > &tris_out) |
Protected Attributes | |
ReadUtilIface * | readMeshIface |
Interface * | mdbImpl |
interface instance More... | |
ASCII and Binary Stereo Lithography File readers.
STL files contain no connectivity infomration. Each triangle is specified as by three sets of single-precision coordinate triples. This reader does not use ANY tolerance when comparing vertex locations to recover connectivity. The points must be EXACTLY equal (including the sign on zero values.) If the file was written by an application which represented connectivity explicitly, there is no reason for the vertex coordinates to be anything other than exactly equal.
For binary STL files, the defacto standard is that they be written with a little-endian byte order. The reader will attempt to determine the byte order automatically, and if it is ambiguous, will default to little-endian. The byte ordering may be forced by by creating an integer tag named "__STL_BYTE_ORDER" and setting a global/mesh value for the tag as 1 for big-endian or 0 for little-endian.
For binary files, this reader relies on the file size to determine the validity of the file and may use it in guessing the byte order. This should not be an issue, as the file size can be determined exactly from the number of triangles for a valid file. However, if for some reason the file is readable even though it is invalid (e.g. it is some hybrid file with STL data in the beginning and some app- specific data appended to the end of the file) the check on the file size can be disabled by giving the reader a something other than a regular file to read from. For example, on Unix-like systems, have the reader read from a FIFO instead of a file: mkfifo /tmp/fifo.stlb cat my_binary_file.stlb > /tmp/fifo.stlb and instruct the MOAB-based application to read from /tmp/fifo.stlb
Definition at line 63 of file ReadSTL.hpp.
Enumerator | |
---|---|
STL_BIG_ENDIAN | |
STL_LITTLE_ENDIAN | |
STL_UNKNOWN_BYTE_ORDER |
Definition at line 103 of file ReadSTL.hpp.
104 { 105 STL_BIG_ENDIAN, 106 STL_LITTLE_ENDIAN, 107 STL_UNKNOWN_BYTE_ORDER 108 };
ReadSTL::ReadSTL | ( | Interface * | impl = NULL | ) |
Constructor.
Definition at line 40 of file ReadSTL.cpp.
40 : mdbImpl( impl ) 41 { 42 mdbImpl->query_interface( readMeshIface ); 43 }
References mdbImpl, moab::Interface::query_interface(), and readMeshIface.
Referenced by factory().
|
virtual |
Destructor.
Definition at line 45 of file ReadSTL.cpp.
46 {
47 if( readMeshIface )
48 {
49 mdbImpl->release_interface( readMeshIface );
50 readMeshIface = NULL;
51 }
52 }
References mdbImpl, readMeshIface, and moab::Interface::release_interface().
|
protected |
Definition at line 184 of file ReadSTL.cpp.
185 {
186 FILE* file = fopen( name, "r" );
187 if( !file )
188 {
189 return MB_FILE_DOES_NOT_EXIST;
190 }
191
192 char header[81];
193 if( !fgets( header, sizeof( header ), file ) || // Read header line
194 strlen( header ) < 6 || // Must be at least 6 chars
195 header[strlen( header ) - 1] != '\n' || // Cannot exceed 80 chars
196 memcmp( header, "solid", 5 ) || // Must begin with "solid"
197 !isspace( header[5] ) )
198 { // Followed by a whitespace char
199 fclose( file );
200 return MB_FILE_WRITE_ERROR;
201 }
202
203 // Use tokenizer for remainder of parsing
204 FileTokenizer tokens( file, readMeshIface );
205
206 Triangle tri;
207 float norm[3];
208
209 // Read until end of file. If we reach "endsolid", read
210 // was successful. If EOF before "endsolid", return error.
211 for( ;; )
212 {
213 // Check for either another facet or the end of the list.
214 const char* const expected[] = { "facet", "endsolid", 0 };
215 switch( tokens.match_token( expected ) )
216 {
217 case 1:
218 break; // Found another facet
219 case 2:
220 return MB_SUCCESS; // Found "endsolid" -- done
221 default:
222 return MB_FILE_WRITE_ERROR; // Found something else, or EOF
223 }
224
225 if( !tokens.match_token( "normal" ) || // Expect "normal" keyword
226 !tokens.get_floats( 3, norm ) || // Followed by normal vector
227 !tokens.match_token( "outer" ) || // Followed by "outer loop"
228 !tokens.match_token( "loop" ) )
229 return MB_FILE_WRITE_ERROR;
230
231 // For each of three triangle vertices
232 for( int i = 0; i < 3; i++ )
233 {
234 if( !tokens.match_token( "vertex" ) || !tokens.get_floats( 3, tri.points[i].coords ) )
235 return MB_FILE_WRITE_ERROR;
236 }
237
238 if( !tokens.match_token( "endloop" ) || // Facet ends with "endloop"
239 !tokens.match_token( "endfacet" ) ) // and then "endfacet"
240 return MB_FILE_WRITE_ERROR;
241
242 tris.push_back( tri );
243 }
244
245 fclose( file );
246 return MB_SUCCESS;
247 }
References moab::ReadSTL::Point::coords, moab::FileTokenizer::get_floats(), moab::FileTokenizer::match_token(), MB_FILE_DOES_NOT_EXIST, MB_FILE_WRITE_ERROR, MB_SUCCESS, moab::ReadSTL::Triangle::points, and readMeshIface.
Referenced by load_file().
|
protected |
Definition at line 265 of file ReadSTL.cpp.
268 {
269 FILE* file = fopen( name, "rb" );
270 if( !file )
271 {
272 return MB_FILE_DOES_NOT_EXIST;
273 }
274
275 // Read header block
276 BinaryHeader header;
277 if( fread( &header, 84, 1, file ) != 1 )
278 {
279 fclose( file );
280 return MB_FILE_WRITE_ERROR;
281 }
282
283 // Allow user setting for byte order, default to little endian
284 const bool want_big_endian = ( byte_order == STL_BIG_ENDIAN );
285 const bool am_big_endian = !SysUtil::little_endian();
286 bool swap_bytes = ( want_big_endian == am_big_endian );
287
288 // Compare the number of triangles to the length of the file.
289 // The file must contain an 80-byte description, a 4-byte
290 // triangle count and 50 bytes per triangle.
291 //
292 // The triangle count *may* allow us to determine the byte order
293 // of the file, if it is not an endian-symmetric value.
294 //
295 // We need to compare the expected size calculated from the triangle
296 // count with the file size anyway, as an invalid file or a byte-
297 // swapping issue could result in a very large (incorrect) value for
298 // num_tri, resulting in a SEGFAULT.
299
300 // Get expected number of triangles
301 if( swap_bytes ) SysUtil::byteswap( &header.count, 1 );
302 unsigned long num_tri = header.count;
303
304 // Get the file length
305 long filesize = SysUtil::filesize( file );
306 if( filesize >= 0 )
307 { // -1 indicates could not determine file size (e.g. reading from FIFO)
308 // Check file size, but be careful of numeric overflow
309 if( ULONG_MAX / 50 - 84 < num_tri || // Next calc would have overflow
310 84 + 50 * num_tri != (unsigned long)filesize )
311 {
312 // Unless the byte order was specified explicitly in the
313 // tag, try the opposite byte order.
314 uint32_t num_tri_tmp = header.count;
315 SysUtil::byteswap( &num_tri_tmp, 1 );
316 unsigned long num_tri_swap = num_tri_tmp;
317 if( byte_order != STL_UNKNOWN_BYTE_ORDER || // If byte order was specified, fail now
318 ULONG_MAX / 50 - 84 < num_tri_swap || // Watch for overflow in next line
319 84 + 50 * num_tri_swap != (unsigned long)filesize )
320 {
321 fclose( file );
322 return MB_FILE_WRITE_ERROR;
323 }
324 swap_bytes = !swap_bytes;
325 num_tri = num_tri_swap;
326 }
327 }
328
329 // Allocate storage for triangles
330 tris.resize( num_tri );
331
332 // Read each triangle
333 BinaryTri tri; // Binary block read from file
334 for( std::vector< Triangle >::iterator i = tris.begin(); i != tris.end(); ++i )
335 {
336 if( fread( &tri, 50, 1, file ) != 1 )
337 {
338 fclose( file );
339 return MB_FILE_WRITE_ERROR;
340 }
341
342 if( swap_bytes ) SysUtil::byteswap( tri.coords, 9 );
343
344 for( unsigned j = 0; j < 9; ++j )
345 i->points[j / 3].coords[j % 3] = tri.coords[j];
346 }
347
348 fclose( file );
349 return MB_SUCCESS;
350 }
References moab::SysUtil::byteswap(), moab::BinaryTri::coords, moab::BinaryHeader::count, moab::SysUtil::filesize(), moab::SysUtil::little_endian(), MB_FILE_DOES_NOT_EXIST, MB_FILE_WRITE_ERROR, MB_SUCCESS, STL_BIG_ENDIAN, STL_UNKNOWN_BYTE_ORDER, and moab::SysUtil::swap_bytes().
Referenced by load_file().
|
static |
factory method for STL reader
Definition at line 352 of file ReadSTL.cpp.
353 {
354 return new ReadSTL( iface );
355 }
References iface, and ReadSTL().
Referenced by moab::ReaderWriterSet::ReaderWriterSet().
|
virtual |
Generic file loading code for both binary and ASCII readers. Calls reader-specific read_triangles function to do actual I/O.
Implements moab::ReaderIface.
Definition at line 72 of file ReadSTL.cpp.
77 {
78 if( subset_list )
79 {
80 MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "Reading subset of files not supported for STL" );
81 }
82
83 ErrorCode result;
84
85 std::vector< ReadSTL::Triangle > triangles;
86
87 bool is_ascii = false, is_binary = false;
88 if( MB_SUCCESS == opts.get_null_option( "ASCII" ) ) is_ascii = true;
89 if( MB_SUCCESS == opts.get_null_option( "BINARY" ) ) is_binary = true;
90 if( is_ascii && is_binary )
91 {
92 MB_SET_ERR( MB_FAILURE, "Conflicting options: BINARY ASCII" );
93 }
94
95 bool big_endian = false, little_endian = false;
96 if( MB_SUCCESS == opts.get_null_option( "BIG_ENDIAN" ) ) big_endian = true;
97 if( MB_SUCCESS == opts.get_null_option( "LITTLE_ENDIAN" ) ) little_endian = true;
98 if( big_endian && little_endian )
99 {
100 MB_SET_ERR( MB_FAILURE, "Conflicting options: BIG_ENDIAN LITTLE_ENDIAN" );
101 }
102 ByteOrder byte_order = big_endian ? STL_BIG_ENDIAN : little_endian ? STL_LITTLE_ENDIAN : STL_UNKNOWN_BYTE_ORDER;
103
104 if( is_ascii )
105 result = ascii_read_triangles( filename, triangles );
106 else if( is_binary )
107 result = binary_read_triangles( filename, byte_order, triangles );
108 else
109 {
110 // Try ASCII first
111 result = ascii_read_triangles( filename, triangles );
112 if( MB_SUCCESS != result )
113 // ASCII failed, try binary
114 result = binary_read_triangles( filename, byte_order, triangles );
115 }
116 if( MB_SUCCESS != result ) return result;
117
118 // Create a std::map from position->handle, and such
119 // that all positions are specified, and handles are zero.
120 std::map< Point, EntityHandle > vertex_map;
121 for( std::vector< Triangle >::iterator i = triangles.begin(); i != triangles.end(); ++i )
122 {
123 vertex_map[i->points[0]] = 0;
124 vertex_map[i->points[1]] = 0;
125 vertex_map[i->points[2]] = 0;
126 }
127
128 // Create vertices
129 std::vector< double* > coord_arrays;
130 EntityHandle vtx_handle = 0;
131 result = readMeshIface->get_node_coords( 3, vertex_map.size(), MB_START_ID, vtx_handle, coord_arrays );
132 if( MB_SUCCESS != result ) return result;
133
134 // Copy vertex coordinates into entity sequence coordinate arrays
135 // and copy handle into vertex_map.
136 double *x = coord_arrays[0], *y = coord_arrays[1], *z = coord_arrays[2];
137 for( std::map< Point, EntityHandle >::iterator i = vertex_map.begin(); i != vertex_map.end(); ++i )
138 {
139 i->second = vtx_handle;
140 ++vtx_handle;
141 *x = i->first.coords[0];
142 ++x;
143 *y = i->first.coords[1];
144 ++y;
145 *z = i->first.coords[2];
146 ++z;
147 }
148
149 // Allocate triangles
150 EntityHandle elm_handle = 0;
151 EntityHandle* connectivity;
152 result = readMeshIface->get_element_connect( triangles.size(), 3, MBTRI, MB_START_ID, elm_handle, connectivity );
153 if( MB_SUCCESS != result ) return result;
154
155 // Use vertex_map to recover triangle connectivity from
156 // vertex coordinates.
157 EntityHandle* conn_sav = connectivity;
158 for( std::vector< Triangle >::iterator i = triangles.begin(); i != triangles.end(); ++i )
159 {
160 *connectivity = vertex_map[i->points[0]];
161 ++connectivity;
162 *connectivity = vertex_map[i->points[1]];
163 ++connectivity;
164 *connectivity = vertex_map[i->points[2]];
165 ++connectivity;
166 }
167
168 // Notify MOAB of the new elements
169 result = readMeshIface->update_adjacencies( elm_handle, triangles.size(), 3, conn_sav );
170 if( MB_SUCCESS != result ) return result;
171
172 if( file_id_tag )
173 {
174 Range vertices( vtx_handle, vtx_handle + vertex_map.size() - 1 );
175 Range elements( elm_handle, elm_handle + triangles.size() - 1 );
176 readMeshIface->assign_ids( *file_id_tag, vertices );
177 readMeshIface->assign_ids( *file_id_tag, elements );
178 }
179
180 return MB_SUCCESS;
181 }
References ascii_read_triangles(), moab::ReadUtilIface::assign_ids(), moab::SysUtil::big_endian(), binary_read_triangles(), ErrorCode, moab::ReadUtilIface::get_element_connect(), moab::ReadUtilIface::get_node_coords(), moab::FileOptions::get_null_option(), moab::SysUtil::little_endian(), MB_SET_ERR, MB_START_ID, MB_SUCCESS, MB_UNSUPPORTED_OPERATION, MBTRI, readMeshIface, STL_BIG_ENDIAN, STL_LITTLE_ENDIAN, STL_UNKNOWN_BYTE_ORDER, and moab::ReadUtilIface::update_adjacencies().
|
virtual |
Read tag values from a file.
Read the list if all integer tag values from the file for a tag that is a single integer value per entity.
file_name | The file to read. |
tag_name | The tag for which to read values |
tag_values_out | Output: The list of tag values. |
subset_list | An array of tag name and value sets specifying the subset of the file to read. If multiple tags are specified, the sets that match all tags (intersection) should be read. |
subset_list_length | The length of the 'subset_list' array. |
Implements moab::ReaderIface.
Definition at line 60 of file ReadSTL.cpp.
65 {
66 return MB_NOT_IMPLEMENTED;
67 }
References MB_NOT_IMPLEMENTED.
|
protected |
interface instance
Definition at line 120 of file ReadSTL.hpp.
Referenced by ReadSTL(), and ~ReadSTL().
|
protected |
Definition at line 117 of file ReadSTL.hpp.
Referenced by ascii_read_triangles(), load_file(), ReadSTL(), and ~ReadSTL().