Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
ReadSmf.cpp
Go to the documentation of this file.
1 /**
2  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3  * storing and accessing finite element mesh data.
4  *
5  * Copyright 2004 Sandia Corporation. Under the terms of Contract
6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7  * retains certain rights in this software.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  */
15 
16 /**
17  * \class ReadSmf
18  * \brief SMF reader from QSLIM
19  * \author Michael Garland
20  */
21 
22 #ifdef _WIN32 /* windows */
23 #define _USE_MATH_DEFINES // For M_PI
24 #endif
25 
26 #include <cassert>
27 #include <cstdlib>
28 #include <iostream>
29 
30 #include "ReadSmf.hpp"
31 #include "moab/Range.hpp"
32 #include "Internals.hpp"
33 #include "moab/Interface.hpp"
34 #include "moab/ReadUtilIface.hpp"
35 #include "moab/FileOptions.hpp"
36 #include "AffineXform.hpp"
37 
38 static inline int streq( const char* a, const char* b )
39 {
40  return strcmp( a, b ) == 0;
41 }
42 
43 namespace moab
44 {
45 
46 ReadSmf::cmd_entry ReadSmf::read_cmds[] = { { "v", &ReadSmf::vertex },
47  { ":vn", &ReadSmf::v_normal },
48  { ":vc", &ReadSmf::v_color },
49  { ":fc", &ReadSmf::f_color },
50  { "t", &ReadSmf::face },
51  { "f", &ReadSmf::face },
52 
53  { "begin", &ReadSmf::begin },
54  { "end", &ReadSmf::end },
55  { "set", &ReadSmf::set },
56  { "inc", &ReadSmf::inc },
57  { "dec", &ReadSmf::dec },
58 
59  { "mmult", &ReadSmf::mload },
60  { "mload", &ReadSmf::mmult },
61  { "trans", &ReadSmf::trans },
62  { "scale", &ReadSmf::scale },
63  { "rot", &ReadSmf::rot },
64 
65  { NULL, NULL } };
66 
67 ErrorCode ReadSmf::parse_mat( const std::vector< std::string >& argv, AffineXform& mat )
68 {
69  double values[12];
70  ErrorCode err = parse_doubles( 12, argv, values );
71  if( MB_SUCCESS != err ) return err;
72 
73  mat = AffineXform( values, values + 9 );
74  return MB_SUCCESS;
75 }
76 
77 void ReadSmf::bad_annotation( const char* cmd )
78 {
79  std::cerr << "SMF: Malformed annotation [" << cmd << "]" << std::endl;
80 }
81 
83 {
84  return new ReadSmf( iface );
85 }
86 
88  : mdbImpl( impl ), mCurrentMeshHandle( 0 ), lineNo( 0 ), commandNo( 0 ), versionMajor( 0 ), versionMinor( 0 )
89 {
91  ivar.next_vertex = 0;
92  ivar.next_face = 0;
93  _numNodes = _numFaces = 0;
95 }
96 
98 {
99  if( readMeshIface )
100  {
102  readMeshIface = 0;
103  }
104 }
105 
106 ErrorCode ReadSmf::read_tag_values( const char* /* file_name */,
107  const char* /* tag_name */,
108  const FileOptions& /* opts */,
109  std::vector< int >& /* tag_values_out */,
110  const SubsetList* /* subset_list */ )
111 {
112  return MB_NOT_IMPLEMENTED;
113 }
114 
115 ErrorCode ReadSmf::load_file( const char* filename,
116  const EntityHandle* /* file_set */,
117  const FileOptions& opts,
118  const ReaderIface::SubsetList* subset_list,
119  const Tag* file_id_tag )
120 {
121  ErrorCode result;
122  lineNo = 0;
123  commandNo = 0;
124  versionMajor = 0;
125  versionMinor = 0;
126 
127  if( subset_list )
128  {
129  MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "Reading subset of files not supported for VTK" );
130  }
131 
132  // Does the caller want a field to be used for partitioning the entities?
133  // If not, we'll assume any scalar integer field named MATERIAL_SET specifies partitions.
134  std::string partition_tag_name;
135  result = opts.get_option( "PARTITION", partition_tag_name );
136  if( result == MB_SUCCESS ) mPartitionTagName = partition_tag_name;
137 
138  std::ifstream smfFile( filename );
139  if( !smfFile ) return MB_FILE_DOES_NOT_EXIST;
140 
141  ivar.next_face = 1;
142  ivar.next_vertex = 1;
143  state.push_back( SMF_State( ivar ) );
144 
145  while( smfFile.getline( line, SMF_MAXLINE, '\n' ).good() )
146  {
147  ++lineNo;
148  result = parse_line( line );
149  if( MB_SUCCESS != result ) return result;
150  }
151 
152  if( !smfFile.eof() )
153  {
154  // Parsing terminated for a reason other than EOF: signal failure.
155  return MB_FILE_WRITE_ERROR;
156  }
157 
158  // At this point we have _numNodesInFile vertices and _numElementsInFile triangles
159  // the coordinates are in _coords, and connectivities in _connec
160  // std::vector<double> _coords; // 3*numNodes; we might not know the number of nodes
161  // std::vector<int> _connec; // 3*num of elements; we might not know them;
162 
163  // Create vertices
164  std::vector< double* > arrays;
165  EntityHandle start_handle_out;
166  start_handle_out = 0;
167  result = readMeshIface->get_node_coords( 3, _numNodesInFile, MB_START_ID, start_handle_out, arrays );
168 
169  if( MB_SUCCESS != result ) return result;
170 
171  // Fill the arrays with data from _coords
172  // Cppcheck warning (false positive): variable arrays is assigned a value that is never used
173  for( int i = 0; i < _numNodesInFile; i++ )
174  {
175  int i3 = 3 * i;
176  arrays[0][i] = _coords[i3];
177  arrays[1][i] = _coords[i3 + 1];
178  arrays[2][i] = _coords[i3 + 2];
179  }
180  // Elements
181 
182  EntityHandle start_handle_elem_out;
183  start_handle_elem_out = 0;
184  EntityHandle* conn_array_out;
186  MBTRI, // EntityType
187  MB_START_ID, start_handle_elem_out, conn_array_out );
188  if( MB_SUCCESS != result ) return result;
189  for( int j = 0; j < _numElementsInFile * 3; j++ )
190  conn_array_out[j] = _connec[j];
191 
192  // Notify MOAB of the new elements
193  result = readMeshIface->update_adjacencies( start_handle_elem_out, _numElementsInFile, 3, conn_array_out );
194 
195  if( MB_SUCCESS != result ) return result;
196 
197  if( file_id_tag )
198  {
199  Range nodes( start_handle_out, start_handle_out + _numNodesInFile - 1 );
200  Range elems( start_handle_elem_out, start_handle_elem_out + _numElementsInFile - 1 );
201  readMeshIface->assign_ids( *file_id_tag, nodes );
202  readMeshIface->assign_ids( *file_id_tag, elems );
203  }
204 
205  return MB_SUCCESS;
206 }
207 
208 ErrorCode ReadSmf::annotation( char* cmd, std::vector< std::string >& argv )
209 {
210  // Skip over the '#$' prefix
211  cmd += 2;
212 
213  if( streq( cmd, "SMF" ) )
214  {
215  // If SMF version is specified, it must be the first
216  // thing specified in the file.
217  if( commandNo > 1 )
218  {
219  MB_SET_ERR( MB_FILE_WRITE_ERROR, "SMF file version specified at line " << lineNo );
220  }
221 
222  if( 2 == sscanf( argv[0].c_str(), "%d.%d", &versionMajor, &versionMinor ) )
223  {
224  if( versionMajor != 1 || versionMinor != 0 )
225  {
227  "Unsupported SMF file version: " << versionMajor << "." << versionMinor );
228  }
229  }
230  else
231  {
232  MB_SET_ERR( MB_FILE_WRITE_ERROR, "Invalid SMF version annotation" );
233  }
234  }
235  else if( streq( cmd, "vertices" ) )
236  {
237  if( argv.size() == 1 )
238  _numNodes = atoi( argv[0].c_str() );
239  else
240  bad_annotation( cmd );
241  }
242  else if( streq( cmd, "faces" ) )
243  {
244  if( argv.size() == 1 )
245  _numFaces = atoi( argv[0].c_str() );
246  else
247  bad_annotation( cmd );
248  }
249  else if( streq( cmd, "BBox" ) )
250  {
251  }
252  else if( streq( cmd, "BSphere" ) )
253  {
254  }
255  else if( streq( cmd, "PXform" ) )
256  {
257  if( argv.size() == 16 )
258  {
259  // parse_mat(argv);
260  }
261  else
262  bad_annotation( cmd );
263  }
264  else if( streq( cmd, "MXform" ) )
265  {
266  if( argv.size() == 16 )
267  {
268  // parse_mat(argv);
269  }
270  else
271  bad_annotation( cmd );
272  }
273 
274  return MB_SUCCESS;
275 }
276 
278 {
279  char *cmd, *s;
280  std::vector< std::string > argv;
281  ErrorCode err;
282 
283  while( *ln == ' ' || *ln == '\t' )
284  ln++; // Skip initial white space
285 
286  // Ignore empty lines
287  if( ln[0] == '\n' || ln[0] == '\0' ) return MB_SUCCESS;
288 
289  // Ignore comments
290  if( ln[0] == '#' && ln[1] != '$' ) return MB_SUCCESS;
291 
292  // First, split the line into tokens
293  cmd = strtok( ln, " \t\n" );
294 
295  while( ( s = strtok( NULL, " \t\n" ) ) )
296  {
297  std::string stg( s );
298  argv.push_back( stg );
299  }
300 
301  // Figure out what command it is and execute it
302  if( cmd[0] == '#' && cmd[1] == '$' )
303  {
304  err = annotation( cmd, argv );
305  if( MB_SUCCESS != err ) return err;
306  }
307  else
308  {
309  cmd_entry* entry = &read_cmds[0];
310  bool handled = false;
311 
312  while( entry->name && !handled )
313  {
314  if( streq( entry->name, cmd ) )
315  {
316  err = ( this->*( entry->cmd ) )( argv );
317  if( MB_SUCCESS != err ) return err;
318  handled = true;
319  ++commandNo;
320  }
321  else
322  entry++;
323  }
324 
325  if( !handled )
326  {
327  // If the first command was invalid, this probably
328  // wasn't an Smf file. Fail silently in this case.
329  // If versionMajor is set, then we saw an initial #$SMF,
330  // in which case it must be a SMF file.
331  if( !versionMajor && !commandNo ) return MB_FILE_WRITE_ERROR;
332 
333  // Invalid command:
334  MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "Illegal SMF command at line " << lineNo << ": \"" << cmd << "\"" );
335  }
336  }
337 
338  return MB_SUCCESS;
339 }
340 
341 ErrorCode ReadSmf::check_length( int count, const std::vector< std::string >& argv )
342 {
343  if( ( argv.size() < (unsigned)count ) || ( argv.size() > (unsigned)count && argv[count][0] != '#' ) )
344  {
345  MB_SET_ERR( MB_FILE_WRITE_ERROR, "Expect " << count << " arguments at line " << lineNo );
346  }
347 
348  return MB_SUCCESS;
349 }
350 
351 ErrorCode ReadSmf::parse_doubles( int count, const std::vector< std::string >& argv, double results[] )
352 {
353  ErrorCode rval = check_length( count, argv );
354  if( MB_SUCCESS != rval ) return rval;
355 
356  char* endptr;
357  for( int i = 0; i < count; i++ )
358  {
359  results[i] = strtod( argv[i].c_str(), &endptr );
360  if( *endptr )
361  {
362  MB_SET_ERR( MB_FILE_WRITE_ERROR, "Invalid vertex coordinates at line " << lineNo );
363  }
364  }
365 
366  return MB_SUCCESS;
367 }
368 
369 ErrorCode ReadSmf::vertex( std::vector< std::string >& argv )
370 {
371  double v[3];
372  ErrorCode err = parse_doubles( 3, argv, v );
373  if( MB_SUCCESS != err ) return err;
374 
375  state.back().vertex( v );
376  ivar.next_vertex++;
377  _numNodesInFile++;
378  for( int j = 0; j < 3; j++ )
379  _coords.push_back( v[j] );
380  // model->in_Vertex(v);
381  return MB_SUCCESS;
382 }
383 
384 ErrorCode ReadSmf::v_normal( std::vector< std::string >& /*argv*/ )
385 {
386  return MB_SUCCESS;
387 }
388 
389 ErrorCode ReadSmf::v_color( std::vector< std::string >& /*argv*/ )
390 {
391  return MB_SUCCESS;
392 }
393 
394 ErrorCode ReadSmf::f_color( std::vector< std::string >& /*argv*/ )
395 {
396  return MB_SUCCESS;
397 }
398 
399 ErrorCode ReadSmf::face( std::vector< std::string >& argv )
400 {
401  ErrorCode err = check_length( 3, argv );
402  if( MB_SUCCESS != err ) return err;
403 
404  int vert[3] = {};
405  char* endptr;
406  for( unsigned int i = 0; i < argv.size(); i++ )
407  {
408  vert[i] = strtol( argv[i].c_str(), &endptr, 0 );
409  if( *endptr )
410  {
411  MB_SET_ERR( MB_FILE_WRITE_ERROR, "Invalid face spec at line " << lineNo );
412  }
413  }
414 
415  state.back().face( vert, ivar );
416  ivar.next_face++;
417  for( int j = 0; j < 3; j++ )
418  _connec.push_back( vert[j] );
420 
421  return MB_SUCCESS;
422 }
423 
424 ErrorCode ReadSmf::begin( std::vector< std::string >& /*argv*/ )
425 {
426  state.push_back( SMF_State( ivar, &state.back() ) );
427 
428  return MB_SUCCESS;
429 }
430 
431 ErrorCode ReadSmf::end( std::vector< std::string >& /*argv*/ )
432 {
433  // There must always be at least one state on the stack.
434  // Don't let mismatched begin/end statements cause us
435  // to read from an empty vector.
436  if( state.size() == 1 )
437  {
438  MB_SET_ERR( MB_FILE_WRITE_ERROR, "End w/out Begin at line " << lineNo );
439  }
440 
441  state.pop_back();
442 
443  return MB_SUCCESS;
444 }
445 
446 ErrorCode ReadSmf::set( std::vector< std::string >& argv )
447 {
448  if( argv.size() < 2 || argv[0] != "vertex_coorection" ) return MB_SUCCESS;
449 
450  char* endptr;
451  int val = strtol( argv[1].c_str(), &endptr, 0 );
452  if( *endptr )
453  {
454  MB_SET_ERR( MB_FILE_WRITE_ERROR, "Invalid value at line " << lineNo );
455  }
456 
457  state.back().set_vertex_correction( val );
458 
459  return MB_SUCCESS;
460 }
461 
462 ErrorCode ReadSmf::inc( std::vector< std::string >& /*argv*/ )
463 {
464  // std::cerr << "SMF: INC not yet implemented." << std::endl;
465  return MB_SUCCESS;
466 }
467 
468 ErrorCode ReadSmf::dec( std::vector< std::string >& )
469 {
470  // std::cerr << "SMF: DEC not yet implemented." << std::endl;
471  return MB_SUCCESS;
472 }
473 
474 ErrorCode ReadSmf::trans( std::vector< std::string >& argv )
475 {
476  double v3[3];
477  ErrorCode err = parse_doubles( 3, argv, v3 );
478  if( MB_SUCCESS != err ) return err;
479 
481  // Mat4 M = Mat4::trans(atof(argv(0)), atof(argv(1)), atof(argv(2)));
482  state.back().mmult( M );
483 
484  return MB_SUCCESS;
485 }
486 
487 ErrorCode ReadSmf::scale( std::vector< std::string >& argv )
488 {
489  double v3[3];
490  ErrorCode err = parse_doubles( 3, argv, v3 );
491  if( MB_SUCCESS != err ) return err;
492 
494  // Mat4 M = Mat4::scale(atof(argv(0)), atof(argv(1)), atof(argv(2)));
495  state.back().mmult( M );
496 
497  return MB_SUCCESS;
498 }
499 
500 ErrorCode ReadSmf::rot( std::vector< std::string >& argv )
501 {
502  ErrorCode err = check_length( 2, argv );
503  if( MB_SUCCESS != err ) return err;
504 
505  double axis[3] = { 0., 0., 0. };
506  std::string axisname = argv.front();
507  argv.erase( argv.begin() );
508  if( axisname.size() != 1 )
509  {
510  MB_SET_ERR( MB_FILE_WRITE_ERROR, "Malformed rotation command at line " << lineNo );
511  }
512  switch( axisname[0] )
513  {
514  case 'x':
515  axis[0] = 1.;
516  break;
517  case 'y':
518  axis[1] = 1.;
519  break;
520  case 'z':
521  axis[2] = 1.;
522  break;
523  default:
524  MB_SET_ERR( MB_FILE_WRITE_ERROR, "Malformed rotation command at line " << lineNo );
525  }
526 
527  double angle;
528  err = parse_doubles( 1, argv, &angle );
529  if( MB_SUCCESS != err ) return err;
530  angle *= M_PI / 180.0;
531 
533  state.back().mmult( M );
534 
535  return MB_SUCCESS;
536 }
537 
538 ErrorCode ReadSmf::mmult( std::vector< std::string >& argv )
539 {
540  AffineXform mat;
541  ErrorCode rval = parse_mat( argv, mat );
542  if( MB_SUCCESS != rval ) return rval;
543 
544  state.back().mmult( mat );
545 
546  return MB_SUCCESS;
547 }
548 
549 ErrorCode ReadSmf::mload( std::vector< std::string >& argv )
550 {
551  AffineXform mat;
552  ErrorCode rval = parse_mat( argv, mat );
553  if( MB_SUCCESS != rval ) return rval;
554 
555  state.back().mload( mat );
556 
557  return MB_SUCCESS;
558 }
559 
560 } // namespace moab