Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /** 00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating, 00003 * storing and accessing finite element mesh data. 00004 * 00005 * Copyright 2004 Sandia Corporation. Under the terms of Contract 00006 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 00007 * retains certain rights in this software. 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 */ 00015 00016 /** 00017 * \class ReadSmf 00018 * \brief SMF reader from QSLIM 00019 * \author Michael Garland 00020 */ 00021 00022 #ifdef _WIN32 /* windows */ 00023 #define _USE_MATH_DEFINES // For M_PI 00024 #endif 00025 00026 #include <cassert> 00027 #include <cstdlib> 00028 #include <iostream> 00029 00030 #include "ReadSmf.hpp" 00031 #include "moab/Range.hpp" 00032 #include "Internals.hpp" 00033 #include "moab/Interface.hpp" 00034 #include "moab/ReadUtilIface.hpp" 00035 #include "moab/FileOptions.hpp" 00036 #include "AffineXform.hpp" 00037 00038 static inline int streq( const char* a, const char* b ) 00039 { 00040 return strcmp( a, b ) == 0; 00041 } 00042 00043 namespace moab 00044 { 00045 00046 ReadSmf::cmd_entry ReadSmf::read_cmds[] = { { "v", &ReadSmf::vertex }, 00047 { ":vn", &ReadSmf::v_normal }, 00048 { ":vc", &ReadSmf::v_color }, 00049 { ":fc", &ReadSmf::f_color }, 00050 { "t", &ReadSmf::face }, 00051 { "f", &ReadSmf::face }, 00052 00053 { "begin", &ReadSmf::begin }, 00054 { "end", &ReadSmf::end }, 00055 { "set", &ReadSmf::set }, 00056 { "inc", &ReadSmf::inc }, 00057 { "dec", &ReadSmf::dec }, 00058 00059 { "mmult", &ReadSmf::mload }, 00060 { "mload", &ReadSmf::mmult }, 00061 { "trans", &ReadSmf::trans }, 00062 { "scale", &ReadSmf::scale }, 00063 { "rot", &ReadSmf::rot }, 00064 00065 { NULL, NULL } }; 00066 00067 ErrorCode ReadSmf::parse_mat( const std::vector< std::string >& argv, AffineXform& mat ) 00068 { 00069 double values[12]; 00070 ErrorCode err = parse_doubles( 12, argv, values ); 00071 if( MB_SUCCESS != err ) return err; 00072 00073 mat = AffineXform( values, values + 9 ); 00074 return MB_SUCCESS; 00075 } 00076 00077 void ReadSmf::bad_annotation( const char* cmd ) 00078 { 00079 std::cerr << "SMF: Malformed annotation [" << cmd << "]" << std::endl; 00080 } 00081 00082 ReaderIface* ReadSmf::factory( Interface* iface ) 00083 { 00084 return new ReadSmf( iface ); 00085 } 00086 00087 ReadSmf::ReadSmf( Interface* impl ) 00088 : mdbImpl( impl ), mCurrentMeshHandle( 0 ), lineNo( 0 ), commandNo( 0 ), versionMajor( 0 ), versionMinor( 0 ) 00089 { 00090 mdbImpl->query_interface( readMeshIface ); 00091 ivar.next_vertex = 0; 00092 ivar.next_face = 0; 00093 _numNodes = _numFaces = 0; 00094 _numNodesInFile = _numElementsInFile = 0; 00095 } 00096 00097 ReadSmf::~ReadSmf() 00098 { 00099 if( readMeshIface ) 00100 { 00101 mdbImpl->release_interface( readMeshIface ); 00102 readMeshIface = 0; 00103 } 00104 } 00105 00106 ErrorCode ReadSmf::read_tag_values( const char* /* file_name */, 00107 const char* /* tag_name */, 00108 const FileOptions& /* opts */, 00109 std::vector< int >& /* tag_values_out */, 00110 const SubsetList* /* subset_list */ ) 00111 { 00112 return MB_NOT_IMPLEMENTED; 00113 } 00114 00115 ErrorCode ReadSmf::load_file( const char* filename, 00116 const EntityHandle* /* file_set */, 00117 const FileOptions& opts, 00118 const ReaderIface::SubsetList* subset_list, 00119 const Tag* file_id_tag ) 00120 { 00121 ErrorCode result; 00122 lineNo = 0; 00123 commandNo = 0; 00124 versionMajor = 0; 00125 versionMinor = 0; 00126 00127 if( subset_list ) 00128 { 00129 MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "Reading subset of files not supported for VTK" ); 00130 } 00131 00132 // Does the caller want a field to be used for partitioning the entities? 00133 // If not, we'll assume any scalar integer field named MATERIAL_SET specifies partitions. 00134 std::string partition_tag_name; 00135 result = opts.get_option( "PARTITION", partition_tag_name ); 00136 if( result == MB_SUCCESS ) mPartitionTagName = partition_tag_name; 00137 00138 std::ifstream smfFile( filename ); 00139 if( !smfFile ) return MB_FILE_DOES_NOT_EXIST; 00140 00141 ivar.next_face = 1; 00142 ivar.next_vertex = 1; 00143 state.push_back( SMF_State( ivar ) ); 00144 00145 while( smfFile.getline( line, SMF_MAXLINE, '\n' ).good() ) 00146 { 00147 ++lineNo; 00148 result = parse_line( line ); 00149 if( MB_SUCCESS != result ) return result; 00150 } 00151 00152 if( !smfFile.eof() ) 00153 { 00154 // Parsing terminated for a reason other than EOF: signal failure. 00155 return MB_FILE_WRITE_ERROR; 00156 } 00157 00158 // At this point we have _numNodesInFile vertices and _numElementsInFile triangles 00159 // the coordinates are in _coords, and connectivities in _connec 00160 // std::vector<double> _coords; // 3*numNodes; we might not know the number of nodes 00161 // std::vector<int> _connec; // 3*num of elements; we might not know them; 00162 00163 // Create vertices 00164 std::vector< double* > arrays; 00165 EntityHandle start_handle_out; 00166 start_handle_out = 0; 00167 result = readMeshIface->get_node_coords( 3, _numNodesInFile, MB_START_ID, start_handle_out, arrays ); 00168 00169 if( MB_SUCCESS != result ) return result; 00170 00171 // Fill the arrays with data from _coords 00172 // Cppcheck warning (false positive): variable arrays is assigned a value that is never used 00173 for( int i = 0; i < _numNodesInFile; i++ ) 00174 { 00175 int i3 = 3 * i; 00176 arrays[0][i] = _coords[i3]; 00177 arrays[1][i] = _coords[i3 + 1]; 00178 arrays[2][i] = _coords[i3 + 2]; 00179 } 00180 // Elements 00181 00182 EntityHandle start_handle_elem_out; 00183 start_handle_elem_out = 0; 00184 EntityHandle* conn_array_out; 00185 result = readMeshIface->get_element_connect( _numElementsInFile, 3, 00186 MBTRI, // EntityType 00187 MB_START_ID, start_handle_elem_out, conn_array_out ); 00188 if( MB_SUCCESS != result ) return result; 00189 for( int j = 0; j < _numElementsInFile * 3; j++ ) 00190 conn_array_out[j] = _connec[j]; 00191 00192 // Notify MOAB of the new elements 00193 result = readMeshIface->update_adjacencies( start_handle_elem_out, _numElementsInFile, 3, conn_array_out ); 00194 00195 if( MB_SUCCESS != result ) return result; 00196 00197 if( file_id_tag ) 00198 { 00199 Range nodes( start_handle_out, start_handle_out + _numNodesInFile - 1 ); 00200 Range elems( start_handle_elem_out, start_handle_elem_out + _numElementsInFile - 1 ); 00201 readMeshIface->assign_ids( *file_id_tag, nodes ); 00202 readMeshIface->assign_ids( *file_id_tag, elems ); 00203 } 00204 00205 return MB_SUCCESS; 00206 } 00207 00208 ErrorCode ReadSmf::annotation( char* cmd, std::vector< std::string >& argv ) 00209 { 00210 // Skip over the '#$' prefix 00211 cmd += 2; 00212 00213 if( streq( cmd, "SMF" ) ) 00214 { 00215 // If SMF version is specified, it must be the first 00216 // thing specified in the file. 00217 if( commandNo > 1 ) 00218 { 00219 MB_SET_ERR( MB_FILE_WRITE_ERROR, "SMF file version specified at line " << lineNo ); 00220 } 00221 00222 if( 2 == sscanf( argv[0].c_str(), "%d.%d", &versionMajor, &versionMinor ) ) 00223 { 00224 if( versionMajor != 1 || versionMinor != 0 ) 00225 { 00226 MB_SET_ERR( MB_FILE_WRITE_ERROR, 00227 "Unsupported SMF file version: " << versionMajor << "." << versionMinor ); 00228 } 00229 } 00230 else 00231 { 00232 MB_SET_ERR( MB_FILE_WRITE_ERROR, "Invalid SMF version annotation" ); 00233 } 00234 } 00235 else if( streq( cmd, "vertices" ) ) 00236 { 00237 if( argv.size() == 1 ) 00238 _numNodes = atoi( argv[0].c_str() ); 00239 else 00240 bad_annotation( cmd ); 00241 } 00242 else if( streq( cmd, "faces" ) ) 00243 { 00244 if( argv.size() == 1 ) 00245 _numFaces = atoi( argv[0].c_str() ); 00246 else 00247 bad_annotation( cmd ); 00248 } 00249 else if( streq( cmd, "BBox" ) ) 00250 { 00251 } 00252 else if( streq( cmd, "BSphere" ) ) 00253 { 00254 } 00255 else if( streq( cmd, "PXform" ) ) 00256 { 00257 if( argv.size() == 16 ) 00258 { 00259 // parse_mat(argv); 00260 } 00261 else 00262 bad_annotation( cmd ); 00263 } 00264 else if( streq( cmd, "MXform" ) ) 00265 { 00266 if( argv.size() == 16 ) 00267 { 00268 // parse_mat(argv); 00269 } 00270 else 00271 bad_annotation( cmd ); 00272 } 00273 00274 return MB_SUCCESS; 00275 } 00276 00277 ErrorCode ReadSmf::parse_line( char* ln ) 00278 { 00279 char *cmd, *s; 00280 std::vector< std::string > argv; 00281 ErrorCode err; 00282 00283 while( *ln == ' ' || *ln == '\t' ) 00284 ln++; // Skip initial white space 00285 00286 // Ignore empty lines 00287 if( ln[0] == '\n' || ln[0] == '\0' ) return MB_SUCCESS; 00288 00289 // Ignore comments 00290 if( ln[0] == '#' && ln[1] != '$' ) return MB_SUCCESS; 00291 00292 // First, split the line into tokens 00293 cmd = strtok( ln, " \t\n" ); 00294 00295 while( ( s = strtok( NULL, " \t\n" ) ) ) 00296 { 00297 std::string stg( s ); 00298 argv.push_back( stg ); 00299 } 00300 00301 // Figure out what command it is and execute it 00302 if( cmd[0] == '#' && cmd[1] == '$' ) 00303 { 00304 err = annotation( cmd, argv ); 00305 if( MB_SUCCESS != err ) return err; 00306 } 00307 else 00308 { 00309 cmd_entry* entry = &read_cmds[0]; 00310 bool handled = false; 00311 00312 while( entry->name && !handled ) 00313 { 00314 if( streq( entry->name, cmd ) ) 00315 { 00316 err = ( this->*( entry->cmd ) )( argv ); 00317 if( MB_SUCCESS != err ) return err; 00318 handled = true; 00319 ++commandNo; 00320 } 00321 else 00322 entry++; 00323 } 00324 00325 if( !handled ) 00326 { 00327 // If the first command was invalid, this probably 00328 // wasn't an Smf file. Fail silently in this case. 00329 // If versionMajor is set, then we saw an initial #$SMF, 00330 // in which case it must be a SMF file. 00331 if( !versionMajor && !commandNo ) return MB_FILE_WRITE_ERROR; 00332 00333 // Invalid command: 00334 MB_SET_ERR( MB_UNSUPPORTED_OPERATION, "Illegal SMF command at line " << lineNo << ": \"" << cmd << "\"" ); 00335 } 00336 } 00337 00338 return MB_SUCCESS; 00339 } 00340 00341 ErrorCode ReadSmf::check_length( int count, const std::vector< std::string >& argv ) 00342 { 00343 if( ( argv.size() < (unsigned)count ) || ( argv.size() > (unsigned)count && argv[count][0] != '#' ) ) 00344 { 00345 MB_SET_ERR( MB_FILE_WRITE_ERROR, "Expect " << count << " arguments at line " << lineNo ); 00346 } 00347 00348 return MB_SUCCESS; 00349 } 00350 00351 ErrorCode ReadSmf::parse_doubles( int count, const std::vector< std::string >& argv, double results[] ) 00352 { 00353 ErrorCode rval = check_length( count, argv ); 00354 if( MB_SUCCESS != rval ) return rval; 00355 00356 char* endptr; 00357 for( int i = 0; i < count; i++ ) 00358 { 00359 results[i] = strtod( argv[i].c_str(), &endptr ); 00360 if( *endptr ) 00361 { 00362 MB_SET_ERR( MB_FILE_WRITE_ERROR, "Invalid vertex coordinates at line " << lineNo ); 00363 } 00364 } 00365 00366 return MB_SUCCESS; 00367 } 00368 00369 ErrorCode ReadSmf::vertex( std::vector< std::string >& argv ) 00370 { 00371 double v[3]; 00372 ErrorCode err = parse_doubles( 3, argv, v ); 00373 if( MB_SUCCESS != err ) return err; 00374 00375 state.back().vertex( v ); 00376 ivar.next_vertex++; 00377 _numNodesInFile++; 00378 for( int j = 0; j < 3; j++ ) 00379 _coords.push_back( v[j] ); 00380 // model->in_Vertex(v); 00381 return MB_SUCCESS; 00382 } 00383 00384 ErrorCode ReadSmf::v_normal( std::vector< std::string >& /*argv*/ ) 00385 { 00386 return MB_SUCCESS; 00387 } 00388 00389 ErrorCode ReadSmf::v_color( std::vector< std::string >& /*argv*/ ) 00390 { 00391 return MB_SUCCESS; 00392 } 00393 00394 ErrorCode ReadSmf::f_color( std::vector< std::string >& /*argv*/ ) 00395 { 00396 return MB_SUCCESS; 00397 } 00398 00399 ErrorCode ReadSmf::face( std::vector< std::string >& argv ) 00400 { 00401 ErrorCode err = check_length( 3, argv ); 00402 if( MB_SUCCESS != err ) return err; 00403 00404 int vert[3] = {}; 00405 char* endptr; 00406 for( unsigned int i = 0; i < argv.size(); i++ ) 00407 { 00408 vert[i] = strtol( argv[i].c_str(), &endptr, 0 ); 00409 if( *endptr ) 00410 { 00411 MB_SET_ERR( MB_FILE_WRITE_ERROR, "Invalid face spec at line " << lineNo ); 00412 } 00413 } 00414 00415 state.back().face( vert, ivar ); 00416 ivar.next_face++; 00417 for( int j = 0; j < 3; j++ ) 00418 _connec.push_back( vert[j] ); 00419 _numElementsInFile++; 00420 00421 return MB_SUCCESS; 00422 } 00423 00424 ErrorCode ReadSmf::begin( std::vector< std::string >& /*argv*/ ) 00425 { 00426 state.push_back( SMF_State( ivar, &state.back() ) ); 00427 00428 return MB_SUCCESS; 00429 } 00430 00431 ErrorCode ReadSmf::end( std::vector< std::string >& /*argv*/ ) 00432 { 00433 // There must always be at least one state on the stack. 00434 // Don't let mismatched begin/end statements cause us 00435 // to read from an empty vector. 00436 if( state.size() == 1 ) 00437 { 00438 MB_SET_ERR( MB_FILE_WRITE_ERROR, "End w/out Begin at line " << lineNo ); 00439 } 00440 00441 state.pop_back(); 00442 00443 return MB_SUCCESS; 00444 } 00445 00446 ErrorCode ReadSmf::set( std::vector< std::string >& argv ) 00447 { 00448 if( argv.size() < 2 || argv[0] != "vertex_coorection" ) return MB_SUCCESS; 00449 00450 char* endptr; 00451 int val = strtol( argv[1].c_str(), &endptr, 0 ); 00452 if( *endptr ) 00453 { 00454 MB_SET_ERR( MB_FILE_WRITE_ERROR, "Invalid value at line " << lineNo ); 00455 } 00456 00457 state.back().set_vertex_correction( val ); 00458 00459 return MB_SUCCESS; 00460 } 00461 00462 ErrorCode ReadSmf::inc( std::vector< std::string >& /*argv*/ ) 00463 { 00464 // std::cerr << "SMF: INC not yet implemented." << std::endl; 00465 return MB_SUCCESS; 00466 } 00467 00468 ErrorCode ReadSmf::dec( std::vector< std::string >& ) 00469 { 00470 // std::cerr << "SMF: DEC not yet implemented." << std::endl; 00471 return MB_SUCCESS; 00472 } 00473 00474 ErrorCode ReadSmf::trans( std::vector< std::string >& argv ) 00475 { 00476 double v3[3]; 00477 ErrorCode err = parse_doubles( 3, argv, v3 ); 00478 if( MB_SUCCESS != err ) return err; 00479 00480 AffineXform M = AffineXform::translation( v3 ); 00481 // Mat4 M = Mat4::trans(atof(argv(0)), atof(argv(1)), atof(argv(2))); 00482 state.back().mmult( M ); 00483 00484 return MB_SUCCESS; 00485 } 00486 00487 ErrorCode ReadSmf::scale( std::vector< std::string >& argv ) 00488 { 00489 double v3[3]; 00490 ErrorCode err = parse_doubles( 3, argv, v3 ); 00491 if( MB_SUCCESS != err ) return err; 00492 00493 AffineXform M = AffineXform::scale( v3 ); 00494 // Mat4 M = Mat4::scale(atof(argv(0)), atof(argv(1)), atof(argv(2))); 00495 state.back().mmult( M ); 00496 00497 return MB_SUCCESS; 00498 } 00499 00500 ErrorCode ReadSmf::rot( std::vector< std::string >& argv ) 00501 { 00502 ErrorCode err = check_length( 2, argv ); 00503 if( MB_SUCCESS != err ) return err; 00504 00505 double axis[3] = { 0., 0., 0. }; 00506 std::string axisname = argv.front(); 00507 argv.erase( argv.begin() ); 00508 if( axisname.size() != 1 ) 00509 { 00510 MB_SET_ERR( MB_FILE_WRITE_ERROR, "Malformed rotation command at line " << lineNo ); 00511 } 00512 switch( axisname[0] ) 00513 { 00514 case 'x': 00515 axis[0] = 1.; 00516 break; 00517 case 'y': 00518 axis[1] = 1.; 00519 break; 00520 case 'z': 00521 axis[2] = 1.; 00522 break; 00523 default: 00524 MB_SET_ERR( MB_FILE_WRITE_ERROR, "Malformed rotation command at line " << lineNo ); 00525 } 00526 00527 double angle; 00528 err = parse_doubles( 1, argv, &angle ); 00529 if( MB_SUCCESS != err ) return err; 00530 angle *= M_PI / 180.0; 00531 00532 AffineXform M = AffineXform::rotation( angle, axis ); 00533 state.back().mmult( M ); 00534 00535 return MB_SUCCESS; 00536 } 00537 00538 ErrorCode ReadSmf::mmult( std::vector< std::string >& argv ) 00539 { 00540 AffineXform mat; 00541 ErrorCode rval = parse_mat( argv, mat ); 00542 if( MB_SUCCESS != rval ) return rval; 00543 00544 state.back().mmult( mat ); 00545 00546 return MB_SUCCESS; 00547 } 00548 00549 ErrorCode ReadSmf::mload( std::vector< std::string >& argv ) 00550 { 00551 AffineXform mat; 00552 ErrorCode rval = parse_mat( argv, mat ); 00553 if( MB_SUCCESS != rval ) return rval; 00554 00555 state.back().mload( mat ); 00556 00557 return MB_SUCCESS; 00558 } 00559 00560 } // namespace moab