moab
|
00001 00022 #include <assert.h> 00023 #include <stdlib.h> 00024 #include <string.h> 00025 00026 #include "ReadVtk.hpp" 00027 #include "moab/Range.hpp" 00028 #include "Internals.hpp" 00029 #include "moab/Interface.hpp" 00030 #include "moab/ReadUtilIface.hpp" 00031 #include "moab/FileOptions.hpp" 00032 #include "FileTokenizer.hpp" 00033 #include "VtkUtil.hpp" 00034 00035 #define MB_VTK_MATERIAL_SETS 00036 #ifdef MB_VTK_MATERIAL_SETS 00037 # include "MBTagConventions.hpp" 00038 # include <map> 00039 00040 namespace moab { 00041 00042 class Hash 00043 { 00044 public: 00045 unsigned long value; 00046 00047 Hash() 00048 { 00049 this->value = 5381L; 00050 } 00051 Hash( const unsigned char* bytes, size_t len ) 00052 { // djb2, a hash by dan bernstein presented on comp.lang.c for hashing strings. 00053 this->value = 5381L; 00054 for ( ; len ; -- len, ++ bytes ) 00055 this->value = this->value * 33 + ( *bytes ); 00056 } 00057 Hash( bool duh ) 00058 { 00059 this->value = duh; // hashing a single bit with a long is stupid but easy. 00060 } 00061 Hash( const Hash& src ) 00062 { 00063 this->value = src.value; 00064 } 00065 Hash& operator = ( const Hash& src ) 00066 { 00067 this->value = src.value; 00068 return *this; 00069 } 00070 bool operator < ( const Hash& other ) const 00071 { 00072 return this->value < other.value; 00073 } 00074 }; 00075 00076 // Pass this class opaque data + a handle and it adds the handle to a set 00077 // whose opaque data has the same hash. If no set exists for the hash, 00078 // it creates one. Each set is tagged with the opaque data. 00079 // When entities with different opaque data have the same hash, they 00080 // will be placed into the same set. 00081 // There will be no collisions when the opaque data is shorter than an 00082 // unsigned long, and this is really the only case we need to support. 00083 // The rest is bonus. Hash does quite well with strings, even those 00084 // with identical prefixes. 00085 class Modulator : public std::map<Hash,EntityHandle> 00086 { 00087 public: 00088 Modulator( Interface* iface, std::string tag_name, DataType mb_type, size_t sz, size_t per_elem ) 00089 { 00090 this->mesh = iface; 00091 std::vector<unsigned char> default_val; 00092 default_val.resize( sz * per_elem ); 00093 this->mesh->tag_get_handle( tag_name.c_str(), per_elem, mb_type, this->tag, 00094 MB_TAG_SPARSE|MB_TAG_BYTES|MB_TAG_CREAT, 00095 &default_val[0] ); 00096 } 00097 void add_entity( EntityHandle ent, const unsigned char* bytes, size_t len ) 00098 { 00099 Hash h( bytes, len ); 00100 EntityHandle mset = this->congruence_class( h, bytes ); 00101 this->mesh->add_entities( mset, &ent, 1 ); 00102 } 00103 void add_entities( Range& range, const unsigned char* bytes, size_t bytes_per_ent ) 00104 { 00105 for( Range::iterator it = range.begin(); it != range.end(); ++ it, bytes += bytes_per_ent ) 00106 { 00107 Hash h( bytes, bytes_per_ent ); 00108 EntityHandle mset = this->congruence_class( h, bytes ); 00109 this->mesh->add_entities( mset, &*it, 1 ); 00110 } 00111 } 00112 EntityHandle congruence_class( const Hash& h, const void* tag_data ) 00113 { 00114 std::map<Hash,EntityHandle>::iterator it = this->find( h ); 00115 if ( it == this->end() ) 00116 { 00117 EntityHandle mset; 00118 Range preexist; 00119 this->mesh->get_entities_by_type_and_tag( 0, MBENTITYSET, &this->tag, &tag_data, 1, preexist ); 00120 if ( preexist.size() ) 00121 { 00122 mset = *preexist.begin(); 00123 } 00124 else 00125 { 00126 this->mesh->create_meshset( MESHSET_SET, mset ); 00127 this->mesh->tag_set_data( this->tag, &mset, 1, tag_data ); 00128 } 00129 (*this)[h] = mset; 00130 return mset; 00131 } 00132 return it->second; 00133 } 00134 00135 Interface* mesh; 00136 Tag tag; 00137 }; 00138 #endif // MB_VTK_MATERIAL_SETS 00139 00140 ReaderIface* ReadVtk::factory( Interface* iface ) 00141 { return new ReadVtk( iface ); } 00142 00143 ReadVtk::ReadVtk(Interface* impl) 00144 : mdbImpl(impl), mPartitionTagName(MATERIAL_SET_TAG_NAME) 00145 { 00146 mdbImpl->query_interface(readMeshIface); 00147 } 00148 00149 ReadVtk::~ReadVtk() 00150 { 00151 if (readMeshIface) { 00152 mdbImpl->release_interface(readMeshIface); 00153 readMeshIface = 0; 00154 } 00155 } 00156 00157 const char* const vtk_type_names[] = { "bit", 00158 "char", 00159 "unsigned_char", 00160 "short", 00161 "unsigned_short", 00162 "int", 00163 "unsigned_int", 00164 "long", 00165 "unsigned_long", 00166 "float", 00167 "double", 00168 "vtkIdType", 00169 0 }; 00170 00171 00172 ErrorCode ReadVtk::read_tag_values( const char* /* file_name */, 00173 const char* /* tag_name */, 00174 const FileOptions& /* opts */, 00175 std::vector<int>& /* tag_values_out */, 00176 const SubsetList* /* subset_list */ ) 00177 { 00178 return MB_NOT_IMPLEMENTED; 00179 } 00180 00181 00182 ErrorCode ReadVtk::load_file( const char *filename, 00183 const EntityHandle* , 00184 const FileOptions& opts, 00185 const ReaderIface::SubsetList* subset_list, 00186 const Tag* file_id_tag) 00187 { 00188 ErrorCode result; 00189 00190 int major, minor; 00191 char vendor_string[257]; 00192 std::vector<Range> element_list; 00193 Range vertices; 00194 00195 if (subset_list) { 00196 readMeshIface->report_error( "Reading subset of files not supported for VTK." ); 00197 return MB_UNSUPPORTED_OPERATION; 00198 } 00199 00200 // Does the caller want a field to be used for partitioning the entities? 00201 // If not, we'll assume any scalar integer field named MATERIAL_SET specifies partitions. 00202 std::string partition_tag_name; 00203 result = opts.get_option( "PARTITION", partition_tag_name ); 00204 if ( result == MB_SUCCESS ) 00205 mPartitionTagName = partition_tag_name; 00206 00207 FILE* file = fopen( filename, "r" ); 00208 if (!file) 00209 { 00210 return MB_FILE_DOES_NOT_EXIST; 00211 } 00212 00213 // Read file header 00214 00215 if (!fgets( vendor_string, sizeof(vendor_string), file )) 00216 { 00217 fclose( file ); 00218 return MB_FAILURE; 00219 } 00220 00221 if (!strchr( vendor_string, '\n' ) || 00222 2 != sscanf( vendor_string, "# vtk DataFile Version %d.%d", &major, &minor )) 00223 { 00224 fclose( file ); 00225 return MB_FAILURE; 00226 } 00227 00228 if (!fgets( vendor_string, sizeof(vendor_string), file )) 00229 { 00230 fclose( file ); 00231 return MB_FAILURE; 00232 } 00233 00234 // VTK spec says this should not exceed 256 chars. 00235 if (!strchr( vendor_string, '\n' )) 00236 { 00237 readMeshIface->report_error( "Vendor string (line 2) exceeds 256 characters." ); 00238 fclose( file ); 00239 return MB_FAILURE; 00240 } 00241 00242 00243 // Check file type 00244 00245 FileTokenizer tokens( file, readMeshIface ); 00246 const char* const file_type_names[] = { "ASCII", "BINARY", 0 }; 00247 int filetype = tokens.match_token( file_type_names ); 00248 switch (filetype) { 00249 case 2: // BINARY 00250 readMeshIface->report_error( "Cannot read BINARY VTK files" ); 00251 default: // ERROR 00252 return MB_FAILURE; 00253 case 1: // ASCII 00254 break; 00255 } 00256 00257 // Read the mesh 00258 if (!tokens.match_token( "DATASET" )) 00259 return MB_FAILURE; 00260 result = vtk_read_dataset( tokens, vertices, element_list ); 00261 if (MB_SUCCESS != result) 00262 return result; 00263 00264 if (file_id_tag) { 00265 result = store_file_ids( *file_id_tag, vertices, element_list ); 00266 if (MB_SUCCESS != result) 00267 return result; 00268 } 00269 00270 // Count the number of elements read 00271 long elem_count = 0; 00272 for (std::vector<Range>::iterator it = element_list.begin(); it != element_list.end(); ++it ) 00273 elem_count += it->size(); 00274 00275 // Read attribute data until end of file. 00276 const char* const block_type_names[] = { "POINT_DATA", "CELL_DATA", 0 }; 00277 std::vector<Range> vertex_list(1); 00278 vertex_list[0] = vertices; 00279 int blocktype = 0; 00280 while (!tokens.eof()) 00281 { 00282 // get POINT_DATA or CELL_DATA 00283 int new_block_type = tokens.match_token( block_type_names, false ); 00284 if (tokens.eof()) 00285 break; 00286 00287 if (!new_block_type) 00288 { 00289 // If next token was neither POINT_DATA nor CELL_DATA, 00290 // then there's another attribute under the current one. 00291 if (blocktype) 00292 tokens.unget_token(); 00293 else 00294 break; 00295 } 00296 else 00297 { 00298 blocktype = new_block_type; 00299 long count; 00300 if (!tokens.get_long_ints( 1, &count )) 00301 return MB_FAILURE; 00302 00303 if (blocktype == 1 && (unsigned long)count != vertices.size()) 00304 { 00305 readMeshIface->report_error( 00306 "Count inconsistent with number of vertices at line %d.", 00307 tokens.line_number()); 00308 return MB_FAILURE; 00309 } 00310 else if (blocktype == 2 && count != elem_count) 00311 { 00312 readMeshIface->report_error( 00313 "Count inconsistent with number of elements at line %d.", 00314 tokens.line_number()); 00315 return MB_FAILURE; 00316 } 00317 } 00318 00319 00320 if (blocktype == 1) 00321 result = vtk_read_attrib_data( tokens, vertex_list ); 00322 else 00323 result = vtk_read_attrib_data( tokens, element_list ); 00324 00325 if (MB_SUCCESS != result) 00326 return result; 00327 } 00328 00329 return MB_SUCCESS; 00330 } 00331 00332 ErrorCode ReadVtk::allocate_vertices( long num_verts, 00333 EntityHandle& start_handle_out, 00334 double*& x_coord_array_out, 00335 double*& y_coord_array_out, 00336 double*& z_coord_array_out ) 00337 { 00338 ErrorCode result; 00339 00340 // Create vertices 00341 std::vector<double*> arrays; 00342 start_handle_out = 0; 00343 result = readMeshIface->get_node_coords( 3, num_verts, MB_START_ID, 00344 start_handle_out, arrays ); 00345 if (MB_SUCCESS != result) 00346 return result; 00347 00348 x_coord_array_out = arrays[0]; 00349 y_coord_array_out = arrays[1]; 00350 z_coord_array_out = arrays[2]; 00351 00352 return MB_SUCCESS; 00353 } 00354 00355 ErrorCode ReadVtk::read_vertices( FileTokenizer& tokens, 00356 long num_verts, 00357 EntityHandle& start_handle_out ) 00358 { 00359 ErrorCode result; 00360 double *x, *y, *z; 00361 00362 result = allocate_vertices( num_verts, start_handle_out, x, y, z ); 00363 if (MB_SUCCESS != result) 00364 return result; 00365 00366 // Read vertex coordinates 00367 for (long vtx = 0; vtx < num_verts; ++vtx) 00368 { 00369 if (!tokens.get_doubles( 1, x++ ) || 00370 !tokens.get_doubles( 1, y++ ) || 00371 !tokens.get_doubles( 1, z++ )) 00372 return MB_FAILURE; 00373 } 00374 00375 return MB_SUCCESS; 00376 } 00377 00378 ErrorCode ReadVtk::allocate_elements( long num_elements, 00379 int vert_per_element, 00380 EntityType type, 00381 EntityHandle& start_handle_out, 00382 EntityHandle*& conn_array_out, 00383 std::vector<Range>& append_to_this ) 00384 { 00385 ErrorCode result; 00386 00387 start_handle_out = 0; 00388 result = readMeshIface->get_element_connect( num_elements, 00389 vert_per_element, 00390 type, 00391 MB_START_ID, 00392 start_handle_out, 00393 conn_array_out ); 00394 if (MB_SUCCESS != result) 00395 return result; 00396 00397 Range range(start_handle_out, start_handle_out+num_elements-1); 00398 append_to_this.push_back( range ); 00399 return MB_SUCCESS; 00400 } 00401 00402 ErrorCode ReadVtk::vtk_read_dataset( FileTokenizer& tokens, 00403 Range& vertex_list, 00404 std::vector<Range>& element_list ) 00405 { 00406 const char* const data_type_names[] = { "STRUCTURED_POINTS", 00407 "STRUCTURED_GRID", 00408 "UNSTRUCTURED_GRID", 00409 "POLYDATA", 00410 "RECTILINEAR_GRID", 00411 "FIELD", 00412 0 }; 00413 int datatype = tokens.match_token( data_type_names ); 00414 switch( datatype ) 00415 { 00416 case 1: return vtk_read_structured_points( tokens, vertex_list, element_list ); 00417 case 2: return vtk_read_structured_grid ( tokens, vertex_list, element_list ); 00418 case 3: return vtk_read_unstructured_grid( tokens, vertex_list, element_list ); 00419 case 4: return vtk_read_polydata ( tokens, vertex_list, element_list ); 00420 case 5: return vtk_read_rectilinear_grid ( tokens, vertex_list, element_list ); 00421 case 6: return vtk_read_field ( tokens ); 00422 default: return MB_FAILURE; 00423 } 00424 00425 } 00426 00427 00428 ErrorCode ReadVtk::vtk_read_structured_points( FileTokenizer& tokens, 00429 Range& vertex_list, 00430 std::vector<Range>& elem_list ) 00431 { 00432 long i, j, k; 00433 long dims[3]; 00434 double origin[3], space[3]; 00435 ErrorCode result; 00436 00437 if (!tokens.match_token( "DIMENSIONS" ) || 00438 !tokens.get_long_ints( 3, dims ) || 00439 !tokens.get_newline( )) 00440 return MB_FAILURE; 00441 00442 if (dims[0] < 1 || dims[1] < 1 || dims[2] < 1) 00443 { 00444 readMeshIface->report_error( "Invalid dimension at line %d", 00445 tokens.line_number()); 00446 return MB_FAILURE; 00447 } 00448 00449 if (!tokens.match_token( "ORIGIN" ) || 00450 !tokens.get_doubles( 3, origin ) || 00451 !tokens.get_newline( )) 00452 return MB_FAILURE; 00453 00454 const char* const spacing_names[] = { "SPACING", "ASPECT_RATIO", 0 }; 00455 if (!tokens.match_token( spacing_names ) || 00456 !tokens.get_doubles( 3, space ) || 00457 !tokens.get_newline()) 00458 return MB_FAILURE; 00459 00460 // Create vertices 00461 double *x, *y, *z; 00462 EntityHandle start_handle = 0; 00463 long num_verts = dims[0]*dims[1]*dims[2]; 00464 result = allocate_vertices( num_verts, start_handle, x, y, z ); 00465 if (MB_SUCCESS != result) 00466 return result; 00467 vertex_list.insert( start_handle, start_handle + num_verts - 1 ); 00468 00469 for (k = 0; k < dims[2]; ++k) 00470 for (j = 0; j < dims[1]; ++j) 00471 for (i = 0; i < dims[0]; ++i) 00472 { 00473 *x = origin[0] + i*space[0]; ++x; 00474 *y = origin[1] + j*space[1]; ++y; 00475 *z = origin[2] + k*space[2]; ++z; 00476 } 00477 00478 return vtk_create_structured_elems( dims, start_handle, elem_list ); 00479 } 00480 00481 ErrorCode ReadVtk::vtk_read_structured_grid( FileTokenizer& tokens, 00482 Range& vertex_list, 00483 std::vector<Range>& elem_list ) 00484 { 00485 long num_verts, dims[3]; 00486 ErrorCode result; 00487 00488 if (!tokens.match_token( "DIMENSIONS" ) || 00489 !tokens.get_long_ints( 3, dims ) || 00490 !tokens.get_newline( ) ) 00491 return MB_FAILURE; 00492 00493 if (dims[0] < 1 || dims[1] < 1 || dims[2] < 1) 00494 { 00495 readMeshIface->report_error( "Invalid dimension at line %d", 00496 tokens.line_number()); 00497 return MB_FAILURE; 00498 } 00499 00500 if (!tokens.match_token( "POINTS" ) || 00501 !tokens.get_long_ints( 1, &num_verts ) || 00502 !tokens.match_token( vtk_type_names ) || 00503 !tokens.get_newline()) 00504 return MB_FAILURE; 00505 00506 if (num_verts != (dims[0] * dims[1] * dims[2])) 00507 { 00508 readMeshIface->report_error( 00509 "Point count not consistent with dimensions at line %d", 00510 tokens.line_number() ); 00511 return MB_FAILURE; 00512 } 00513 00514 // Create and read vertices 00515 EntityHandle start_handle = 0; 00516 result = read_vertices( tokens, num_verts, start_handle ); 00517 if (MB_SUCCESS != result) 00518 return result; 00519 vertex_list.insert( start_handle, start_handle + num_verts - 1 ); 00520 00521 return vtk_create_structured_elems( dims, start_handle, elem_list ); 00522 } 00523 00524 ErrorCode ReadVtk::vtk_read_rectilinear_grid( FileTokenizer& tokens, 00525 Range& vertex_list, 00526 std::vector<Range>& elem_list ) 00527 { 00528 int i, j, k; 00529 long dims[3]; 00530 const char* labels[] = { "X_COORDINATES", "Y_COORDINATES", "Z_COORDINATES" }; 00531 std::vector<double> coords[3]; 00532 ErrorCode result; 00533 00534 if (!tokens.match_token( "DIMENSIONS" )|| 00535 !tokens.get_long_ints( 3, dims ) || 00536 !tokens.get_newline( )) 00537 return MB_FAILURE; 00538 00539 if (dims[0] < 1 || dims[1] < 1 || dims[2] < 1) 00540 { 00541 readMeshIface->report_error( "Invalid dimension at line %d", 00542 tokens.line_number()); 00543 return MB_FAILURE; 00544 } 00545 00546 for (i = 0; i < 3; i++) 00547 { 00548 long count; 00549 if (!tokens.match_token( labels[i] ) || 00550 !tokens.get_long_ints( 1, &count ) || 00551 !tokens.match_token( vtk_type_names )) 00552 return MB_FAILURE; 00553 00554 if (count != dims[i]) 00555 { 00556 readMeshIface->report_error( 00557 "Coordinate count inconsistent with dimensions at line %d", 00558 tokens.line_number() ); 00559 return MB_FAILURE; 00560 } 00561 00562 coords[i].resize(count); 00563 if (!tokens.get_doubles( count, &coords[i][0] )) 00564 return MB_FAILURE; 00565 } 00566 00567 // Create vertices 00568 double *x, *y, *z; 00569 EntityHandle start_handle = 0; 00570 long num_verts = dims[0]*dims[1]*dims[2]; 00571 result = allocate_vertices( num_verts, start_handle, x, y, z ); 00572 if (MB_SUCCESS != result) 00573 return result; 00574 vertex_list.insert( start_handle, start_handle + num_verts - 1 ); 00575 00576 // Calculate vertex coordinates 00577 for (k = 0; k < dims[2]; ++k) 00578 for (j = 0; j < dims[1]; ++j) 00579 for (i = 0; i < dims[0]; ++i) 00580 { 00581 *x = coords[0][i]; ++x; 00582 *y = coords[1][j]; ++y; 00583 *z = coords[2][k]; ++z; 00584 } 00585 00586 00587 return vtk_create_structured_elems( dims, start_handle, elem_list ); 00588 } 00589 00590 ErrorCode ReadVtk::vtk_read_polydata( FileTokenizer& tokens, 00591 Range& vertex_list, 00592 std::vector<Range>& elem_list ) 00593 { 00594 ErrorCode result; 00595 long num_verts; 00596 std::vector<int> connectivity; 00597 const char* const poly_data_names[] = { "VERTICES", 00598 "LINES", 00599 "POLYGONS", 00600 "TRIANGLE_STRIPS", 00601 0 }; 00602 00603 if (!tokens.match_token( "POINTS" ) || 00604 !tokens.get_long_ints( 1, &num_verts ) || 00605 !tokens.match_token( vtk_type_names ) || 00606 !tokens.get_newline( )) 00607 return MB_FAILURE; 00608 00609 if (num_verts < 1) 00610 { 00611 readMeshIface->report_error( "Invalid point count at line %d", 00612 tokens.line_number()); 00613 return MB_FAILURE; 00614 } 00615 00616 // Create vertices and read coordinates 00617 EntityHandle start_handle = 0; 00618 result = read_vertices( tokens, num_verts, start_handle ); 00619 if (MB_SUCCESS != result) 00620 return result; 00621 vertex_list.insert( start_handle, start_handle + num_verts - 1 ); 00622 00623 int poly_type = tokens.match_token( poly_data_names ); 00624 switch (poly_type) 00625 { 00626 case 0: 00627 result = MB_FAILURE; 00628 break; 00629 case 1: 00630 readMeshIface->report_error( 00631 "Vertex element type at line %d", 00632 tokens.line_number() ); 00633 result = MB_FAILURE; 00634 break; 00635 case 2: 00636 readMeshIface->report_error( 00637 "Unsupported type: polylines at line %d", 00638 tokens.line_number() ); 00639 result = MB_FAILURE; 00640 break; 00641 case 3: 00642 result = vtk_read_polygons( tokens, start_handle, elem_list ); 00643 break; 00644 case 4: 00645 readMeshIface->report_error( 00646 "Unsupported type: triangle strips at line %d", 00647 tokens.line_number() ); 00648 result = MB_FAILURE; 00649 break; 00650 } 00651 00652 return result; 00653 } 00654 00655 ErrorCode ReadVtk::vtk_read_polygons( FileTokenizer& tokens, 00656 EntityHandle first_vtx, 00657 std::vector<Range>& elem_list ) 00658 { 00659 ErrorCode result; 00660 long size[2]; 00661 00662 if (!tokens.get_long_ints( 2, size ) || 00663 !tokens.get_newline( )) 00664 return MB_FAILURE; 00665 00666 const Range empty; 00667 std::vector<EntityHandle> conn_hdl; 00668 std::vector<long> conn_idx; 00669 EntityHandle first = 0, prev = 0, handle; 00670 for (int i = 0; i < size[0]; ++i) { 00671 long count; 00672 if (!tokens.get_long_ints( 1, &count )) 00673 return MB_FAILURE; 00674 conn_idx.resize(count); 00675 conn_hdl.resize(count); 00676 if (!tokens.get_long_ints( count, &conn_idx[0])) 00677 return MB_FAILURE; 00678 00679 for (long j = 0; j < count; ++j) 00680 conn_hdl[j] = first_vtx + conn_idx[j]; 00681 00682 result = mdbImpl->create_element( MBPOLYGON, &conn_hdl[0], count, handle ); 00683 if (MB_SUCCESS != result) 00684 return result; 00685 00686 if (prev +1 != handle) { 00687 if (first) { // true except for first iteration (first == 0) 00688 if (first < elem_list.back().front()) // only need new range if order would get mixed up 00689 elem_list.push_back( empty ); 00690 elem_list.back().insert( first, prev ); 00691 } 00692 first = handle; 00693 } 00694 prev = handle; 00695 } 00696 if (first) { // true unless no elements (size[0] == 0) 00697 if (first < elem_list.back().front()) // only need new range if order would get mixed up 00698 elem_list.push_back( empty ); 00699 elem_list.back().insert( first, prev ); 00700 } 00701 00702 return MB_SUCCESS; 00703 } 00704 00705 00706 00707 ErrorCode ReadVtk::vtk_read_unstructured_grid( FileTokenizer& tokens, 00708 Range& vertex_list, 00709 std::vector<Range>& elem_list ) 00710 { 00711 ErrorCode result; 00712 long i, num_verts, num_elems[2]; 00713 EntityHandle tmp_conn_list[27]; 00714 00715 // Poorly formatted VTK legacy format document seems to 00716 // lead many to think that a FIELD block can occur within 00717 // an UNSTRUCTURED_GRID dataset rather than as its own data 00718 // set. So allow for field data between other blocks of 00719 // data. 00720 00721 const char* pts_str[] = { "FIELD", "POINTS", 0 }; 00722 while (1 == (i = tokens.match_token(pts_str))) { 00723 result = vtk_read_field(tokens); 00724 if (MB_SUCCESS != result) 00725 return result; 00726 } 00727 if (i != 2) 00728 return MB_FAILURE; 00729 00730 if (!tokens.get_long_ints( 1, &num_verts ) || 00731 !tokens.match_token( vtk_type_names) || 00732 !tokens.get_newline( )) 00733 return MB_FAILURE; 00734 00735 if (num_verts < 1) 00736 { 00737 readMeshIface->report_error( "Invalid point count at line %d", tokens.line_number()); 00738 return MB_FAILURE; 00739 } 00740 00741 // Create vertices and read coordinates 00742 EntityHandle first_vertex = 0; 00743 result = read_vertices( tokens, num_verts, first_vertex ); 00744 if (MB_SUCCESS != result) 00745 return result; 00746 vertex_list.insert( first_vertex, first_vertex + num_verts - 1 ); 00747 00748 const char* cell_str[] = { "FIELD", "CELLS", 0 }; 00749 while (1 == (i = tokens.match_token(cell_str))) { 00750 result = vtk_read_field(tokens); 00751 if (MB_SUCCESS != result) 00752 return result; 00753 } 00754 if (i != 2) 00755 return MB_FAILURE; 00756 00757 if (!tokens.get_long_ints( 2, num_elems ) || 00758 !tokens.get_newline( )) 00759 return MB_FAILURE; 00760 00761 // Read element connectivity for all elements 00762 std::vector<long> connectivity( num_elems[1] ); 00763 if (!tokens.get_long_ints( num_elems[1], &connectivity[0] )) 00764 return MB_FAILURE; 00765 00766 if (!tokens.match_token( "CELL_TYPES" ) || 00767 !tokens.get_long_ints( 1, &num_elems[1]) || 00768 !tokens.get_newline( )) 00769 return MB_FAILURE; 00770 00771 // Read element types 00772 std::vector<long> types( num_elems[0] ); 00773 if (!tokens.get_long_ints( num_elems[0], &types[0] )) 00774 return MB_FAILURE; 00775 00776 // Create elements in blocks of the same type 00777 // It is important to preserve the order in 00778 // which the elements were read for later reading 00779 // attribute data. 00780 long id = 0; 00781 std::vector<long>::iterator conn_iter = connectivity.begin(); 00782 while (id < num_elems[0]) 00783 { 00784 unsigned vtk_type = types[id]; 00785 if (vtk_type >= VtkUtil::numVtkElemType) 00786 return MB_FAILURE; 00787 00788 EntityType type = VtkUtil::vtkElemTypes[vtk_type].mb_type; 00789 if (type == MBMAXTYPE) { 00790 readMeshIface->report_error( "Unsupported VTK element type: %s (%d)\n", 00791 VtkUtil::vtkElemTypes[vtk_type].name, vtk_type ); 00792 return MB_FAILURE; 00793 } 00794 00795 int num_vtx = *conn_iter; 00796 if (type != MBPOLYGON && num_vtx != (int)VtkUtil::vtkElemTypes[vtk_type].num_nodes) { 00797 readMeshIface->report_error( 00798 "Cell %ld is of type '%s' but has %u vertices.\n", 00799 id, VtkUtil::vtkElemTypes[vtk_type].name, num_vtx ); 00800 return MB_FAILURE; 00801 } 00802 00803 // Find any subsequent elements of the same type 00804 std::vector<long>::iterator conn_iter2 = conn_iter + num_vtx + 1; 00805 long end_id = id + 1; 00806 while ( end_id < num_elems[0] && 00807 (unsigned)types[end_id] == vtk_type && 00808 *conn_iter2 == num_vtx) { 00809 ++end_id; 00810 conn_iter2 += num_vtx + 1; 00811 } 00812 00813 // Allocate element block 00814 long num_elem = end_id - id; 00815 EntityHandle start_handle = 0; 00816 EntityHandle* conn_array; 00817 00818 result = allocate_elements( num_elem, num_vtx, type, start_handle, 00819 conn_array, elem_list ); 00820 if (MB_SUCCESS != result) 00821 return result; 00822 00823 EntityHandle *conn_sav = conn_array; 00824 00825 // Store element connectivity 00826 for ( ; id < end_id; ++id) 00827 { 00828 if (conn_iter == connectivity.end()) 00829 { 00830 readMeshIface->report_error( 00831 "Connectivity data truncated at cell %ld\n", id ); 00832 return MB_FAILURE; 00833 } 00834 00835 // make sure connectivity length is correct. 00836 if (*conn_iter != num_vtx) 00837 { 00838 readMeshIface->report_error( 00839 "Cell %ld is of type '%s' but has %u vertices.\n", 00840 id, VtkUtil::vtkElemTypes[vtk_type].name, num_vtx ); 00841 return MB_FAILURE; 00842 } 00843 ++conn_iter; 00844 00845 for (i = 0; i < num_vtx; ++i, ++conn_iter) 00846 { 00847 if (conn_iter == connectivity.end()) 00848 { 00849 readMeshIface->report_error( 00850 "Connectivity data truncated at cell %ld\n", id ); 00851 return MB_FAILURE; 00852 } 00853 00854 conn_array[i] = *conn_iter + first_vertex; 00855 } 00856 00857 const unsigned* order = VtkUtil::vtkElemTypes[vtk_type].node_order; 00858 if ( order ) 00859 { 00860 assert( num_vtx * sizeof(EntityHandle) <= sizeof(tmp_conn_list) ); 00861 memcpy( tmp_conn_list, conn_array, num_vtx * sizeof(EntityHandle) ); 00862 for (int j = 0; j < num_vtx; ++j) 00863 conn_array[order[j]] = tmp_conn_list[j]; 00864 } 00865 00866 conn_array += num_vtx; 00867 } 00868 00869 // notify MOAB of the new elements 00870 result = readMeshIface->update_adjacencies(start_handle, num_elem, 00871 num_vtx, conn_sav); 00872 if (MB_SUCCESS != result) return result; 00873 } 00874 00875 return MB_SUCCESS; 00876 } 00877 00878 ErrorCode ReadVtk::vtk_create_structured_elems( const long* dims, 00879 EntityHandle first_vtx, 00880 std::vector<Range>& elem_list ) 00881 { 00882 ErrorCode result; 00883 //int non_zero[3] = {0,0,0}; // True if dim > 0 for x, y, z respectively 00884 long elem_dim = 0; // Element dimension (2->quad, 3->hex) 00885 long num_elems = 1; // Total number of elements 00886 long vert_per_elem; // Element connectivity length 00887 long edims[3] = { 1, 1, 1 };// Number of elements in each grid direction 00888 00889 // Populate above data 00890 for (int d = 0; d < 3; d++) 00891 if (dims[d] > 1) 00892 { 00893 //non_zero[elem_dim] = d; 00894 ++elem_dim; 00895 edims[d] = dims[d] - 1; 00896 num_elems *= edims[d]; 00897 } 00898 vert_per_elem = 1 << elem_dim; 00899 00900 // Get element type from element dimension 00901 EntityType type; 00902 switch( elem_dim ) 00903 { 00904 case 1: type = MBEDGE; break; 00905 case 2: type = MBQUAD; break; 00906 case 3: type = MBHEX; break; 00907 default: 00908 readMeshIface->report_error( "Invalid dimension for structured elements: %ld\n", 00909 elem_dim ); 00910 return MB_FAILURE; 00911 } 00912 00913 // Allocate storage for elements 00914 EntityHandle start_handle = 0; 00915 EntityHandle* conn_array; 00916 result = allocate_elements( num_elems, vert_per_elem, type, start_handle, 00917 conn_array, elem_list ); 00918 if (MB_SUCCESS != result) 00919 return MB_FAILURE; 00920 00921 EntityHandle *conn_sav = conn_array; 00922 00923 // Offsets of element vertices in grid relative to corner closest to origin 00924 long k = dims[0]*dims[1]; 00925 const long corners[8] = { 0, 1, 1+dims[0], dims[0], k, k+1, k+1+dims[0], k+dims[0] }; 00926 00927 // Populate element list 00928 for (long z = 0; z < edims[2]; ++z) 00929 for (long y = 0; y < edims[1]; ++y) 00930 for (long x = 0; x < edims[0]; ++x) 00931 { 00932 const long index = x + y*dims[0] + z*(dims[0]*dims[1]); 00933 for (long j = 0; j < vert_per_elem; ++j, ++conn_array) 00934 *conn_array = index + corners[j] + first_vtx; 00935 } 00936 00937 // notify MOAB of the new elements 00938 result = readMeshIface->update_adjacencies(start_handle, num_elems, 00939 vert_per_elem, conn_sav); 00940 if (MB_SUCCESS != result) return result; 00941 00942 return MB_SUCCESS; 00943 } 00944 00945 ErrorCode ReadVtk::vtk_read_field( FileTokenizer& tokens ) 00946 { 00947 // This is not supported yet. 00948 // Parse the data but throw it away because 00949 // Mesquite has no internal representation for it. 00950 00951 // Could save this in tags, but the only useful thing that 00952 // could be done with the data is to write it back out 00953 // with the modified mesh. As there's no way to save the 00954 // type of a tag in Mesquite, it cannot be written back 00955 // out correctly either. 00956 // FIXME: Don't know what to do with this data. 00957 // For now, read it and throw it out. 00958 00959 long num_arrays; 00960 if (!tokens.get_string() || // name 00961 !tokens.get_long_ints( 1, &num_arrays )) 00962 return MB_FAILURE; 00963 00964 for (long i = 0; i < num_arrays; ++i) 00965 { 00966 /*const char* name =*/ tokens.get_string( ); 00967 00968 long dims[2]; 00969 if (!tokens.get_long_ints( 2, dims ) || 00970 !tokens.match_token( vtk_type_names )) 00971 return MB_FAILURE; 00972 00973 long num_vals = dims[0] * dims[1]; 00974 00975 for (long j = 0; j < num_vals; j++) 00976 { 00977 double junk; 00978 if (!tokens.get_doubles( 1, &junk )) 00979 return MB_FAILURE; 00980 } 00981 } 00982 00983 return MB_SUCCESS; 00984 } 00985 00986 ErrorCode ReadVtk::vtk_read_attrib_data( FileTokenizer& tokens, 00987 std::vector<Range>& entities ) 00988 { 00989 const char* const type_names[] = { "SCALARS", 00990 "COLOR_SCALARS", 00991 "VECTORS", 00992 "NORMALS", 00993 "TEXTURE_COORDINATES", 00994 "TENSORS", 00995 "FIELD", 00996 0 }; 00997 00998 int type = tokens.match_token( type_names ); 00999 const char* tmp_name = tokens.get_string( ); 01000 if (!type || !tmp_name) 01001 return MB_FAILURE; 01002 01003 std::string name_alloc( tmp_name ); 01004 const char* name = name_alloc.c_str(); 01005 switch( type ) 01006 { 01007 case 1: return vtk_read_scalar_attrib ( tokens, entities, name ); 01008 case 2: return vtk_read_color_attrib ( tokens, entities, name ); 01009 case 3: return vtk_read_vector_attrib ( tokens, entities, name ); 01010 case 4: return vtk_read_vector_attrib ( tokens, entities, name ); 01011 case 5: return vtk_read_texture_attrib( tokens, entities, name ); 01012 case 6: return vtk_read_tensor_attrib ( tokens, entities, name ); 01013 case 7: return vtk_read_field_attrib ( tokens, entities, name ); 01014 } 01015 01016 return MB_FAILURE; 01017 } 01018 01019 ErrorCode ReadVtk::vtk_read_tag_data( FileTokenizer& tokens, 01020 int type, 01021 size_t per_elem, 01022 std::vector<Range>& entities, 01023 const char* name ) 01024 { 01025 ErrorCode result; 01026 DataType mb_type; 01027 size_t size; 01028 if (type == 1) 01029 { 01030 mb_type = MB_TYPE_BIT; 01031 size = sizeof(bool); 01032 } 01033 else if (type >= 2 && type <= 9) 01034 { 01035 mb_type = MB_TYPE_INTEGER; 01036 size = sizeof(int); 01037 } 01038 else if (type == 10 || type == 11) 01039 { 01040 mb_type = MB_TYPE_DOUBLE; 01041 size = sizeof(double); 01042 } 01043 else if ( type == 12 ) 01044 { 01045 mb_type = MB_TYPE_INTEGER; 01046 size = 4; // could be 4 or 8, but we don't know. Hope it's 4 because MOAB doesn't support 64-bit ints. 01047 } 01048 else 01049 { 01050 return MB_FAILURE; 01051 } 01052 01053 #ifdef MB_VTK_MATERIAL_SETS 01054 Modulator materialMap( this->mdbImpl, this->mPartitionTagName, mb_type, size, per_elem ); 01055 bool isMaterial = 01056 size * per_elem <= 4 && // must have int-sized values (ParallelComm requires it) 01057 ! this->mPartitionTagName.empty() && // must have a non-empty field name... 01058 ! strcmp( name, this->mPartitionTagName.c_str() ); // ... that matches our spec. 01059 #endif // MB_VTK_MATERIAL_SETS 01060 01061 // get/create tag 01062 Tag handle; 01063 result = mdbImpl->tag_get_handle( name, per_elem, mb_type, handle, MB_TAG_DENSE|MB_TAG_CREAT ); 01064 if (MB_SUCCESS != result) { 01065 readMeshIface->report_error( 01066 "Tag name conflict for attribute \"%s\" at line %d\n", 01067 name, tokens.line_number() ); 01068 return result; 01069 } 01070 01071 // Count number of entities 01072 long count = 0; 01073 std::vector<Range>::iterator iter; 01074 for (iter = entities.begin(); iter != entities.end(); ++iter) 01075 count += iter->size(); 01076 01077 if (type == 1) 01078 { 01079 for (iter = entities.begin(); iter != entities.end(); ++iter) 01080 { 01081 bool *data = new bool[iter->size() * per_elem]; 01082 if (!tokens.get_booleans( per_elem*iter->size(), data )) 01083 { 01084 delete [] data; 01085 return MB_FAILURE; 01086 } 01087 01088 bool* data_iter = data; 01089 Range::iterator ent_iter = iter->begin(); 01090 for ( ; ent_iter != iter->end(); ++ent_iter) 01091 { 01092 unsigned char bits = 0; 01093 for (unsigned j = 0; j < per_elem; ++j, ++data_iter) 01094 bits |= (unsigned char)(*data_iter << j); 01095 #ifdef MB_VTK_MATERIAL_SETS 01096 if ( isMaterial ) 01097 materialMap.add_entity( *ent_iter, &bits, 1 ); 01098 #endif // MB_VTK_MATERIAL_SETS 01099 result = mdbImpl->tag_set_data( handle, &*ent_iter, 1, &bits ); 01100 if (MB_SUCCESS != result) 01101 { 01102 delete [] data; 01103 return result; 01104 } 01105 } 01106 delete [] data; 01107 } 01108 } 01109 else if ((type >= 2 && type <= 9) || type == 12) 01110 { 01111 std::vector<int> data; 01112 for (iter = entities.begin(); iter != entities.end(); ++iter) 01113 { 01114 data.resize( iter->size() * per_elem ); 01115 if (!tokens.get_integers( iter->size() * per_elem, &data[0] )) 01116 return MB_FAILURE; 01117 #ifdef MB_VTK_MATERIAL_SETS 01118 if ( isMaterial ) 01119 materialMap.add_entities( *iter, (unsigned char*) &data[0], per_elem * size ); 01120 #endif // MB_VTK_MATERIAL_SETS 01121 result = mdbImpl->tag_set_data( handle, *iter, &data[0] ); 01122 if (MB_SUCCESS != result) 01123 return result; 01124 } 01125 } 01126 else if (type == 10 || type == 11) 01127 { 01128 std::vector<double> data; 01129 for (iter = entities.begin(); iter != entities.end(); ++iter) 01130 { 01131 data.resize( iter->size() * per_elem ); 01132 if (!tokens.get_doubles( iter->size() * per_elem, &data[0] )) 01133 return MB_FAILURE; 01134 #ifdef MB_VTK_MATERIAL_SETS 01135 if ( isMaterial ) 01136 materialMap.add_entities( *iter, (unsigned char*) &data[0], per_elem * size ); 01137 #endif // MB_VTK_MATERIAL_SETS 01138 result = mdbImpl->tag_set_data( handle, *iter, &data[0] ); 01139 if (MB_SUCCESS != result) 01140 return result; 01141 } 01142 } 01143 else 01144 { 01145 return MB_FAILURE; 01146 } 01147 01148 return MB_SUCCESS; 01149 } 01150 01151 01152 ErrorCode ReadVtk::vtk_read_scalar_attrib( FileTokenizer& tokens, 01153 std::vector<Range>& entities, 01154 const char* name) 01155 { 01156 int type = tokens.match_token( vtk_type_names ); 01157 if (!type) 01158 return MB_FAILURE; 01159 01160 long size; 01161 const char* tok = tokens.get_string( ); 01162 if (!tok) 01163 return MB_FAILURE; 01164 01165 const char* end = 0; 01166 size = strtol( tok, (char**)&end, 0 ); 01167 if (*end) 01168 { 01169 size = 1; 01170 tokens.unget_token(); 01171 } 01172 01173 // VTK spec says cannot be greater than 4--do we care? 01174 if (size < 1) //|| size > 4) 01175 { 01176 readMeshIface->report_error( 01177 "Scalar count out of range [1,4]" 01178 " at line %d", tokens.line_number()); 01179 return MB_FAILURE; 01180 } 01181 01182 if (!tokens.match_token("LOOKUP_TABLE") || 01183 !tokens.match_token("default")) 01184 return MB_FAILURE; 01185 01186 return vtk_read_tag_data( tokens, type, size, entities, name ); 01187 } 01188 01189 01190 ErrorCode ReadVtk::vtk_read_color_attrib( FileTokenizer& tokens, 01191 std::vector<Range>& entities, 01192 const char* name) 01193 { 01194 long size; 01195 if (!tokens.get_long_ints( 1, &size ) || size < 1) 01196 return MB_FAILURE; 01197 01198 return vtk_read_tag_data( tokens, 10, size, entities, name ); 01199 } 01200 01201 ErrorCode ReadVtk::vtk_read_vector_attrib( FileTokenizer& tokens, 01202 std::vector<Range>& entities, 01203 const char* name) 01204 { 01205 int type = tokens.match_token( vtk_type_names ); 01206 if (!type) 01207 return MB_FAILURE; 01208 01209 return vtk_read_tag_data( tokens, type, 3, entities, name ); 01210 } 01211 01212 ErrorCode ReadVtk::vtk_read_texture_attrib( FileTokenizer& tokens, 01213 std::vector<Range>& entities, 01214 const char* name) 01215 { 01216 int type, dim; 01217 if (!tokens.get_integers( 1, &dim ) || 01218 !(type = tokens.match_token( vtk_type_names ))) 01219 return MB_FAILURE; 01220 01221 if (dim < 1 || dim > 3) 01222 { 01223 readMeshIface->report_error( "Invalid dimension (%d) at line %d.", 01224 dim, tokens.line_number() ); 01225 return MB_FAILURE; 01226 } 01227 01228 return vtk_read_tag_data( tokens, type, dim, entities, name ); 01229 } 01230 01231 ErrorCode ReadVtk::vtk_read_tensor_attrib( FileTokenizer& tokens, 01232 std::vector<Range>& entities, 01233 const char* name ) 01234 { 01235 int type = tokens.match_token( vtk_type_names ); 01236 if (!type) 01237 return MB_FAILURE; 01238 01239 return vtk_read_tag_data( tokens, type, 9, entities, name ); 01240 } 01241 01242 ErrorCode ReadVtk::vtk_read_field_attrib( FileTokenizer& tokens, 01243 std::vector<Range>& entities, 01244 const char* ) 01245 { 01246 long num_fields; 01247 if (!tokens.get_long_ints(1, &num_fields)) 01248 return MB_FAILURE; 01249 01250 long i; 01251 for ( i = 0; i < num_fields; ++ i ) 01252 { 01253 const char* tok = tokens.get_string( ); 01254 if ( ! tok ) 01255 return MB_FAILURE; 01256 01257 std::string name_alloc( tok ); 01258 01259 long num_comp; 01260 if (!tokens.get_long_ints( 1, &num_comp)) 01261 return MB_FAILURE; 01262 01263 long num_tuples; 01264 if (!tokens.get_long_ints( 1, &num_tuples)) 01265 return MB_FAILURE; 01266 01267 int type = tokens.match_token( vtk_type_names ); 01268 if (!type) 01269 return MB_FAILURE; 01270 01271 ErrorCode result; 01272 if ( ( result = vtk_read_tag_data( tokens, type, num_comp, entities, name_alloc.c_str() ) ) != MB_SUCCESS ) 01273 { 01274 readMeshIface->report_error( 01275 "Error reading data for field \"%s\" (%ld components, %ld tuples, type %d) at line %d", 01276 name_alloc.c_str(), num_comp, num_tuples, (int)type, tokens.line_number()); 01277 return result; 01278 } 01279 } 01280 01281 return MB_SUCCESS; 01282 } 01283 01284 ErrorCode ReadVtk::store_file_ids( Tag tag, const Range& verts, 01285 const std::vector<Range>& elems ) 01286 { 01287 ErrorCode rval; 01288 01289 rval = readMeshIface->assign_ids( tag, verts ); 01290 if (MB_SUCCESS != rval) 01291 return rval; 01292 01293 int id = 0; 01294 for (size_t i = 0; i < elems.size(); ++i) { 01295 rval = readMeshIface->assign_ids( tag, elems[i], id ); 01296 id += elems[i].size(); 01297 } 01298 01299 return MB_SUCCESS; 01300 } 01301 01302 } // namespace moab 01303 01304 01305