MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 #include "moab/Interface.hpp" 00002 #include "moab/BoundBox.hpp" 00003 00004 // this is used for spherical elements, bounding box needs to be updated due to curvature 00005 #include "moab/IntxMesh/IntxUtils.hpp" 00006 00007 namespace moab 00008 { 00009 ErrorCode BoundBox::update( Interface& iface, const Range& elems, bool spherical, double radius ) 00010 { 00011 ErrorCode rval; 00012 bMin = CartVect( HUGE_VAL ); 00013 bMax = CartVect( -HUGE_VAL ); 00014 00015 CartVect coords; 00016 EntityHandle const *conn = NULL, *conn2 = NULL; 00017 int len = 0, len2 = 0; 00018 Range::const_iterator i; 00019 CartVect coordverts[27]; // maximum nodes per element supported by MOAB 00020 00021 // vertices 00022 const Range::const_iterator elem_begin = elems.lower_bound( MBEDGE ); 00023 for( i = elems.begin(); i != elem_begin; ++i ) 00024 { 00025 rval = iface.get_coords( &*i, 1, coords.array() ); 00026 if( MB_SUCCESS != rval ) return rval; 00027 update_min( coords.array() ); 00028 update_max( coords.array() ); 00029 } 00030 00031 // elements with vertex-handle connectivity list 00032 const Range::const_iterator poly_begin = elems.lower_bound( MBPOLYHEDRON, elem_begin ); 00033 std::vector< EntityHandle > dum_vector; 00034 for( i = elem_begin; i != poly_begin; ++i ) 00035 { 00036 rval = iface.get_connectivity( *i, conn, len, true, &dum_vector ); 00037 if( MB_SUCCESS != rval ) return rval; 00038 00039 rval = iface.get_coords( conn, len, &( coordverts[0][0] ) ); 00040 if( MB_SUCCESS != rval ) return rval; 00041 for( int j = 0; j < len; ++j ) 00042 { 00043 update_min( coordverts[j].array() ); 00044 update_max( coordverts[j].array() ); 00045 } 00046 // if spherical, use gnomonic projection to improve the computed box 00047 // it is used now for coupling only 00048 if( spherical ) update_box_spherical_elem( coordverts, len, radius ); 00049 } 00050 00051 // polyhedra 00052 const Range::const_iterator set_begin = elems.lower_bound( MBENTITYSET, poly_begin ); 00053 for( i = poly_begin; i != set_begin; ++i ) 00054 { 00055 rval = iface.get_connectivity( *i, conn, len, true ); 00056 if( MB_SUCCESS != rval ) return rval; 00057 00058 for( int j = 0; j < len; ++j ) 00059 { 00060 rval = iface.get_connectivity( conn[j], conn2, len2 ); 00061 if( MB_SUCCESS != rval ) return rval; 00062 rval = iface.get_coords( conn2, len2, &( coordverts[0][0] ) ); 00063 if( MB_SUCCESS != rval ) return rval; 00064 for( int k = 0; k < len2; ++k ) 00065 { 00066 update_min( coordverts[k].array() ); 00067 update_max( coordverts[k].array() ); 00068 } 00069 } 00070 } 00071 00072 // sets 00073 BoundBox box; 00074 for( i = set_begin; i != elems.end(); ++i ) 00075 { 00076 Range tmp_elems; 00077 rval = iface.get_entities_by_handle( *i, tmp_elems ); 00078 if( MB_SUCCESS != rval ) return rval; 00079 rval = box.update( iface, tmp_elems, spherical, radius ); 00080 if( MB_SUCCESS != rval ) return rval; 00081 00082 update( box ); 00083 } 00084 00085 return MB_SUCCESS; 00086 } 00087 void BoundBox::update_box_spherical_elem( const CartVect* verts, int len, double R ) 00088 { 00089 // decide first the gnomonic plane, based on first coordinate 00090 int plane = -1; 00091 CartVect pos; 00092 IntxUtils::decide_gnomonic_plane( verts[0], plane ); 00093 double in_plane_positions[20]; // at most polygons with 10 edges; do we need to revise this? 00094 for( int i = 0; i < len && i < 10; i++ ) 00095 IntxUtils::gnomonic_projection( verts[i], R, plane, in_plane_positions[2 * i], in_plane_positions[2 * i + 1] ); 00096 // look for points on the intersection between edges in gnomonic plane and coordinate axes 00097 // if yes, reverse projection of intx point, and update box 00098 double oriented_area2 = 0; 00099 // if oriented area is != zero, it means the origin is inside the polygon, so we need to upgrade 00100 // the box with the origin, so we do not miss anything (the top of the dome) 00101 for( int i = 0; i < len; i++ ) 00102 { 00103 int i1 = ( i + 1 ) % len; // next vertex in polygon 00104 // check intx with x axis 00105 double ax = in_plane_positions[2 * i], ay = in_plane_positions[2 * i + 1]; 00106 double bx = in_plane_positions[2 * i1], by = in_plane_positions[2 * i1 + 1]; 00107 if( ay * by < 0 ) // it intersects with x axis 00108 { 00109 double alfa = ay / ( ay - by ); 00110 double xintx = ax + alfa * ( bx - ax ); 00111 IntxUtils::reverse_gnomonic_projection( xintx, 0, R, plane, pos ); 00112 update_min( pos.array() ); 00113 update_max( pos.array() ); 00114 } 00115 if( ax * bx < 0 ) // it intersects with y axis 00116 { 00117 double alfa = ax / ( ax - bx ); 00118 double yintx = ay + alfa * ( by - ay ); 00119 IntxUtils::reverse_gnomonic_projection( 0, yintx, R, plane, pos ); 00120 update_min( pos.array() ); 00121 update_max( pos.array() ); 00122 } 00123 oriented_area2 += ( ax * by - ay * bx ); 00124 } 00125 if( fabs( oriented_area2 ) > R * R * 1.e-6 ) // origin is in the interior, add the center 00126 { 00127 IntxUtils::reverse_gnomonic_projection( 0, 0, R, plane, pos ); 00128 update_min( pos.array() ); 00129 update_max( pos.array() ); 00130 } 00131 } 00132 } // namespace moab