1
15
16 #include "ReadOBJ.hpp"
17 #include <iostream>
18 #include <sstream>
19 #include <fstream>
20 #include <vector>
21 #include <cstdlib>
22 #include <map>
23 #include <cassert>
24 #include <cmath>
25
26 #include "moab/Core.hpp"
27 #include "moab/Interface.hpp"
28 #include "moab/ReadUtilIface.hpp"
29 #include "Internals.hpp"
30 #include "moab/Range.hpp"
31 #include "moab/CartVect.hpp"
32 #include "moab/FileOptions.hpp"
33 #include "FileTokenizer.hpp"
34 #include "MBTagConventions.hpp"
35 #include "moab/CN.hpp"
36 #include "moab/GeomTopoTool.hpp"
37
38 namespace moab
39 {
40
41 ReaderIface* ReadOBJ::factory( Interface* iface )
42 {
43 return new ReadOBJ( iface );
44 }
45
46
47 const char* ReadOBJ::delimiters = " ";
48 const char* object_start_token = "o";
49 const char* group_start_token = "g";
50 const char* vertex_start_token = "v";
51 const char* face_start_token = "f";
52
53 #define OBJ_AMBIGUOUS "AMBIGUOUS"
54 #define OBJ_UNDEFINED "UNDEFINED"
55
56
57 const char* const geom_name[] = { "Vertex\0", "Curve\0", "Surface\0", "Volume\0" };
58
59
60 const char geom_category[][CATEGORY_TAG_SIZE] = { "Vertex\0", "Curve\0", "Surface\0", "Volume\0", "Group\0" };
61
62
63 ReadOBJ::ReadOBJ( Interface* impl )
64 : MBI( impl ), geom_tag( 0 ), id_tag( 0 ), name_tag( 0 ), category_tag( 0 ), faceting_tol_tag( 0 ),
65 geometry_resabs_tag( 0 ), obj_name_tag( 0 )
66 {
67 assert( NULL != impl );
68 MBI->query_interface( readMeshIface );
69 myGeomTool = new GeomTopoTool( impl );
70 assert( NULL != readMeshIface );
71
72
73 int negone = -1;
74 ErrorCode rval;
75 rval = MBI->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geom_tag, MB_TAG_SPARSE | MB_TAG_CREAT,
76 &negone );MB_CHK_ERR_RET( rval );
77
78 id_tag = MBI->globalId_tag();
79
80 rval = MBI->tag_get_handle( NAME_TAG_NAME, NAME_TAG_SIZE, MB_TYPE_OPAQUE, name_tag, MB_TAG_SPARSE | MB_TAG_CREAT );MB_CHK_ERR_RET( rval );
81
82 rval = MBI->tag_get_handle( CATEGORY_TAG_NAME, CATEGORY_TAG_SIZE, MB_TYPE_OPAQUE, category_tag,
83 MB_TAG_SPARSE | MB_TAG_CREAT );MB_CHK_ERR_RET( rval );
84
85 rval = MBI->tag_get_handle( "OBJECT_NAME", 32, MB_TYPE_OPAQUE, obj_name_tag, MB_TAG_SPARSE | MB_TAG_CREAT );MB_CHK_ERR_RET( rval );
86
87 rval = MBI->tag_get_handle( "FACETING_TOL", 1, MB_TYPE_DOUBLE, faceting_tol_tag, MB_TAG_SPARSE | MB_TAG_CREAT );MB_CHK_ERR_RET( rval );
88
89 rval =
90 MBI->tag_get_handle( "GEOMETRY_RESABS", 1, MB_TYPE_DOUBLE, geometry_resabs_tag, MB_TAG_SPARSE | MB_TAG_CREAT );MB_CHK_ERR_RET( rval );
91 }
92
93
94 ReadOBJ::~ReadOBJ()
95 {
96 if( readMeshIface )
97 {
98 MBI->release_interface( readMeshIface );
99 readMeshIface = 0;
100 }
101
102 delete myGeomTool;
103 }
104
105 ErrorCode ReadOBJ::read_tag_values( const char* ,
106 const char* ,
107 const FileOptions& ,
108 std::vector< int >& ,
109 const SubsetList* )
110 {
111 return MB_NOT_IMPLEMENTED;
112 }
113
114
115 ErrorCode ReadOBJ::load_file( const char* filename,
116 const EntityHandle*,
117 const FileOptions&,
118 const ReaderIface::SubsetList* subset_list,
119 const Tag* )
120 {
121 ErrorCode rval;
122 int ignored = 0;
123 std::string line;
124 EntityHandle vert_meshset;
125 EntityHandle curr_meshset;
126 std::string object_name;
127 std::vector< EntityHandle > vertex_list;
128 int object_id = 0, group_id = 0;
129 int num_groups;
130
131
132 if( subset_list )
133 {
134 MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "Reading subset of files not supported for OBJ." );
135 }
136
137 std::ifstream input_file( filename );
138
139
140 if( !input_file.good() )
141 {
142 std::cout << "Problems reading file = " << filename << std::endl;
143 return MB_FILE_DOES_NOT_EXIST;
144 }
145
146
147 if( input_file.is_open() )
148 {
149
150
151 rval = MBI->create_meshset( MESHSET_SET, vert_meshset );MB_CHK_SET_ERR( rval, "Failed to create global vert meshset." );
152
153 while( std::getline( input_file, line ) )
154 {
155
156 if( line.length() == 0 ) continue;
157
158
159 std::vector< std::string > tokens;
160 tokenize( line, tokens, delimiters );
161
162
163
164 if( tokens.size() < 2 ) continue;
165
166 switch( get_keyword( tokens ) )
167 {
168
169 case object_start: {
170 object_id++;
171 object_name = tokens[1];
172
173
174 rval = create_new_object( object_name, object_id, curr_meshset );MB_CHK_ERR( rval );
175 break;
176 }
177
178
179 case group_start: {
180 group_id++;
181 num_groups = tokens.size() - 1;
182 std::string group_name = "Group";
183 for( int i = 0; i < num_groups; i++ )
184 {
185 group_name = group_name + '_' + tokens[i + 1];
186 }
187
188
189 rval = create_new_group( group_name, group_id, curr_meshset );MB_CHK_ERR( rval );
190 break;
191 }
192
193
194 case vertex_start: {
195
196 EntityHandle new_vertex_eh;
197 rval = create_new_vertex( tokens, new_vertex_eh );MB_CHK_ERR( rval );
198
199
200 vertex_list.push_back( new_vertex_eh );
201
202
203 MBI->add_entities( vert_meshset, &new_vertex_eh, 1 );MB_CHK_SET_ERR( rval, "Failed to add vertex to global meshset." );
204 break;
205 }
206
207
208 case face_start: {
209
210
211
212 EntityHandle new_face_eh;
213
214 if( tokens.size() == 4 )
215 {
216 rval = create_new_face( tokens, vertex_list, new_face_eh );MB_CHK_ERR( rval );
217
218 if( rval == MB_SUCCESS )
219 {
220
221 MBI->add_entities( curr_meshset, &new_face_eh, 1 );
222 }
223 }
224
225 else if( tokens.size() == 5 )
226 {
227
228 Range new_faces_eh;
229 rval = split_quad( tokens, vertex_list, new_faces_eh );MB_CHK_ERR( rval );
230
231
232 if( rval == MB_SUCCESS )
233 {
234 MBI->add_entities( curr_meshset, new_faces_eh );
235 }
236 }
237
238 else
239 {
240 std::cout << "Neither tri nor a quad: " << line << std::endl;
241 }
242
243 break;
244 }
245
246 case valid_unsupported: {
247
248 ++ignored;
249 break;
250 }
251
252 default: {
253 MB_SET_ERR( MB_FAILURE, "Invalid/unrecognized line" );
254 }
255 }
256 }
257 }
258
259
260 if( object_id == 0 && group_id == 0 )
261 {
262 MB_SET_ERR( MB_FAILURE, "This is not an obj file. " );
263 }
264
265 std::cout << "There were " << ignored << " ignored lines in this file." << std::endl;
266
267 input_file.close();
268
269 return MB_SUCCESS;
270 }
271
272
275 void ReadOBJ::tokenize( const std::string& str, std::vector< std::string >& tokens, const char* delimiters2 )
276 {
277 tokens.clear();
278
279 std::string::size_type next_token_end, next_token_start = str.find_first_not_of( delimiters2, 0 );
280
281 while( std::string::npos != next_token_start )
282 {
283 next_token_end = str.find_first_of( delimiters2, next_token_start );
284 if( std::string::npos == next_token_end )
285 {
286 tokens.push_back( str.substr( next_token_start ) );
287 next_token_start = std::string::npos;
288 }
289 else
290 {
291 tokens.push_back( str.substr( next_token_start, next_token_end - next_token_start ) );
292 next_token_start = str.find_first_not_of( delimiters2, next_token_end );
293 }
294 }
295 }
296
297 keyword_type ReadOBJ::get_keyword( std::vector< std::string > tokens )
298 {
299 std::map< std::string, keyword_type > keywords;
300
301
302 keywords["o"] = object_start;
303 keywords["g"] = group_start;
304 keywords["f"] = face_start;
305 keywords["v"] = vertex_start;
306
307
308 keywords["vn"] = valid_unsupported;
309 keywords["vt"] = valid_unsupported;
310 keywords["vp"] = valid_unsupported;
311 keywords["s"] = valid_unsupported;
312 keywords["mtllib"] = valid_unsupported;
313 keywords["usemtl"] = valid_unsupported;
314 keywords["#"] = valid_unsupported;
315 keywords["cstype"] = valid_unsupported;
316 keywords["deg"] = valid_unsupported;
317 keywords["bmat"] = valid_unsupported;
318 keywords["step"] = valid_unsupported;
319 keywords["p"] = valid_unsupported;
320 keywords["l"] = valid_unsupported;
321 keywords["curv"] = valid_unsupported;
322 keywords["curv2"] = valid_unsupported;
323 keywords["surf"] = valid_unsupported;
324 keywords["parm"] = valid_unsupported;
325 keywords["trim"] = valid_unsupported;
326 keywords["hole"] = valid_unsupported;
327 keywords["scrv"] = valid_unsupported;
328 keywords["sp"] = valid_unsupported;
329 keywords["end"] = valid_unsupported;
330 keywords["mg"] = valid_unsupported;
331 keywords["bevel"] = valid_unsupported;
332 keywords["c_interp"] = valid_unsupported;
333 keywords["d_interp"] = valid_unsupported;
334 keywords["lod"] = valid_unsupported;
335 keywords["shadow_obj"] = valid_unsupported;
336 keywords["trace_obj"] = valid_unsupported;
337 keywords["ctech"] = valid_unsupported;
338 keywords["stech"] = valid_unsupported;
339
340 return keywords[match( tokens[0], keywords )];
341 }
342
343 template < typename T >
344 std::string ReadOBJ::match( const std::string& token, std::map< std::string, T >& tokenList )
345 {
346
347 std::string best_match = OBJ_UNDEFINED;
348
349
350 for( typename std::map< std::string, T >::iterator thisToken = tokenList.begin(); thisToken != tokenList.end();
351 ++thisToken )
352 {
353
354 if( token == ( *thisToken ).first )
355 {
356 best_match = token;
357 break;
358 }
359 }
360
361
362 return best_match;
363 }
364
365
369 ErrorCode ReadOBJ::create_new_object( std::string object_name, int curr_object, EntityHandle& object_meshset )
370 {
371 ErrorCode rval;
372
373
374
375 rval = MBI->create_meshset( MESHSET_SET, object_meshset );MB_CHK_SET_ERR( rval, "Failed to generate object mesh set." );
376
377
378 rval = MBI->tag_set_data( name_tag, &object_meshset, 1, object_name.c_str() );MB_CHK_SET_ERR( rval, "Failed to set mesh set name tag." );
379
380 rval = MBI->tag_set_data( id_tag, &object_meshset, 1, &( curr_object ) );MB_CHK_SET_ERR( rval, "Failed to set mesh set ID tag." );
381
382 int dim = 2;
383 rval = MBI->tag_set_data( geom_tag, &object_meshset, 1, &( dim ) );MB_CHK_SET_ERR( rval, "Failed to set mesh set dim tag." );
384
385 rval = MBI->tag_set_data( category_tag, &object_meshset, 1, geom_category[2] );MB_CHK_SET_ERR( rval, "Failed to set mesh set category tag." );
386
387
391 EntityHandle vol_meshset;
392 rval = MBI->create_meshset( MESHSET_SET, vol_meshset );MB_CHK_SET_ERR( rval, "Failed to create volume mesh set." );
393
394 rval = MBI->add_parent_child( vol_meshset, object_meshset );MB_CHK_SET_ERR( rval, "Failed to add object mesh set as child of volume mesh set." );
395
396
400 rval = MBI->tag_set_data( obj_name_tag, &vol_meshset, 1, object_name.c_str() );MB_CHK_SET_ERR( rval, "Failed to set mesh set name tag." );
401
402 rval = MBI->tag_set_data( id_tag, &vol_meshset, 1, &( curr_object ) );MB_CHK_SET_ERR( rval, "Failed to set mesh set ID tag." );
403
404 dim = 3;
405 rval = MBI->tag_set_data( geom_tag, &vol_meshset, 1, &( dim ) );MB_CHK_SET_ERR( rval, "Failed to set mesh set dim tag." );
406
407 rval = MBI->tag_set_data( name_tag, &vol_meshset, 1, geom_name[3] );MB_CHK_SET_ERR( rval, "Failed to set mesh set name tag." );
408
409 rval = MBI->tag_set_data( category_tag, &vol_meshset, 1, geom_category[3] );MB_CHK_SET_ERR( rval, "Failed to set mesh set category tag." );
410
411 rval = myGeomTool->set_sense( object_meshset, vol_meshset, SENSE_FORWARD );MB_CHK_SET_ERR( rval, "Failed to set surface sense." );
412
413 return rval;
414 }
415
416
420 ErrorCode ReadOBJ::create_new_group( std::string group_name, int curr_group, EntityHandle& group_meshset )
421 {
422 ErrorCode rval;
423
424
425 rval = MBI->create_meshset( MESHSET_SET, group_meshset );MB_CHK_SET_ERR( rval, "Failed to generate group mesh set." );
426
427
428 rval = MBI->tag_set_data( name_tag, &group_meshset, 1, group_name.c_str() );MB_CHK_SET_ERR( rval, "Failed to set mesh set name tag." );
429
430 rval = MBI->tag_set_data( id_tag, &group_meshset, 1, &( curr_group ) );MB_CHK_SET_ERR( rval, "Failed to set mesh set ID tag." );
431
432 return rval;
433 }
434
435
440 ErrorCode ReadOBJ::create_new_vertex( std::vector< std::string > v_tokens, EntityHandle& vertex_eh )
441 {
442 ErrorCode rval;
443 vertex next_vertex;
444
445 for( int i = 1; i < 4; i++ )
446 next_vertex.coord[i - 1] = atof( v_tokens[i].c_str() );
447
448 rval = MBI->create_vertex( next_vertex.coord, vertex_eh );MB_CHK_SET_ERR( rval, "Unbale to create vertex." );
449
450 return rval;
451 }
452
453
458 ErrorCode ReadOBJ::create_new_face( std::vector< std::string > f_tokens,
459 const std::vector< EntityHandle >& vertex_list,
460 EntityHandle& face_eh )
461 {
462 face next_face;
463 ErrorCode rval;
464
465 for( int i = 1; i < 4; i++ )
466 {
467 int vertex_id = atoi( f_tokens[i].c_str() );
468
469
470
471 std::size_t slash = f_tokens[i].find( '/' );
472 if( slash != std::string::npos )
473 {
474 std::string face = f_tokens[i].substr( 0, slash );
475 vertex_id = atoi( face.c_str() );
476 }
477
478 next_face.conn[i - 1] = vertex_list[vertex_id - 1];
479 }
480
481 rval = MBI->create_element( MBTRI, next_face.conn, 3, face_eh );MB_CHK_SET_ERR( rval, "Unable to create new face." );
482
483 return rval;
484 }
485
486
487 ErrorCode ReadOBJ::split_quad( std::vector< std::string > f_tokens,
488 std::vector< EntityHandle >& vertex_list,
489 Range& face_eh )
490 {
491 ErrorCode rval;
492 std::vector< EntityHandle > quad_vert_eh;
493
494
495 for( int i = 1; i < 5; i++ )
496 {
497 int vertex_id = atoi( f_tokens[i].c_str() );
498 std::size_t slash = f_tokens[i].find( '/' );
499 if( slash != std::string::npos )
500 {
501 std::string face = f_tokens[i].substr( 0, slash );
502 vertex_id = atoi( face.c_str() );
503 }
504
505 quad_vert_eh.push_back( vertex_list[vertex_id - 1] );
506 }
507
508
509 rval = create_tri_faces( quad_vert_eh, face_eh );MB_CHK_SET_ERR( rval, "Failed to create triangles when splitting quad." );
510
511 return rval;
512 }
513
514 ErrorCode ReadOBJ::create_tri_faces( std::vector< EntityHandle > quad_vert_eh,
515
516 Range& face_eh )
517 {
518 ErrorCode rval;
519 EntityHandle connectivity[3];
520 EntityHandle new_face;
521
522 connectivity[0] = quad_vert_eh[0];
523 connectivity[1] = quad_vert_eh[1];
524 connectivity[2] = quad_vert_eh[2];
525 rval = MBI->create_element( MBTRI, connectivity, 3, new_face );
526 face_eh.insert( new_face );
527
528 connectivity[0] = quad_vert_eh[2];
529 connectivity[1] = quad_vert_eh[3];
530 connectivity[2] = quad_vert_eh[0];
531 rval = MBI->create_element( MBTRI, connectivity, 3, new_face );
532 face_eh.insert( new_face );
533
534 return rval;
535 }
536
537 }