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 /* 00017 * The algorithms for the calculation of the oriented box from a 00018 * set of points or a set of cells was copied from the implementation 00019 " in the "Visualization Toolkit". J.K. - 2006-07-19 00020 * 00021 * Program: Visualization Toolkit 00022 * Module: $RCSfile$ 00023 * 00024 * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 00025 * All rights reserved. 00026 * See Copyright.txt or http://www.kitware.com/Copyright.htm for details. 00027 */ 00028 00029 /**\file OrientedBox.cpp 00030 *\author Jason Kraftcheck ([email protected]) 00031 *\date 2006-07-18 00032 */ 00033 00034 #include "moab/Interface.hpp" 00035 #include "moab/CN.hpp" 00036 #include "moab/OrientedBox.hpp" 00037 #include "moab/Range.hpp" 00038 #include <ostream> 00039 #include <cassert> 00040 #include <limits> 00041 00042 namespace moab 00043 { 00044 00045 std::ostream& operator<<( std::ostream& s, const OrientedBox& b ) 00046 { 00047 return s << b.center << " + " << b.axes.col( 0 ) 00048 #if MB_ORIENTED_BOX_UNIT_VECTORS 00049 << ":" << b.length[0] 00050 #endif 00051 << " x " << b.axes.col( 1 ) 00052 #if MB_ORIENTED_BOX_UNIT_VECTORS 00053 << ":" << b.length[1] 00054 #endif 00055 << " x " << b.axes.col( 2 ) 00056 #if MB_ORIENTED_BOX_UNIT_VECTORS 00057 << ":" << b.length[2] 00058 #endif 00059 ; 00060 } 00061 00062 /**\brief Find closest point on line 00063 * 00064 * Find the point on the line for which a line trough the 00065 * input point \a p and the result position is orthogonal to 00066 * the input line. 00067 * \param p The point for which to find the perpendicular 00068 * \param b A point on the line 00069 * \param m The direction of the line 00070 * \return The location on the line specified as 't' in the 00071 * formula t * m + b 00072 */ 00073 static double point_perp( const CartVect& p, // closest to this point 00074 const CartVect& b, // point on line 00075 const CartVect& m ) // line direction 00076 { 00077 #if MB_ORIENTED_BOX_UNIT_VECTORS 00078 double t = ( m % ( p - b ) ); 00079 #else 00080 double t = ( m % ( p - b ) ) / ( m % m ); 00081 #endif 00082 return Util::is_finite( t ) ? t : 0.0; 00083 } 00084 00085 void OrientedBox::order_axes_by_length( double ax1_len, double ax2_len, double ax3_len ) 00086 { 00087 00088 CartVect len( ax1_len, ax2_len, ax3_len ); 00089 00090 if( len[2] < len[1] ) 00091 { 00092 if( len[2] < len[0] ) 00093 { 00094 std::swap( len[0], len[2] ); 00095 axes.swapcol( 0, 2 ); 00096 } 00097 } 00098 else if( len[1] < len[0] ) 00099 { 00100 std::swap( len[0], len[1] ); 00101 axes.swapcol( 0, 1 ); 00102 } 00103 if( len[1] > len[2] ) 00104 { 00105 std::swap( len[1], len[2] ); 00106 axes.swapcol( 1, 2 ); 00107 } 00108 00109 #if MB_ORIENTED_BOX_UNIT_VECTORS 00110 length = len; 00111 if( len[0] > 0.0 ) axes.colscale( 0, 1.0 / len[0] ); 00112 if( len[1] > 0.0 ) axes.colscale( 1, 1.0 / len[1] ); 00113 if( len[2] > 0.0 ) axes.colscale( 2, 1.0 / len[2] ); 00114 #endif 00115 00116 #if MB_ORIENTED_BOX_OUTER_RADIUS 00117 radius = len.length(); 00118 #endif 00119 } 00120 00121 OrientedBox::OrientedBox( const CartVect axes_in[3], const CartVect& mid ) : center( mid ) 00122 { 00123 00124 axes = Matrix3( axes_in[0], axes_in[1], axes_in[2], false ); 00125 00126 order_axes_by_length( axes_in[0].length(), axes_in[1].length(), axes_in[2].length() ); 00127 } 00128 00129 OrientedBox::OrientedBox( const Matrix3& axes_mat, const CartVect& mid ) : center( mid ), axes( axes_mat ) 00130 { 00131 order_axes_by_length( axes.col( 0 ).length(), axes.col( 1 ).length(), axes.col( 2 ).length() ); 00132 } 00133 00134 ErrorCode OrientedBox::tag_handle( Tag& handle_out, Interface* instance, const char* name ) 00135 { 00136 // We're going to assume this when mapping the OrientedBox 00137 // to tag data, so assert it. 00138 #if MB_ORIENTED_BOX_OUTER_RADIUS 00139 const int rad_size = 1; 00140 #else 00141 const int rad_size = 0; 00142 #endif 00143 #if MB_ORIENTED_BOX_UNIT_VECTORS 00144 const int SIZE = rad_size + 15; 00145 #else 00146 const int SIZE = rad_size + 12; 00147 #endif 00148 assert( sizeof( OrientedBox ) == SIZE * sizeof( double ) ); 00149 00150 return instance->tag_get_handle( name, SIZE, MB_TYPE_DOUBLE, handle_out, MB_TAG_DENSE | MB_TAG_CREAT ); 00151 } 00152 00153 /**\brief Common code for box calculation 00154 * 00155 * Given the orientation of the box and an approximate center, 00156 * calculate the exact center and extents of the box. 00157 * 00158 *\param result.center As input, the approximate center of the box. 00159 * As output, the exact center of the box. 00160 *\param result.axes As input, directions of principal axes corresponding 00161 * to the orientation of the box. Axes are assumed to 00162 * be unit-length on input. Output will include extents 00163 * of box. 00164 *\param points The set of points the box should contain. 00165 */ 00166 static ErrorCode box_from_axes( OrientedBox& result, Interface* instance, const Range& points ) 00167 { 00168 ErrorCode rval; 00169 00170 // project points onto axes to get box extents 00171 CartVect min( std::numeric_limits< double >::max() ), max( -std::numeric_limits< double >::max() ); 00172 for( Range::iterator i = points.begin(); i != points.end(); ++i ) 00173 { 00174 CartVect coords; 00175 rval = instance->get_coords( &*i, 1, coords.array() );MB_CHK_ERR( rval ); 00176 00177 for( int d = 0; d < 3; ++d ) 00178 { 00179 const double t = point_perp( coords, result.center, result.axes.col( d ) ); 00180 if( t < min[d] ) min[d] = t; 00181 if( t > max[d] ) max[d] = t; 00182 } 00183 } 00184 00185 // We now have a box defined by three orthogonal line segments 00186 // that intersect at the center of the box. Each line segment 00187 // is defined as result.center + t * result.axes[i], where the 00188 // range of t is [min[i], max[i]]. 00189 00190 // Calculate new center 00191 const CartVect mid = 0.5 * ( min + max ); 00192 result.center += mid[0] * result.axes.col( 0 ) + mid[1] * result.axes.col( 1 ) + mid[2] * result.axes.col( 2 ); 00193 00194 // reorder axes by length 00195 CartVect range = 0.5 * ( max - min ); 00196 if( range[2] < range[1] ) 00197 { 00198 if( range[2] < range[0] ) 00199 { 00200 std::swap( range[0], range[2] ); 00201 result.axes.swapcol( 0, 2 ); 00202 } 00203 } 00204 else if( range[1] < range[0] ) 00205 { 00206 std::swap( range[0], range[1] ); 00207 result.axes.swapcol( 0, 1 ); 00208 } 00209 if( range[1] > range[2] ) 00210 { 00211 std::swap( range[1], range[2] ); 00212 result.axes.swapcol( 1, 2 ); 00213 } 00214 00215 // scale axis to encompass all points, divide in half 00216 #if MB_ORIENTED_BOX_UNIT_VECTORS 00217 result.length = range; 00218 #else 00219 result.axes.colscale( 0, range[0] ); 00220 result.axes.colscale( 1, range[1] ); 00221 result.axes.colscale( 2, range[2] ); 00222 #endif 00223 00224 #if MB_ORIENTED_BOX_OUTER_RADIUS 00225 result.radius = range.length(); 00226 #endif 00227 00228 return MB_SUCCESS; 00229 } 00230 00231 ErrorCode OrientedBox::compute_from_vertices( OrientedBox& result, Interface* instance, const Range& vertices ) 00232 { 00233 const Range::iterator begin = vertices.lower_bound( MBVERTEX ); 00234 const Range::iterator end = vertices.upper_bound( MBVERTEX ); 00235 size_t count = 0; 00236 00237 // compute mean 00238 CartVect v; 00239 result.center = CartVect( 0, 0, 0 ); 00240 for( Range::iterator i = begin; i != end; ++i ) 00241 { 00242 ErrorCode rval = instance->get_coords( &*i, 1, v.array() ); 00243 if( MB_SUCCESS != rval ) return rval; 00244 result.center += v; 00245 ++count; 00246 } 00247 result.center /= count; 00248 00249 // compute covariance matrix 00250 Matrix3 a( 0.0 ); 00251 for( Range::iterator i = begin; i != end; ++i ) 00252 { 00253 ErrorCode rval = instance->get_coords( &*i, 1, v.array() ); 00254 if( MB_SUCCESS != rval ) return rval; 00255 00256 v -= result.center; 00257 a += outer_product( v, v ); 00258 } 00259 a /= count; 00260 00261 // Get axes (Eigenvectors) from covariance matrix 00262 CartVect lambda; 00263 a.eigen_decomposition( lambda, result.axes ); 00264 00265 // Calculate center and extents of box given orientation defined by axes 00266 return box_from_axes( result, instance, vertices ); 00267 } 00268 00269 ErrorCode OrientedBox::covariance_data_from_tris( CovarienceData& result, Interface* instance, const Range& elements ) 00270 { 00271 ErrorCode rval; 00272 const Range::iterator begin = elements.lower_bound( CN::TypeDimensionMap[2].first ); 00273 const Range::iterator end = elements.lower_bound( CN::TypeDimensionMap[3].first ); 00274 00275 // compute mean and moments 00276 result.matrix = Matrix3( 0.0 ); 00277 result.center = CartVect( 0.0 ); 00278 result.area = 0.0; 00279 for( Range::iterator i = begin; i != end; ++i ) 00280 { 00281 const EntityHandle* conn = NULL; 00282 int conn_len = 0; 00283 rval = instance->get_connectivity( *i, conn, conn_len ); 00284 if( MB_SUCCESS != rval ) return rval; 00285 00286 // for each triangle in the 2-D cell 00287 for( int j = 2; j < conn_len; ++j ) 00288 { 00289 EntityHandle vertices[3] = { conn[0], conn[j - 1], conn[j] }; 00290 CartVect coords[3]; 00291 rval = instance->get_coords( vertices, 3, coords[0].array() ); 00292 if( MB_SUCCESS != rval ) return rval; 00293 00294 // edge vectors 00295 const CartVect edge0 = coords[1] - coords[0]; 00296 const CartVect edge1 = coords[2] - coords[0]; 00297 const CartVect centroid = ( coords[0] + coords[1] + coords[2] ) / 3; 00298 const double tri_area2 = ( edge0 * edge1 ).length(); 00299 result.area += tri_area2; 00300 result.center += tri_area2 * centroid; 00301 00302 result.matrix += 00303 tri_area2 * ( 9 * outer_product( centroid, centroid ) + outer_product( coords[0], coords[0] ) + 00304 outer_product( coords[1], coords[1] ) + outer_product( coords[2], coords[2] ) ); 00305 } // for each triangle 00306 } // for each element 00307 00308 return MB_SUCCESS; 00309 } 00310 00311 ErrorCode OrientedBox::compute_from_2d_cells( OrientedBox& result, Interface* instance, const Range& elements ) 00312 { 00313 // Get orientation data from elements 00314 CovarienceData data; 00315 ErrorCode rval = covariance_data_from_tris( data, instance, elements ); 00316 if( MB_SUCCESS != rval ) return rval; 00317 00318 // get vertices from elements 00319 Range points; 00320 rval = instance->get_adjacencies( elements, 0, false, points, Interface::UNION ); 00321 if( MB_SUCCESS != rval ) return rval; 00322 00323 // Calculate box given points and orientation data 00324 return compute_from_covariance_data( result, instance, data, points ); 00325 } 00326 00327 ErrorCode OrientedBox::compute_from_covariance_data( OrientedBox& result, 00328 Interface* instance, 00329 CovarienceData& data, 00330 const Range& vertices ) 00331 { 00332 if( data.area <= 0.0 ) 00333 { 00334 Matrix3 empty_axes( 0.0 ); 00335 result = OrientedBox( empty_axes, CartVect( 0. ) ); 00336 return MB_SUCCESS; 00337 } 00338 00339 // get center from sum 00340 result.center = data.center / data.area; 00341 00342 // get covariance matrix from moments 00343 data.matrix /= 12 * data.area; 00344 data.matrix -= outer_product( result.center, result.center ); 00345 00346 // get axes (Eigenvectors) from covariance matrix 00347 CartVect lambda; 00348 data.matrix.eigen_decomposition( lambda, result.axes ); 00349 00350 // We now have only the axes. Calculate proper center 00351 // and extents for enclosed points. 00352 return box_from_axes( result, instance, vertices ); 00353 } 00354 00355 bool OrientedBox::contained( const CartVect& point, double tol ) const 00356 { 00357 CartVect from_center = point - center; 00358 #if MB_ORIENTED_BOX_UNIT_VECTORS 00359 return fabs( from_center % axes.col( 0 ) ) - length[0] <= tol && 00360 fabs( from_center % axes.col( 1 ) ) - length[1] <= tol && 00361 fabs( from_center % axes.col( 2 ) ) - length[2] <= tol; 00362 #else 00363 for( int i = 0; i < 3; ++i ) 00364 { 00365 double length = axes.col( i ).length(); 00366 if( fabs( from_center % axes.col( i ) ) - length * length > length * tol ) return false; 00367 } 00368 return true; 00369 #endif 00370 } 00371 00372 ErrorCode OrientedBox::compute_from_covariance_data( OrientedBox& result, 00373 Interface* moab_instance, 00374 const CovarienceData* data, 00375 unsigned data_length, 00376 const Range& vertices ) 00377 { 00378 // Sum input CovarienceData structures 00379 CovarienceData data_sum( Matrix3( 0.0 ), CartVect( 0.0 ), 0.0 ); 00380 for( const CovarienceData* const end = data + data_length; data != end; ++data ) 00381 { 00382 data_sum.matrix += data->matrix; 00383 data_sum.center += data->center; 00384 data_sum.area += data->area; 00385 } 00386 // Compute box from sum of structs 00387 return compute_from_covariance_data( result, moab_instance, data_sum, vertices ); 00388 } 00389 00390 // bool OrientedBox::contained( const OrientedBox& box, double tol ) const 00391 //{ 00392 // for (int i = -1; i < 2; i += 2) 00393 // { 00394 // for (int j = -1; j < 2; j += 2) 00395 // { 00396 // for (int k = -1; k < 2; k += 2) 00397 // { 00398 // CartVect corner( center ); 00399 //#ifdef MB_ORIENTED_BOX_UNIT_VECTORS 00400 // corner += i * box.length[0] * box.axis.col(0); 00401 // corner += j * box.length[1] * box.axis.col(1); 00402 // corner += k * box.length[2] * box.axis.col(2); 00403 //#else 00404 // corner += i * box.axis.col(0); 00405 // corner += j * box.axis.col(1); 00406 // corner += k * box.axis.col(2); 00407 //#endif 00408 // if (!contained( corner, tol )) 00409 // return false; 00410 // } 00411 // } 00412 // } 00413 // return true; 00414 //} 00415 00416 /* This is a helper function to check limits on ray length, turning the box-ray 00417 * intersection test into a box-segment intersection test. Use this to test the 00418 * limits against one side (plane) of the box. The side of the box (plane) is 00419 * normal to an axis. 00420 * 00421 * normal_par_pos Coordinate of particle's position along axis normal to side of box 00422 * normal_par_dir Coordinate of particle's direction along axis normal to side of box 00423 * half_extent Distance between center of box and side of box 00424 * nonneg_ray_len Maximum ray length in positive direction (in front of origin) 00425 * neg_ray_len Maximum ray length in negative direction (behind origin) 00426 * return true if intersection with plane occurs within distance limits 00427 * 00428 * ray equation: intersection = origin + dist*direction 00429 * plane equation: intersection.plane_normal = half_extent 00430 * 00431 * Assume plane_normal and direction are unit vectors. Combine equations. 00432 * 00433 * (origin + dist*direction).plane_normal = half_extent 00434 * origin.plane_normal + dist*direction.plane_normal = half_extent 00435 * dist = (half_extent - origin.plane_normal)/(direction.plane_normal) 00436 * 00437 * Although this solves for distance, avoid floating point division. 00438 * 00439 * dist*direction.plane_normal = half_extent - origin.plane_normal 00440 * 00441 * Use inequalities to test dist against ray length limits. Be aware that 00442 * inequalities change due to sign of direction.plane_normal. 00443 */ 00444 inline bool check_ray_limits( const double normal_par_pos, 00445 const double normal_par_dir, 00446 const double half_extent, 00447 const double* nonneg_ray_len, 00448 const double* neg_ray_len ) 00449 { 00450 00451 const double extent_pos_diff = half_extent - normal_par_pos; 00452 00453 // limit in positive direction 00454 if( nonneg_ray_len ) 00455 { // should be 0 <= t <= nonneg_ray_len 00456 assert( 0 <= *nonneg_ray_len ); 00457 if( normal_par_dir > 0 ) 00458 { // if/else if needed for pos/neg divisor 00459 if( *nonneg_ray_len * normal_par_dir >= extent_pos_diff && extent_pos_diff >= 0 ) return true; 00460 } 00461 else if( normal_par_dir < 0 ) 00462 { 00463 if( *nonneg_ray_len * normal_par_dir <= extent_pos_diff && extent_pos_diff <= 0 ) return true; 00464 } 00465 } 00466 else 00467 { // should be 0 <= t 00468 if( normal_par_dir > 0 ) 00469 { // if/else if needed for pos/neg divisor 00470 if( extent_pos_diff >= 0 ) return true; 00471 } 00472 else if( normal_par_dir < 0 ) 00473 { 00474 if( extent_pos_diff <= 0 ) return true; 00475 } 00476 } 00477 00478 // limit in negative direction 00479 if( neg_ray_len ) 00480 { // should be neg_ray_len <= t < 0 00481 assert( 0 >= *neg_ray_len ); 00482 if( normal_par_dir > 0 ) 00483 { // if/else if needed for pos/neg divisor 00484 if( *neg_ray_len * normal_par_dir <= extent_pos_diff && extent_pos_diff < 0 ) return true; 00485 } 00486 else if( normal_par_dir < 0 ) 00487 { 00488 if( *neg_ray_len * normal_par_dir >= extent_pos_diff && extent_pos_diff > 0 ) return true; 00489 } 00490 } 00491 00492 return false; 00493 } 00494 00495 /* This implementation copied from cgmMC (overlap.C). 00496 * Original author: Tim Tautges? 00497 */ 00498 bool OrientedBox::intersect_ray( const CartVect& ray_origin, 00499 const CartVect& ray_direction, 00500 const double reps, 00501 const double* nonneg_ray_len, 00502 const double* neg_ray_len ) const 00503 { 00504 // test distance from box center to line 00505 const CartVect cx = center - ray_origin; 00506 const double dist_s = cx % ray_direction; 00507 const double dist_sq = cx % cx - ( dist_s * dist_s ); 00508 const double max_diagsq = outer_radius_squared( reps ); 00509 00510 // For the largest sphere, no intersections exist if discriminant is negative. 00511 // Geometrically, if distance from box center to line is greater than the 00512 // longest diagonal, there is no intersection. 00513 // manipulate the discriminant: 0 > dist_s*dist_s - cx%cx + max_diagsq 00514 if( dist_sq > max_diagsq ) return false; 00515 00516 // If the closest possible intersection must be closer than nonneg_ray_len. Be 00517 // careful with absolute value, squaring distances, and subtracting squared 00518 // distances. 00519 if( nonneg_ray_len ) 00520 { 00521 assert( 0 <= *nonneg_ray_len ); 00522 double max_len; 00523 if( neg_ray_len ) 00524 { 00525 assert( 0 >= *neg_ray_len ); 00526 max_len = std::max( *nonneg_ray_len, -( *neg_ray_len ) ); 00527 } 00528 else 00529 { 00530 max_len = *nonneg_ray_len; 00531 } 00532 const double temp = fabs( dist_s ) - max_len; 00533 if( 0.0 < temp && temp * temp > max_diagsq ) return false; 00534 } 00535 00536 // if smaller than shortest diagonal, we do hit 00537 if( dist_sq < inner_radius_squared( reps ) ) 00538 { 00539 // nonnegative direction 00540 if( dist_s >= 0.0 ) 00541 { 00542 if( nonneg_ray_len ) 00543 { 00544 if( *nonneg_ray_len > dist_s ) return true; 00545 } 00546 else 00547 { 00548 return true; 00549 } 00550 // negative direction 00551 } 00552 else 00553 { 00554 if( neg_ray_len && *neg_ray_len < dist_s ) return true; 00555 } 00556 } 00557 00558 // get transpose of axes 00559 Matrix3 B = axes.transpose(); 00560 00561 // transform ray to box coordintae system 00562 CartVect par_pos = B * ( ray_origin - center ); 00563 CartVect par_dir = B * ray_direction; 00564 00565 // Fast Rejection Test: Ray will not intersect if it is going away from the box. 00566 // This will not work for rays with neg_ray_len. length[0] is half of box width 00567 // along axes.col(0). 00568 const double half_x = length[0] + reps; 00569 const double half_y = length[1] + reps; 00570 const double half_z = length[2] + reps; 00571 if( !neg_ray_len ) 00572 { 00573 if( ( par_pos[0] > half_x && par_dir[0] >= 0 ) || ( par_pos[0] < -half_x && par_dir[0] <= 0 ) ) return false; 00574 00575 if( ( par_pos[1] > half_y && par_dir[1] >= 0 ) || ( par_pos[1] < -half_y && par_dir[1] <= 0 ) ) return false; 00576 00577 if( ( par_pos[2] > half_z && par_dir[2] >= 0 ) || ( par_pos[2] < -half_z && par_dir[2] <= 0 ) ) return false; 00578 } 00579 00580 // test if ray_origin is inside box 00581 if( par_pos[0] <= half_x && par_pos[0] >= -half_x && par_pos[1] <= half_y && par_pos[1] >= -half_y && 00582 par_pos[2] <= half_z && par_pos[2] >= -half_z ) 00583 return true; 00584 00585 // test two xy plane 00586 if( fabs( par_dir[0] * ( half_z - par_pos[2] ) + par_dir[2] * par_pos[0] ) <= 00587 fabs( par_dir[2] * half_x ) && // test against x extents using z 00588 fabs( par_dir[1] * ( half_z - par_pos[2] ) + par_dir[2] * par_pos[1] ) <= 00589 fabs( par_dir[2] * half_y ) && // test against y extents using z 00590 check_ray_limits( par_pos[2], par_dir[2], half_z, nonneg_ray_len, neg_ray_len ) ) 00591 return true; 00592 if( fabs( par_dir[0] * ( -half_z - par_pos[2] ) + par_dir[2] * par_pos[0] ) <= fabs( par_dir[2] * half_x ) && 00593 fabs( par_dir[1] * ( -half_z - par_pos[2] ) + par_dir[2] * par_pos[1] ) <= fabs( par_dir[2] * half_y ) && 00594 check_ray_limits( par_pos[2], par_dir[2], -half_z, nonneg_ray_len, neg_ray_len ) ) 00595 return true; 00596 00597 // test two xz plane 00598 if( fabs( par_dir[0] * ( half_y - par_pos[1] ) + par_dir[1] * par_pos[0] ) <= fabs( par_dir[1] * half_x ) && 00599 fabs( par_dir[2] * ( half_y - par_pos[1] ) + par_dir[1] * par_pos[2] ) <= fabs( par_dir[1] * half_z ) && 00600 check_ray_limits( par_pos[1], par_dir[1], half_y, nonneg_ray_len, neg_ray_len ) ) 00601 return true; 00602 if( fabs( par_dir[0] * ( -half_y - par_pos[1] ) + par_dir[1] * par_pos[0] ) <= fabs( par_dir[1] * half_x ) && 00603 fabs( par_dir[2] * ( -half_y - par_pos[1] ) + par_dir[1] * par_pos[2] ) <= fabs( par_dir[1] * half_z ) && 00604 check_ray_limits( par_pos[1], par_dir[1], -half_y, nonneg_ray_len, neg_ray_len ) ) 00605 return true; 00606 00607 // test two yz plane 00608 if( fabs( par_dir[1] * ( half_x - par_pos[0] ) + par_dir[0] * par_pos[1] ) <= fabs( par_dir[0] * half_y ) && 00609 fabs( par_dir[2] * ( half_x - par_pos[0] ) + par_dir[0] * par_pos[2] ) <= fabs( par_dir[0] * half_z ) && 00610 check_ray_limits( par_pos[0], par_dir[0], half_x, nonneg_ray_len, neg_ray_len ) ) 00611 return true; 00612 if( fabs( par_dir[1] * ( -half_x - par_pos[0] ) + par_dir[0] * par_pos[1] ) <= fabs( par_dir[0] * half_y ) && 00613 fabs( par_dir[2] * ( -half_x - par_pos[0] ) + par_dir[0] * par_pos[2] ) <= fabs( par_dir[0] * half_z ) && 00614 check_ray_limits( par_pos[0], par_dir[0], -half_x, nonneg_ray_len, neg_ray_len ) ) 00615 return true; 00616 00617 return false; 00618 } 00619 00620 ErrorCode OrientedBox::make_hex( EntityHandle& hex, Interface* instance ) 00621 { 00622 ErrorCode rval; 00623 int signs[8][3] = { { -1, -1, -1 }, { 1, -1, -1 }, { 1, 1, -1 }, { -1, 1, -1 }, 00624 { -1, -1, 1 }, { 1, -1, 1 }, { 1, 1, 1 }, { -1, 1, 1 } }; 00625 00626 std::vector< EntityHandle > vertices; 00627 for( int i = 0; i < 8; ++i ) 00628 { 00629 CartVect coords( center ); 00630 for( int j = 0; j < 3; ++j ) 00631 { 00632 #if MB_ORIENTED_BOX_UNIT_VECTORS 00633 coords += signs[i][j] * ( axes.col( j ) * length[j] ); 00634 #else 00635 coords += signs[i][j] * axes.col( j ); 00636 #endif 00637 } 00638 EntityHandle handle; 00639 rval = instance->create_vertex( coords.array(), handle ); 00640 if( MB_SUCCESS != rval ) 00641 { 00642 instance->delete_entities( &vertices[0], vertices.size() ); 00643 return rval; 00644 } 00645 vertices.push_back( handle ); 00646 } 00647 00648 rval = instance->create_element( MBHEX, &vertices[0], vertices.size(), hex ); 00649 if( MB_SUCCESS != rval ) 00650 { 00651 instance->delete_entities( &vertices[0], vertices.size() ); 00652 return rval; 00653 } 00654 00655 return MB_SUCCESS; 00656 } 00657 00658 void OrientedBox::closest_location_in_box( const CartVect& input_position, CartVect& output_position ) const 00659 { 00660 // get coordinates on box axes 00661 const CartVect from_center = input_position - center; 00662 00663 #if MB_ORIENTED_BOX_UNIT_VECTORS 00664 CartVect local( from_center % axes.col( 0 ), from_center % axes.col( 1 ), from_center % axes.col( 2 ) ); 00665 00666 for( int i = 0; i < 3; ++i ) 00667 { 00668 if( local[i] < -length[i] ) 00669 local[i] = -length[i]; 00670 else if( local[i] > length[i] ) 00671 local[i] = length[i]; 00672 } 00673 #else 00674 CartVect local( ( from_center % axes.col( 0 ) ) / ( axes.col( 0 ) % axes.col( 0 ) ), 00675 ( from_center % axes.col( 1 ) ) / ( axes.col( 1 ) % axes.col( 1 ) ), 00676 ( from_center % axes.col( 2 ) ) / ( axes.col( 2 ) % axes.col( 2 ) ) ); 00677 00678 for( int i = 0; i < 3; ++i ) 00679 { 00680 if( local[i] < -1.0 ) 00681 local[i] = -1.0; 00682 else if( local[i] > 1.0 ) 00683 local[i] = 1.0; 00684 } 00685 #endif 00686 00687 output_position = center + local[0] * axes.col( 0 ) + local[1] * axes.col( 1 ) + local[2] * axes.col( 2 ); 00688 } 00689 00690 } // namespace moab