![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
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 (kraftche@cae.wisc.edu)
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
00039 #include
00040 #include
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