1 /*
2 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3 * storing and accessing finite element mesh data.
4 *
5 * Copyright 2004 Sandia Corporation. Under the terms of Contract
6 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7 * retains certain rights in this software.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 */
15
16 /**\file OrientedBox.hpp
17 *\author Jason Kraftcheck (kraftche@cae.wisc.edu)
18 *\date 2006-07-18
19 */
20
21 #ifndef MB_ORIENTED_BOX_HPP
22 #define MB_ORIENTED_BOX_HPP
23
24 #include "moab/Forward.hpp"
25 #include "moab/CartVect.hpp"
26 #include "moab/Matrix3.hpp"
27
28 #include <iosfwd>
29
30 namespace moab
31 {
32
33 #define MB_ORIENTED_BOX_UNIT_VECTORS 1
34 #define MB_ORIENTED_BOX_OUTER_RADIUS 1
35
36 class Range;
37
38 /**\brief Oriented bounding box
39 */
40 class OrientedBox
41 {
42 private:
43 void order_axes_by_length( double ax1_len,
44 double ax2_len,
45 double ax3_len ); //!< orders the box axes by the given lengths for each axis
46
47 public:
48 CartVect center; //!< Box center
49 Matrix3 axes; //!< Box axes, unit vectors sorted by extent of box along axis
50 #if MB_ORIENTED_BOX_UNIT_VECTORS
51 CartVect length; //!< distance from center to plane along each axis
52 #endif
53 #if MB_ORIENTED_BOX_OUTER_RADIUS
54 double radius; //!< outer radius (1/2 diagonal length) of box
55 #endif
56
57 inline OrientedBox() : radius( 0.0 ) {}
58
59 OrientedBox( const Matrix3& axes_mat, const CartVect& center );
60 OrientedBox( const CartVect axes_in[3], const CartVect& center );
61
62 inline double inner_radius() const; //!< radius of inscribed sphere
63 inline double outer_radius() const; //!< radius of circumscribed sphere
64 inline double outer_radius_squared(
65 const double reps ) const; //!< square of (radius+at least epsilon) of circumsphere
66 inline double inner_radius_squared( const double reps ) const; //!< square of (radius-epsilon) of inscribed sphere
67 inline double volume() const; //!< volume of box
68 inline CartVect dimensions() const; //!< number of dimensions for which box is not flat
69 inline double area() const; //!< largest side area
70 inline CartVect axis( int index ) const; //!< get unit vector in direction of axis
71 inline CartVect scaled_axis( int index ) const; //!< get vector in direction of axis, scaled to its true length
72
73 /** Test if point is contained in box */
74 bool contained( const CartVect& point, double tolerance ) const;
75
76 // bool contained( const OrientedBox& other, double tolerance ) const;
77
78 /**\brief get tag handle for storing oriented box
79 *
80 * Get the handle for the tag with the specified name and
81 * check that the tag is appropriate for storing instances
82 * of OrientedBox. The resulting tag may be used to store
83 * instances of OrientedBox directly.
84 *
85 *\param handle_out The TagHandle, passed back to caller
86 *\param name The tag name
87 *\param create If true, tag will be created if it does not exist
88 */
89 static ErrorCode tag_handle( Tag& handle_out, Interface* instance, const char* name );
90
91 /**\brief Calculate an oriented box from a set of vertices */
92 static ErrorCode compute_from_vertices( OrientedBox& result, Interface* instance, const Range& vertices );
93
94 /**\brief Calculate an oriented box from a set of 2D elements */
95 static ErrorCode compute_from_2d_cells( OrientedBox& result, Interface* instance, const Range& elements );
96
97 /** Structure to hold temporary accumulated triangle data for
98 * calculating box orientation. See box_from_covariance_data
99 * to see how this is used to calculate the final covariance matrix
100 * and resulting box orientation.
101 */
102 struct CovarienceData
103 {
104 CovarienceData() : area( 0.0 ) {}
105 CovarienceData( const Matrix3& m, const CartVect& c, double a ) : matrix( m ), center( c ), area( a ) {}
106 Matrix3 matrix; //!< Running sum for covariance matrix
107 CartVect center; //!< Sum of triangle centroids weighted by 2*triangle area
108 double area; //!< 2x the sum of the triangle areas
109 };
110
111 /** Calculate a CovarienceData struct from a list of triangles */
112 static ErrorCode covariance_data_from_tris( CovarienceData& result,
113 Interface* moab_instance,
114 const Range& elements );
115
116 /** Calculate an OrientedBox given an array of CovarienceData and
117 * the list of vertices the box is to bound.
118 */
119 static ErrorCode compute_from_covariance_data( OrientedBox& result,
120 Interface* moab_instance,
121 const CovarienceData* orient_array,
122 unsigned orient_array_length,
123 const Range& vertices );
124
125 /** Test for intersection of a ray (or line segment) with this box.
126 * Ray length limits are used to optimize Monte Carlo particle tracking.
127 *\param ray_start_point The base point of the ray
128 *\param ray_unit_direction The direction of the ray (must be unit length)
129 *\param distance_tolerance Tolerance to use in intersection checks
130 *\param nonnegative_ray_len Optional length of ray in forward direction
131 *\param negative_ray_len Optional length of ray in reverse direction
132 */
133 bool intersect_ray( const CartVect& ray_start_point,
134 const CartVect& ray_unit_direction,
135 const double distance_tolerance,
136 const double* nonnegatve_ray_len = 0,
137 const double* negative_ray_len = 0 ) const;
138
139 /**\brief Find closest position on/within box to input position.
140 *
141 * Find the closest position in the solid box to the input position.
142 * If the input position is on or within the box, then the output
143 * position will be the same as the input position. If the input
144 * position is outside the box, the outside position will be the
145 * closest point on the box boundary to the input position.
146 */
147 void closest_location_in_box( const CartVect& input_position, CartVect& output_position ) const;
148
149 //! Construct a hexahedral element with the same shape as this box.
150 ErrorCode make_hex( EntityHandle& hex, Interface* instance );
151
152 /** Calculate an OrientedBox given a CovarienceData struct and
153 * the list of points the box is to bound.
154 */
155 static ErrorCode compute_from_covariance_data( OrientedBox& result,
156 Interface* moab_instance,
157 CovarienceData& orientation_data,
158 const Range& vertices );
159 };
160
161 std::ostream& operator<<( std::ostream&, const OrientedBox& );
162
163 double OrientedBox::inner_radius() const
164 {
165 #if MB_ORIENTED_BOX_UNIT_VECTORS
166 return length[0];
167 #else
168 return axes.col( 0 ).length();
169 #endif
170 }
171
172 double OrientedBox::outer_radius() const
173 {
174 #if MB_ORIENTED_BOX_OUTER_RADIUS
175 return radius;
176 #elif MB_ORIENTED_BOX_UNIT_VECTORS
177 return length.length();
178 #else
179 return ( axes.col( 0 ) + axes.col( 1 ) + axes.col( 2 ) ).length();
180 #endif
181 }
182
183 // Add at least epsilon to the radius, before squaring it.
184 double OrientedBox::outer_radius_squared( const double reps ) const
185 {
186 #if MB_ORIENTED_BOX_OUTER_RADIUS
187 return ( radius + reps ) * ( radius + reps );
188 #elif MB_ORIENTED_BOX_UNIT_VECTORS
189 CartVect tmp( length[0] + reps, length[1] + reps, length[2] + reps );
190 return tmp % tmp;
191 #else
192 CartVect half_diag = axes.col( 0 ) + axes.col( 1 ) + axes.col( 2 );
193 half_diag += CartVect( reps, reps, reps );
194 return half_diag % half_diag;
195 #endif
196 }
197
198 // Subtract epsilon from the length of the shortest axis, before squaring it.
199 double OrientedBox::inner_radius_squared( const double reps ) const
200 {
201 #if MB_ORIENTED_BOX_UNIT_VECTORS
202 return ( length[0] - reps ) * ( length[0] - reps );
203 #else
204 CartVect tmp = axes.col( 0 );
205 tmp -= CartVect( reps, reps, reps );
206 return ( tmp % tmp );
207 #endif
208 }
209
210 double OrientedBox::volume() const
211 {
212 #if MB_ORIENTED_BOX_UNIT_VECTORS
213 return 8 * length[0] * length[1] * length[2];
214 #else
215 return fabs( 8 * axes.col( 0 ) % ( axes.col( 1 ) * axes.col( 2 ) ) );
216 #endif
217 }
218
219 CartVect OrientedBox::dimensions() const
220 {
221 #if MB_ORIENTED_BOX_UNIT_VECTORS
222 return 2.0 * length;
223 #else
224 return 2.0 * CartVect( axes.col( 0 ).length(), axes.col( 1 ).length(), axes.col( 2 ).length() );
225 #endif
226 }
227
228 double OrientedBox::area() const
229 {
230 #if MB_ORIENTED_BOX_UNIT_VECTORS
231 return 4 * length[1] * length[2];
232 #else
233 return 4 * ( axes.col( 1 ) * axes.col( 2 ) ).length();
234 #endif
235 }
236
237 CartVect OrientedBox::axis( int index ) const
238 {
239 return axes.col( index );
240 }
241
242 CartVect OrientedBox::scaled_axis( int index ) const
243 {
244 #if MB_ORIENTED_BOX_UNIT_VECTORS
245 return length[index] * axes.col( index );
246 #else
247 return axes.col( index );
248 #endif
249 }
250
251 } // namespace moab
252
253 #endif