1 #include <iostream>
2 #include <fstream>
3 #include <sstream>
4
5 #include "moab/Core.hpp"
6 #include "moab/Interface.hpp"
7 #include "moab/OrientedBoxTreeTool.hpp"
8 #include "moab/CartVect.hpp"
9 #include "moab/OrientedBox.hpp"
10 #include "moab/GeomTopoTool.hpp"
11
12 #include "cgm2moab.hpp"
13
14 using namespace moab;
15
16 class TriCounter : public OrientedBoxTreeTool::Op
17 {
18
19 public:
20 int count;
21 Interface* mbi;
22 OrientedBoxTreeTool* tool;
23 const CartVect& pt;
24
25 TriCounter( Interface* mbi_p, OrientedBoxTreeTool* tool_p, const CartVect& p )
26 : OrientedBoxTreeTool::Op(), count( 0 ), mbi( mbi_p ), tool( tool_p ), pt( p )
27 {
28 }
29
30 virtual ErrorCode visit( EntityHandle node, int, bool& descend )
31 {
32 OrientedBox box;
33 ErrorCode rval = tool->box( node, box );
34
35 descend = box.contained( pt, 1e-6 );
36
37 return rval;
38 }
39
40 virtual ErrorCode leaf( EntityHandle node )
41 {
42
43 int numtris;
44 ErrorCode rval = tool->get_moab_instance()->get_number_entities_by_type( node, MBTRI, numtris );
45 count += numtris;
46 return rval;
47 }
48 };
49
50 ErrorCode obbvis_create( GeomTopoTool& gtt, std::vector< int >& volumes, int grid, std::string& filename )
51 {
52 OrientedBoxTreeTool& obbtool = *gtt.obb_tree();
53
54 CartVect min, max;
55 EntityHandle vol = gtt.entity_by_id( 3, volumes.front() );
56 double middle[3];
57 double axis1[3], axis2[3], axis3[3];
58 double minPt[3], maxPt[3];
59 ErrorCode rval = gtt.get_obb( vol, middle, axis1, axis2, axis3 );
60
61 for( int i = 0; i < 3; i++ )
62 {
63 double sum = fabs( axis1[i] ) + fabs( axis2[i] ) + fabs( axis3[i] );
64 minPt[i] = middle[i] - sum;
65 maxPt[i] = middle[i] + sum;
66 }
67 CHECKERR( gtt, rval );
68
69
70 for( std::vector< int >::iterator i = volumes.begin() + 1; i != volumes.end(); ++i )
71 {
72 CartVect i_min, i_max;
73 vol = gtt.entity_by_id( 3, *i );
74 rval = gtt.get_obb( vol, middle, axis1, axis2, axis3 );
75
76 for( int j = 0; j < 3; j++ )
77 {
78 double sum = fabs( axis1[j] ) + fabs( axis2[j] ) + fabs( axis3[j] );
79 minPt[j] = middle[j] - sum;
80 maxPt[j] = middle[j] + sum;
81 }
82
83 for( int j = 0; j < 3; ++j )
84 {
85 min[j] = std::min( min[j], i_min[j] );
86 max[j] = std::max( max[j], i_max[j] );
87 }
88 }
89
90
91 CartVect center( middle );
92 CartVect v1( axis1 );
93 CartVect v2( axis2 );
94 CartVect v3( axis3 );
95
96
98 int numpoints = pow( (double)( grid + 1 ), 3 );
99 double* pgrid = new double[numpoints * 3];
100 int idx = 0;
101
102 for( int i = 0; i < numpoints * 3; ++i )
103 pgrid[i] = 0.0;
104
105 for( int i = 0; i <= grid; ++i )
106 {
107 CartVect x = -v1 + ( ( v1 * 2.0 ) * ( i / (double)grid ) );
108
109 for( int j = 0; j <= grid; ++j )
110 {
111 CartVect y = -v2 + ( ( v2 * 2.0 ) * ( j / (double)grid ) );
112
113 for( int k = 0; k <= grid; ++k )
114 {
115 CartVect z = -v3 + ( ( v3 * 2.0 ) * ( k / (double)grid ) );
116
117 CartVect p = center + x + y + z;
118 for( int d = 0; d < 3; ++d )
119 {
120 pgrid[idx++] = p[d];
121 }
122 }
123 }
124 }
125
126
127 Core mb2;
128 Range r;
129 rval = mb2.create_vertices( pgrid, numpoints, r );
130 CHECKERR( mb2, rval );
131
132 Tag lttag;
133 rval = mb2.tag_get_handle( "LEAFTRIS", sizeof( int ), MB_TYPE_INTEGER, lttag,
134 MB_TAG_EXCL | MB_TAG_CREAT | MB_TAG_BYTES | MB_TAG_DENSE, 0 );
135 CHECKERR( mb2, rval );
136
137 int row = grid + 1;
138 int side = row * row;
139 EntityHandle connect[8];
140 EntityHandle hex;
141
142
143 CartVect grid_hex_center_offset = ( v1 + v2 + v3 ) * 2 * ( 1.0 / grid );
144
145
146
147 Range surfs;
148 for( std::vector< int >::iterator it = volumes.begin(); it != volumes.end(); ++it )
149 {
150
151 vol = gtt.entity_by_id( 3, *it );
152 Range it_surfs;
153 rval = gtt.get_moab_instance()->get_child_meshsets( vol, it_surfs );
154 CHECKERR( gtt, rval );
155 surfs.merge( it_surfs );
156 }
157 std::cout << "visualizing " << surfs.size() << " surfaces." << std::endl;
158
159
160 for( int i = 0; i < grid; ++i )
161 {
162 for( int j = 0; j < grid; ++j )
163 {
164 for( int k = 0; k < grid; ++k )
165 {
166
167 idx = ( side * k ) + ( row * j ) + i;
168 assert( idx + 1 + row + side > numpoints - 1 );
169
170 CartVect loc = CartVect( ( pgrid + ( idx * 3 ) ) ) + grid_hex_center_offset;
171 TriCounter tc( gtt.get_moab_instance(), &obbtool, loc );
172
173 for( Range::iterator it = surfs.begin(); it != surfs.end(); ++it )
174 {
175
176 EntityHandle surf_tree;
177 rval = gtt.get_root( *it, surf_tree );
178 CHECKERR( gtt, rval );
179
180 rval = obbtool.preorder_traverse( surf_tree, tc );
181 CHECKERR( gtt, rval );
182 }
183
184 if( tc.count == 0 ) continue;
185
186 connect[0] = r[idx];
187 connect[1] = r[idx + 1];
188 connect[2] = r[idx + 1 + row];
189 connect[3] = r[idx + row];
190 connect[4] = r[idx + side];
191 connect[5] = r[idx + 1 + side];
192 connect[6] = r[idx + 1 + row + side];
193 connect[7] = r[idx + row + side];
194
195 rval = mb2.create_element( MBHEX, connect, 8, hex );
196 CHECKERR( mb2, rval );
197
198 rval = mb2.tag_set_data( lttag, &hex, 1, &( tc.count ) );
199 CHECKERR( mb2, rval );
200 }
201 }
202 }
203
204 if( verbose )
205 {
206 std::cout << "Writing " << filename << std::endl;
207 }
208 rval = mb2.write_file( filename.c_str() );
209 CHECKERR( mb2, rval );
210
211 return rval;
212 }
213
214
215 static inline double std_dev( double sqr, double sum, double count )
216 {
217 sum /= count;
218 sqr /= count;
219 return sqrt( sqr - sum * sum );
220 }
221
222 class TriStats : public OrientedBoxTreeTool::Op
223 {
224
225 public:
226 unsigned min, max, sum, leaves;
227 double sqr;
228
229 const static unsigned ten_buckets_max = 5;
230 unsigned ten_buckets[ten_buckets_max];
231 double ten_buckets_vol[ten_buckets_max];
232
233 Interface* mbi;
234 OrientedBoxTreeTool* tool;
235
236 double tot_vol;
237
238 TriStats( Interface* mbi_p, OrientedBoxTreeTool* tool_p, EntityHandle root )
239 : OrientedBoxTreeTool::Op(), sum( 0 ), leaves( 0 ), sqr( 0 ), mbi( mbi_p ), tool( tool_p )
240 {
241 min = std::numeric_limits< unsigned >::max();
242 max = std::numeric_limits< unsigned >::min();
243
244 for( unsigned i = 0; i < ten_buckets_max; ++i )
245 {
246 ten_buckets[i] = 0;
247 ten_buckets_vol[i] = 0.;
248 }
249
250 OrientedBox box;
251 ErrorCode rval = tool->box( root, box );
252 CHECKERR( mbi, rval );
253 tot_vol = box.volume();
254 }
255
256 virtual ErrorCode visit( EntityHandle, int, bool& descend )
257 {
258
259 descend = true;
260 return MB_SUCCESS;
261 }
262
263 virtual ErrorCode leaf( EntityHandle node )
264 {
265
266 Range tris;
267 ErrorCode rval = tool->get_moab_instance()->get_entities_by_type( node, MBTRI, tris );
268 unsigned count = tris.size();
269
270 sum += count;
271 sqr += ( count * count );
272 if( min > count ) min = count;
273 if( max < count ) max = count;
274
275 for( unsigned i = 0; i < ten_buckets_max; ++i )
276 {
277 if( count > std::pow( (double)10, (int)( i + 1 ) ) )
278 {
279 ten_buckets[i] += 1;
280 OrientedBox box;
281 rval = tool->box( node, box );
282 CHECKERR( mbi, rval );
283 ten_buckets_vol[i] += box.volume();
284 }
285 }
286
287 leaves++;
288
289 return rval;
290 }
291
292 std::string commafy( int num )
293 {
294 std::stringstream str;
295 str << num;
296 std::string s = str.str();
297
298 int n = s.size();
299 for( int i = n - 3; i >= 1; i -= 3 )
300 {
301 s.insert( i, 1, ',' );
302 n++;
303 }
304
305 return s;
306 }
307
308 void write_results( std::ostream& out )
309 {
310
311 out << commafy( sum ) << " triangles in " << commafy( leaves ) << " leaves." << std::endl;
312
313 double avg = sum / (double)leaves;
314 double stddev = std_dev( sqr, sum, leaves );
315
316 out << "Tris per leaf: Min " << min << ", Max " << max << ", avg " << avg << ", stddev " << stddev << std::endl;
317
318 for( unsigned i = 0; i < ten_buckets_max; ++i )
319 {
320 if( ten_buckets[i] )
321 {
322 out << "Leaves exceeding " << std::pow( (double)10, (int)( i + 1 ) )
323 << " triangles: " << ten_buckets[i];
324
325 double frac_total_vol = ten_buckets_vol[i] / tot_vol;
326 double avg_ftv = frac_total_vol / ten_buckets[i];
327
328 out << " (avg " << avg_ftv * 100.0 << "% of OBB volume)" << std::endl;
329 }
330 }
331 }
332 };
333
334
373
374 ErrorCode obbstat_write( GeomTopoTool& gtt,
375 std::vector< int >& volumes,
376 std::vector< std::string >& ,
377 std::ostream& out )
378 {
379
380 ErrorCode ret = MB_SUCCESS;
381 OrientedBoxTreeTool& obbtool = *gtt.obb_tree();
382
383
384 for( std::vector< int >::iterator i = volumes.begin(); i != volumes.end(); ++i )
385 {
386 EntityHandle vol_root;
387 EntityHandle vol = gtt.entity_by_id( 3, *i );
388 CHECKERR( gtt, ret );
389
390 if( vol == 0 )
391 {
392 std::cerr << "ERROR: volume " << *i << " has no entity." << std::endl;
393 continue;
394 }
395
396 ret = gtt.get_root( vol, vol_root );
397 CHECKERR( gtt, ret );
398
399 out << "\nVolume " << *i << " " << std::flush;
400
401 if( gtt.is_implicit_complement( vol ) ) out << "(implicit complement) ";
402 out << std::endl;
403
404
405 Range surfs;
406 ret = gtt.get_moab_instance()->get_child_meshsets( vol, surfs );
407 CHECKERR( gtt, ret );
408
409 out << " with " << surfs.size() << " surfaces" << std::endl;
410
411 TriStats ts( gtt.get_moab_instance(), &obbtool, vol_root );
412 ret = obbtool.preorder_traverse( vol_root, ts );
413 CHECKERR( gtt, ret );
414 ts.write_results( out );
415
416 if( verbose )
417 {
418 out << "Surface list: " << std::flush;
419 for( Range::iterator j = surfs.begin(); j != surfs.end(); ++j )
420 {
421 out << gtt.global_id( *j );
422 if( j + 1 != surfs.end() ) out << ",";
423 }
424 out << std::endl;
425 ret = obbtool.stats( vol_root, out );
426 CHECKERR( gtt, ret );
427 }
428
429 out << "\n ------------ " << std::endl;
430 }
431
432 return ret;
433 }