![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 #include
00002 #include
00003 #include
00004
00005 #include "moab/Core.hpp"
00006 #include "moab/Interface.hpp"
00007 #include "moab/OrientedBoxTreeTool.hpp"
00008 #include "moab/CartVect.hpp"
00009 #include "moab/OrientedBox.hpp"
00010 #include "moab/GeomTopoTool.hpp"
00011
00012 #include "cgm2moab.hpp"
00013
00014 using namespace moab;
00015
00016 class TriCounter : public OrientedBoxTreeTool::Op
00017 {
00018
00019 public:
00020 int count;
00021 Interface* mbi;
00022 OrientedBoxTreeTool* tool;
00023 const CartVect& pt;
00024
00025 TriCounter( Interface* mbi_p, OrientedBoxTreeTool* tool_p, const CartVect& p )
00026 : OrientedBoxTreeTool::Op(), count( 0 ), mbi( mbi_p ), tool( tool_p ), pt( p )
00027 {
00028 }
00029
00030 virtual ErrorCode visit( EntityHandle node, int, bool& descend )
00031 {
00032 OrientedBox box;
00033 ErrorCode rval = tool->box( node, box );
00034
00035 descend = box.contained( pt, 1e-6 );
00036
00037 return rval;
00038 }
00039
00040 virtual ErrorCode leaf( EntityHandle node )
00041 {
00042
00043 int numtris;
00044 ErrorCode rval = tool->get_moab_instance()->get_number_entities_by_type( node, MBTRI, numtris );
00045 count += numtris;
00046 return rval;
00047 }
00048 };
00049
00050 ErrorCode obbvis_create( GeomTopoTool& gtt, std::vector< int >& volumes, int grid, std::string& filename )
00051 {
00052 OrientedBoxTreeTool& obbtool = *gtt.obb_tree();
00053
00054 CartVect min, max;
00055 EntityHandle vol = gtt.entity_by_id( 3, volumes.front() );
00056 double middle[3];
00057 double axis1[3], axis2[3], axis3[3];
00058 double minPt[3], maxPt[3];
00059 ErrorCode rval = gtt.get_obb( vol, middle, axis1, axis2, axis3 );
00060 // compute min and max verticies
00061 for( int i = 0; i < 3; i++ )
00062 {
00063 double sum = fabs( axis1[i] ) + fabs( axis2[i] ) + fabs( axis3[i] );
00064 minPt[i] = middle[i] - sum;
00065 maxPt[i] = middle[i] + sum;
00066 }
00067 CHECKERR( gtt, rval );
00068
00069 /* Compute an axis-aligned bounding box of all the requested volumes */
00070 for( std::vector< int >::iterator i = volumes.begin() + 1; i != volumes.end(); ++i )
00071 {
00072 CartVect i_min, i_max;
00073 vol = gtt.entity_by_id( 3, *i );
00074 rval = gtt.get_obb( vol, middle, axis1, axis2, axis3 );
00075 // compute min and max verticies
00076 for( int j = 0; j < 3; j++ )
00077 {
00078 double sum = fabs( axis1[j] ) + fabs( axis2[j] ) + fabs( axis3[j] );
00079 minPt[j] = middle[j] - sum;
00080 maxPt[j] = middle[j] + sum;
00081 }
00082
00083 for( int j = 0; j < 3; ++j )
00084 {
00085 min[j] = std::min( min[j], i_min[j] );
00086 max[j] = std::max( max[j], i_max[j] );
00087 }
00088 }
00089
00090 // These vectors could be repurposed to describe an OBB without changing the loops below
00091 CartVect center( middle );
00092 CartVect v1( axis1 );
00093 CartVect v2( axis2 );
00094 CartVect v3( axis3 );
00095
00096 /* Compute the vertices of the visualization grid. Calculation points are at the center
00097 of each cell in this grid, so make grid+1 vertices in each direction. */
00098 int numpoints = pow( (double)( grid + 1 ), 3 );
00099 double* pgrid = new double[numpoints * 3];
00100 int idx = 0;
00101
00102 for( int i = 0; i < numpoints * 3; ++i )
00103 pgrid[i] = 0.0;
00104
00105 for( int i = 0; i <= grid; ++i )
00106 {
00107 CartVect x = -v1 + ( ( v1 * 2.0 ) * ( i / (double)grid ) );
00108
00109 for( int j = 0; j <= grid; ++j )
00110 {
00111 CartVect y = -v2 + ( ( v2 * 2.0 ) * ( j / (double)grid ) );
00112
00113 for( int k = 0; k <= grid; ++k )
00114 {
00115 CartVect z = -v3 + ( ( v3 * 2.0 ) * ( k / (double)grid ) );
00116
00117 CartVect p = center + x + y + z;
00118 for( int d = 0; d < 3; ++d )
00119 {
00120 pgrid[idx++] = p[d];
00121 }
00122 }
00123 }
00124 }
00125
00126 /* Create a new MOAB to use for output, and build the vertex grid */
00127 Core mb2;
00128 Range r;
00129 rval = mb2.create_vertices( pgrid, numpoints, r );
00130 CHECKERR( mb2, rval );
00131
00132 Tag lttag;
00133 rval = mb2.tag_get_handle( "LEAFTRIS", sizeof( int ), MB_TYPE_INTEGER, lttag,
00134 MB_TAG_EXCL | MB_TAG_CREAT | MB_TAG_BYTES | MB_TAG_DENSE, 0 );
00135 CHECKERR( mb2, rval );
00136
00137 int row = grid + 1;
00138 int side = row * row;
00139 EntityHandle connect[8];
00140 EntityHandle hex;
00141
00142 // offset from grid corner to grid center
00143 CartVect grid_hex_center_offset = ( v1 + v2 + v3 ) * 2 * ( 1.0 / grid );
00144
00145 // collect all the surfaces from the requested volumes to iterate over --
00146 // this prevents checking a shared surface more than once.
00147 Range surfs;
00148 for( std::vector< int >::iterator it = volumes.begin(); it != volumes.end(); ++it )
00149 {
00150
00151 vol = gtt.entity_by_id( 3, *it );
00152 Range it_surfs;
00153 rval = gtt.get_moab_instance()->get_child_meshsets( vol, it_surfs );
00154 CHECKERR( gtt, rval );
00155 surfs.merge( it_surfs );
00156 }
00157 std::cout << "visualizing " << surfs.size() << " surfaces." << std::endl;
00158
00159 /* Build hexes for any point with 1 or more leaftris */
00160 for( int i = 0; i < grid; ++i )
00161 {
00162 for( int j = 0; j < grid; ++j )
00163 {
00164 for( int k = 0; k < grid; ++k )
00165 {
00166
00167 idx = ( side * k ) + ( row * j ) + i;
00168 assert( idx + 1 + row + side > numpoints - 1 );
00169
00170 CartVect loc = CartVect( ( pgrid + ( idx * 3 ) ) ) + grid_hex_center_offset;
00171 TriCounter tc( gtt.get_moab_instance(), &obbtool, loc );
00172
00173 for( Range::iterator it = surfs.begin(); it != surfs.end(); ++it )
00174 {
00175
00176 EntityHandle surf_tree;
00177 rval = gtt.get_root( *it, surf_tree );
00178 CHECKERR( gtt, rval );
00179
00180 rval = obbtool.preorder_traverse( surf_tree, tc );
00181 CHECKERR( gtt, rval );
00182 }
00183
00184 if( tc.count == 0 ) continue;
00185
00186 connect[0] = r[idx];
00187 connect[1] = r[idx + 1];
00188 connect[2] = r[idx + 1 + row];
00189 connect[3] = r[idx + row];
00190 connect[4] = r[idx + side];
00191 connect[5] = r[idx + 1 + side];
00192 connect[6] = r[idx + 1 + row + side];
00193 connect[7] = r[idx + row + side];
00194
00195 rval = mb2.create_element( MBHEX, connect, 8, hex );
00196 CHECKERR( mb2, rval );
00197
00198 rval = mb2.tag_set_data( lttag, &hex, 1, &( tc.count ) );
00199 CHECKERR( mb2, rval );
00200 }
00201 }
00202 }
00203
00204 if( verbose )
00205 {
00206 std::cout << "Writing " << filename << std::endl;
00207 }
00208 rval = mb2.write_file( filename.c_str() );
00209 CHECKERR( mb2, rval );
00210
00211 return rval;
00212 }
00213
00214 // stats code borrowed from OrientedBoxTreeTool.cpp
00215 static inline double std_dev( double sqr, double sum, double count )
00216 {
00217 sum /= count;
00218 sqr /= count;
00219 return sqrt( sqr - sum * sum );
00220 }
00221
00222 class TriStats : public OrientedBoxTreeTool::Op
00223 {
00224
00225 public:
00226 unsigned min, max, sum, leaves;
00227 double sqr;
00228
00229 const static unsigned ten_buckets_max = 5;
00230 unsigned ten_buckets[ten_buckets_max];
00231 double ten_buckets_vol[ten_buckets_max];
00232
00233 Interface* mbi;
00234 OrientedBoxTreeTool* tool;
00235
00236 double tot_vol;
00237
00238 TriStats( Interface* mbi_p, OrientedBoxTreeTool* tool_p, EntityHandle root )
00239 : OrientedBoxTreeTool::Op(), sum( 0 ), leaves( 0 ), sqr( 0 ), mbi( mbi_p ), tool( tool_p )
00240 {
00241 min = std::numeric_limits< unsigned >::max();
00242 max = std::numeric_limits< unsigned >::min();
00243
00244 for( unsigned i = 0; i < ten_buckets_max; ++i )
00245 {
00246 ten_buckets[i] = 0;
00247 ten_buckets_vol[i] = 0.;
00248 }
00249
00250 OrientedBox box;
00251 ErrorCode rval = tool->box( root, box );
00252 CHECKERR( mbi, rval );
00253 tot_vol = box.volume();
00254 }
00255
00256 virtual ErrorCode visit( EntityHandle, int, bool& descend )
00257 {
00258
00259 descend = true;
00260 return MB_SUCCESS;
00261 }
00262
00263 virtual ErrorCode leaf( EntityHandle node )
00264 {
00265
00266 Range tris;
00267 ErrorCode rval = tool->get_moab_instance()->get_entities_by_type( node, MBTRI, tris );
00268 unsigned count = tris.size();
00269
00270 sum += count;
00271 sqr += ( count * count );
00272 if( min > count ) min = count;
00273 if( max < count ) max = count;
00274
00275 for( unsigned i = 0; i < ten_buckets_max; ++i )
00276 {
00277 if( count > std::pow( (double)10, (int)( i + 1 ) ) )
00278 {
00279 ten_buckets[i] += 1;
00280 OrientedBox box;
00281 rval = tool->box( node, box );
00282 CHECKERR( mbi, rval );
00283 ten_buckets_vol[i] += box.volume();
00284 }
00285 }
00286
00287 leaves++;
00288
00289 return rval;
00290 }
00291
00292 std::string commafy( int num )
00293 {
00294 std::stringstream str;
00295 str << num;
00296 std::string s = str.str();
00297
00298 int n = s.size();
00299 for( int i = n - 3; i >= 1; i -= 3 )
00300 {
00301 s.insert( i, 1, ',' );
00302 n++;
00303 }
00304
00305 return s;
00306 }
00307
00308 void write_results( std::ostream& out )
00309 {
00310
00311 out << commafy( sum ) << " triangles in " << commafy( leaves ) << " leaves." << std::endl;
00312
00313 double avg = sum / (double)leaves;
00314 double stddev = std_dev( sqr, sum, leaves );
00315
00316 out << "Tris per leaf: Min " << min << ", Max " << max << ", avg " << avg << ", stddev " << stddev << std::endl;
00317
00318 for( unsigned i = 0; i < ten_buckets_max; ++i )
00319 {
00320 if( ten_buckets[i] )
00321 {
00322 out << "Leaves exceeding " << std::pow( (double)10, (int)( i + 1 ) )
00323 << " triangles: " << ten_buckets[i];
00324
00325 double frac_total_vol = ten_buckets_vol[i] / tot_vol;
00326 double avg_ftv = frac_total_vol / ten_buckets[i];
00327
00328 out << " (avg " << avg_ftv * 100.0 << "% of OBB volume)" << std::endl;
00329 }
00330 }
00331 }
00332 };
00333
00334 /* no longer supported
00335 static std::string make_property_string( DagMC& dag, EntityHandle eh, std::vector
00336 &properties )
00337 {
00338 ErrorCode ret;
00339 std::string propstring;
00340 for( std::vector::iterator p = properties.begin();
00341 p != properties.end(); ++p )
00342 {
00343 if( dag.has_prop( eh, *p ) ){
00344 std::vector< std::string> vals;
00345 ret = dag.prop_values( eh, *p, vals );
00346 CHECKERR(dag,ret);
00347 propstring += *p;
00348 if( vals.size() == 1 ){
00349 propstring += "=";
00350 propstring += vals[0];
00351 }
00352 else if( vals.size() > 1 ){
00353 // this property has multiple values, list within brackets
00354 propstring += "=[";
00355 for( std::vector::iterator i = vals.begin();
00356 i != vals.end(); ++i )
00357 {
00358 propstring += *i;
00359 propstring += ",";
00360 }
00361 // replace the last trailing comma with a close braket
00362 propstring[ propstring.length()-1 ] = ']';
00363 }
00364 propstring += ", ";
00365 }
00366 }
00367 if( propstring.length() ){
00368 propstring.resize( propstring.length() - 2 ); // drop trailing comma
00369 }
00370 return propstring;
00371 }
00372 */
00373
00374 ErrorCode obbstat_write( GeomTopoTool& gtt,
00375 std::vector< int >& volumes,
00376 std::vector< std::string >& properties,
00377 std::ostream& out )
00378 {
00379
00380 ErrorCode ret = MB_SUCCESS;
00381 OrientedBoxTreeTool& obbtool = *gtt.obb_tree();
00382
00383 // can assume that volume numbers are valid.
00384 for( std::vector< int >::iterator i = volumes.begin(); i != volumes.end(); ++i )
00385 {
00386 EntityHandle vol_root;
00387 EntityHandle vol = gtt.entity_by_id( 3, *i );
00388 CHECKERR( gtt, ret );
00389
00390 if( vol == 0 )
00391 {
00392 std::cerr << "ERROR: volume " << *i << " has no entity." << std::endl;
00393 continue;
00394 }
00395
00396 ret = gtt.get_root( vol, vol_root );
00397 CHECKERR( gtt, ret );
00398
00399 out << "\nVolume " << *i << " " << std::flush;
00400
00401 if( gtt.is_implicit_complement( vol ) ) out << "(implicit complement) ";
00402 out << std::endl;
00403
00404 // get all surfaces in volume
00405 Range surfs;
00406 ret = gtt.get_moab_instance()->get_child_meshsets( vol, surfs );
00407 CHECKERR( gtt, ret );
00408
00409 out << " with " << surfs.size() << " surfaces" << std::endl;
00410
00411 TriStats ts( gtt.get_moab_instance(), &obbtool, vol_root );
00412 ret = obbtool.preorder_traverse( vol_root, ts );
00413 CHECKERR( gtt, ret );
00414 ts.write_results( out );
00415
00416 if( verbose )
00417 {
00418 out << "Surface list: " << std::flush;
00419 for( Range::iterator j = surfs.begin(); j != surfs.end(); ++j )
00420 {
00421 out << gtt.global_id( *j );
00422 if( j + 1 != surfs.end() ) out << ",";
00423 }
00424 out << std::endl;
00425 ret = obbtool.stats( vol_root, out );
00426 CHECKERR( gtt, ret );
00427 }
00428
00429 out << "\n ------------ " << std::endl;
00430 }
00431
00432 return ret;
00433 }