MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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 /**\file OrientedBox.hpp 00017 *\author Jason Kraftcheck ([email protected]) 00018 *\date 2006-07-18 00019 */ 00020 00021 #ifndef MB_ORIENTED_BOX_HPP 00022 #define MB_ORIENTED_BOX_HPP 00023 00024 #include "moab/Forward.hpp" 00025 #include "moab/CartVect.hpp" 00026 #include "moab/Matrix3.hpp" 00027 00028 #include <iosfwd> 00029 00030 namespace moab 00031 { 00032 00033 #define MB_ORIENTED_BOX_UNIT_VECTORS 1 00034 #define MB_ORIENTED_BOX_OUTER_RADIUS 1 00035 00036 class Range; 00037 00038 /**\brief Oriented bounding box 00039 */ 00040 class OrientedBox 00041 { 00042 private: 00043 void order_axes_by_length( double ax1_len, 00044 double ax2_len, 00045 double ax3_len ); //!< orders the box axes by the given lengths for each axis 00046 00047 public: 00048 CartVect center; //!< Box center 00049 Matrix3 axes; //!< Box axes, unit vectors sorted by extent of box along axis 00050 #if MB_ORIENTED_BOX_UNIT_VECTORS 00051 CartVect length; //!< distance from center to plane along each axis 00052 #endif 00053 #if MB_ORIENTED_BOX_OUTER_RADIUS 00054 double radius; //!< outer radius (1/2 diagonal length) of box 00055 #endif 00056 00057 inline OrientedBox() : radius( 0.0 ) {} 00058 00059 OrientedBox( const Matrix3& axes_mat, const CartVect& center ); 00060 OrientedBox( const CartVect axes_in[3], const CartVect& center ); 00061 00062 inline double inner_radius() const; //!< radius of inscribed sphere 00063 inline double outer_radius() const; //!< radius of circumscribed sphere 00064 inline double outer_radius_squared( 00065 const double reps ) const; //!< square of (radius+at least epsilon) of circumsphere 00066 inline double inner_radius_squared( const double reps ) const; //!< square of (radius-epsilon) of inscribed sphere 00067 inline double volume() const; //!< volume of box 00068 inline CartVect dimensions() const; //!< number of dimensions for which box is not flat 00069 inline double area() const; //!< largest side area 00070 inline CartVect axis( int index ) const; //!< get unit vector in direction of axis 00071 inline CartVect scaled_axis( int index ) const; //!< get vector in direction of axis, scaled to its true length 00072 00073 /** Test if point is contained in box */ 00074 bool contained( const CartVect& point, double tolerance ) const; 00075 00076 // bool contained( const OrientedBox& other, double tolerance ) const; 00077 00078 /**\brief get tag handle for storing oriented box 00079 * 00080 * Get the handle for the tag with the specified name and 00081 * check that the tag is appropriate for storing instances 00082 * of OrientedBox. The resulting tag may be used to store 00083 * instances of OrientedBox directly. 00084 * 00085 *\param handle_out The TagHandle, passed back to caller 00086 *\param name The tag name 00087 *\param create If true, tag will be created if it does not exist 00088 */ 00089 static ErrorCode tag_handle( Tag& handle_out, Interface* instance, const char* name ); 00090 00091 /**\brief Calculate an oriented box from a set of vertices */ 00092 static ErrorCode compute_from_vertices( OrientedBox& result, Interface* instance, const Range& vertices ); 00093 00094 /**\brief Calculate an oriented box from a set of 2D elements */ 00095 static ErrorCode compute_from_2d_cells( OrientedBox& result, Interface* instance, const Range& elements ); 00096 00097 /** Structure to hold temporary accumulated triangle data for 00098 * calculating box orientation. See box_from_covariance_data 00099 * to see how this is used to calculate the final covariance matrix 00100 * and resulting box orientation. 00101 */ 00102 struct CovarienceData 00103 { 00104 CovarienceData() : area( 0.0 ) {} 00105 CovarienceData( const Matrix3& m, const CartVect& c, double a ) : matrix( m ), center( c ), area( a ) {} 00106 Matrix3 matrix; //!< Running sum for covariance matrix 00107 CartVect center; //!< Sum of triangle centroids weighted by 2*triangle area 00108 double area; //!< 2x the sum of the triangle areas 00109 }; 00110 00111 /** Calculate a CovarienceData struct from a list of triangles */ 00112 static ErrorCode covariance_data_from_tris( CovarienceData& result, 00113 Interface* moab_instance, 00114 const Range& elements ); 00115 00116 /** Calculate an OrientedBox given an array of CovarienceData and 00117 * the list of vertices the box is to bound. 00118 */ 00119 static ErrorCode compute_from_covariance_data( OrientedBox& result, 00120 Interface* moab_instance, 00121 const CovarienceData* orient_array, 00122 unsigned orient_array_length, 00123 const Range& vertices ); 00124 00125 /** Test for intersection of a ray (or line segment) with this box. 00126 * Ray length limits are used to optimize Monte Carlo particle tracking. 00127 *\param ray_start_point The base point of the ray 00128 *\param ray_unit_direction The direction of the ray (must be unit length) 00129 *\param distance_tolerance Tolerance to use in intersection checks 00130 *\param nonnegative_ray_len Optional length of ray in forward direction 00131 *\param negative_ray_len Optional length of ray in reverse direction 00132 */ 00133 bool intersect_ray( const CartVect& ray_start_point, 00134 const CartVect& ray_unit_direction, 00135 const double distance_tolerance, 00136 const double* nonnegatve_ray_len = 0, 00137 const double* negative_ray_len = 0 ) const; 00138 00139 /**\brief Find closest position on/within box to input position. 00140 * 00141 * Find the closest position in the solid box to the input position. 00142 * If the input position is on or within the box, then the output 00143 * position will be the same as the input position. If the input 00144 * position is outside the box, the outside position will be the 00145 * closest point on the box boundary to the input position. 00146 */ 00147 void closest_location_in_box( const CartVect& input_position, CartVect& output_position ) const; 00148 00149 //! Construct a hexahedral element with the same shape as this box. 00150 ErrorCode make_hex( EntityHandle& hex, Interface* instance ); 00151 00152 /** Calculate an OrientedBox given a CovarienceData struct and 00153 * the list of points the box is to bound. 00154 */ 00155 static ErrorCode compute_from_covariance_data( OrientedBox& result, 00156 Interface* moab_instance, 00157 CovarienceData& orientation_data, 00158 const Range& vertices ); 00159 }; 00160 00161 std::ostream& operator<<( std::ostream&, const OrientedBox& ); 00162 00163 double OrientedBox::inner_radius() const 00164 { 00165 #if MB_ORIENTED_BOX_UNIT_VECTORS 00166 return length[0]; 00167 #else 00168 return axes.col( 0 ).length(); 00169 #endif 00170 } 00171 00172 double OrientedBox::outer_radius() const 00173 { 00174 #if MB_ORIENTED_BOX_OUTER_RADIUS 00175 return radius; 00176 #elif MB_ORIENTED_BOX_UNIT_VECTORS 00177 return length.length(); 00178 #else 00179 return ( axes.col( 0 ) + axes.col( 1 ) + axes.col( 2 ) ).length(); 00180 #endif 00181 } 00182 00183 // Add at least epsilon to the radius, before squaring it. 00184 double OrientedBox::outer_radius_squared( const double reps ) const 00185 { 00186 #if MB_ORIENTED_BOX_OUTER_RADIUS 00187 return ( radius + reps ) * ( radius + reps ); 00188 #elif MB_ORIENTED_BOX_UNIT_VECTORS 00189 CartVect tmp( length[0] + reps, length[1] + reps, length[2] + reps ); 00190 return tmp % tmp; 00191 #else 00192 CartVect half_diag = axes.col( 0 ) + axes.col( 1 ) + axes.col( 2 ); 00193 half_diag += CartVect( reps, reps, reps ); 00194 return half_diag % half_diag; 00195 #endif 00196 } 00197 00198 // Subtract epsilon from the length of the shortest axis, before squaring it. 00199 double OrientedBox::inner_radius_squared( const double reps ) const 00200 { 00201 #if MB_ORIENTED_BOX_UNIT_VECTORS 00202 return ( length[0] - reps ) * ( length[0] - reps ); 00203 #else 00204 CartVect tmp = axes.col( 0 ); 00205 tmp -= CartVect( reps, reps, reps ); 00206 return ( tmp % tmp ); 00207 #endif 00208 } 00209 00210 double OrientedBox::volume() const 00211 { 00212 #if MB_ORIENTED_BOX_UNIT_VECTORS 00213 return 8 * length[0] * length[1] * length[2]; 00214 #else 00215 return fabs( 8 * axes.col( 0 ) % ( axes.col( 1 ) * axes.col( 2 ) ) ); 00216 #endif 00217 } 00218 00219 CartVect OrientedBox::dimensions() const 00220 { 00221 #if MB_ORIENTED_BOX_UNIT_VECTORS 00222 return 2.0 * length; 00223 #else 00224 return 2.0 * CartVect( axes.col( 0 ).length(), axes.col( 1 ).length(), axes.col( 2 ).length() ); 00225 #endif 00226 } 00227 00228 double OrientedBox::area() const 00229 { 00230 #if MB_ORIENTED_BOX_UNIT_VECTORS 00231 return 4 * length[1] * length[2]; 00232 #else 00233 return 4 * ( axes.col( 1 ) * axes.col( 2 ) ).length(); 00234 #endif 00235 } 00236 00237 CartVect OrientedBox::axis( int index ) const 00238 { 00239 return axes.col( index ); 00240 } 00241 00242 CartVect OrientedBox::scaled_axis( int index ) const 00243 { 00244 #if MB_ORIENTED_BOX_UNIT_VECTORS 00245 return length[index] * axes.col( index ); 00246 #else 00247 return axes.col( index ); 00248 #endif 00249 } 00250 00251 } // namespace moab 00252 00253 #endif