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 /*
17 * The algorithms for the calculation of the oriented box from a
18 * set of points or a set of cells was copied from the implementation
19 " in the "Visualization Toolkit". J.K. - 2006-07-19
20 *
21 * Program: Visualization Toolkit
22 * Module: $RCSfile$
23 *
24 * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
25 * All rights reserved.
26 * See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
27 */
28
29 /**\file OrientedBox.cpp
30 *\author Jason Kraftcheck (kraftche@cae.wisc.edu)
31 *\date 2006-07-18
32 */
33
34 #include "moab/Interface.hpp"
35 #include "moab/CN.hpp"
36 #include "moab/OrientedBox.hpp"
37 #include "moab/Range.hpp"
38 #include <ostream>
39 #include <assert.h>
40 #include <limits>
41
42 namespace moab {
43
operator <<(std::ostream & s,const OrientedBox & b)44 std::ostream& operator<<( std::ostream& s, const OrientedBox& b )
45 {
46 return s << b.center
47 << " + "
48 << b.axes.col(0)
49 #if MB_ORIENTED_BOX_UNIT_VECTORS
50 << ":" << b.length[0]
51 #endif
52 << " x "
53 << b.axes.col(1)
54 #if MB_ORIENTED_BOX_UNIT_VECTORS
55 << ":" << b.length[1]
56 #endif
57 << " x "
58 << b.axes.col(2)
59 #if MB_ORIENTED_BOX_UNIT_VECTORS
60 << ":" << b.length[2]
61 #endif
62 ;
63 }
64
65 /**\brief Find closest point on line
66 *
67 * Find the point on the line for which a line trough the
68 * input point \a p and the result position is orthogonal to
69 * the input line.
70 * \param p The point for which to find the perpendicular
71 * \param b A point on the line
72 * \param m The direction of the line
73 * \return The location on the line specified as 't' in the
74 * formula t * m + b
75 */
point_perp(const CartVect & p,const CartVect & b,const CartVect & m)76 static double point_perp( const CartVect& p, // closest to this point
77 const CartVect& b, // point on line
78 const CartVect& m ) // line direction
79 {
80 #if MB_ORIENTED_BOX_UNIT_VECTORS
81 double t = (m % (p - b));
82 #else
83 double t = (m % (p - b)) / (m % m);
84 #endif
85 return Util::is_finite(t) ? t : 0.0;
86 }
87
order_axes_by_length(double ax1_len,double ax2_len,double ax3_len)88 void OrientedBox::order_axes_by_length(double ax1_len, double ax2_len, double ax3_len)
89 {
90
91 CartVect len( ax1_len, ax2_len, ax3_len );
92
93 if (len[2] < len[1])
94 {
95 if (len[2] < len[0]) {
96 std::swap( len[0], len[2] );
97 axes.swapcol( 0, 2 );
98 }
99 }
100 else if (len[1] < len[0]) {
101 std::swap( len[0], len[1] );
102 axes.swapcol( 0, 1 );
103 }
104 if (len[1] > len[2]) {
105 std::swap( len[1], len[2] );
106 axes.swapcol( 1, 2 );
107 }
108
109 #if MB_ORIENTED_BOX_UNIT_VECTORS
110 length = len;
111 if (len[0] > 0.0)
112 axes.colscale(0, 1.0/len[0]);
113 if (len[1] > 0.0)
114 axes.colscale(1, 1.0/len[1]);
115 if (len[2] > 0.0)
116 axes.colscale(2 ,1.0/len[2]);
117 #endif
118
119 #if MB_ORIENTED_BOX_OUTER_RADIUS
120 radius = len.length();
121 #endif
122 }
123
OrientedBox(const CartVect axes_in[3],const CartVect & mid)124 OrientedBox::OrientedBox( const CartVect axes_in[3], const CartVect& mid )
125 : center(mid)
126 {
127
128 axes = Matrix3( axes_in[0], axes_in[1], axes_in[2], false );
129
130 order_axes_by_length( axes_in[0].length(),axes_in[1].length(),axes_in[2].length() );
131
132 }
133
OrientedBox(const Matrix3 & axes_mat,const CartVect & mid)134 OrientedBox::OrientedBox( const Matrix3& axes_mat, const CartVect& mid )
135 : center(mid), axes(axes_mat)
136 {
137 order_axes_by_length( axes.col(0).length(), axes.col(1).length(), axes.col(2).length() );
138 }
139
tag_handle(Tag & handle_out,Interface * instance,const char * name)140 ErrorCode OrientedBox::tag_handle( Tag& handle_out,
141 Interface* instance,
142 const char* name)
143 {
144 // We're going to assume this when mapping the OrientedBox
145 // to tag data, so assert it.
146 #if MB_ORIENTED_BOX_OUTER_RADIUS
147 const int rad_size = 1;
148 #else
149 const int rad_size = 0;
150 #endif
151 #if MB_ORIENTED_BOX_UNIT_VECTORS
152 const int SIZE = rad_size + 15;
153 #else
154 const int SIZE = rad_size + 12;
155 #endif
156 assert( sizeof(OrientedBox) == SIZE*sizeof(double) );
157
158 return instance->tag_get_handle( name, SIZE, MB_TYPE_DOUBLE,
159 handle_out, MB_TAG_DENSE|MB_TAG_CREAT );
160 }
161
162 /**\brief Common code for box calculation
163 *
164 * Given the orientation of the box and an approximate center,
165 * calculate the exact center and extents of the box.
166 *
167 *\param result.center As input, the approximate center of the box.
168 * As output, the exact center of the box.
169 *\param result.axes As input, directions of principal axes corresponding
170 * to the orientation of the box. Axes are assumed to
171 * be unit-length on input. Output will include extents
172 * of box.
173 *\param points The set of points the box should contain.
174 */
box_from_axes(OrientedBox & result,Interface * instance,const Range & points)175 static ErrorCode box_from_axes( OrientedBox& result,
176 Interface* instance,
177 const Range& points )
178 {
179 ErrorCode rval;
180
181 // project points onto axes to get box extents
182 CartVect min(std::numeric_limits<double>::max()),
183 max(-std::numeric_limits<double>::max());
184 for (Range::iterator i = points.begin(); i != points.end(); ++i)
185 {
186 CartVect coords;
187 rval = instance->get_coords( &*i, 1, coords.array() );MB_CHK_ERR(rval);
188
189 for (int d = 0; d < 3; ++d)
190 {
191 const double t = point_perp( coords, result.center, result.axes.col(d) );
192 if (t < min[d])
193 min[d] = t;
194 if (t > max[d])
195 max[d] = t;
196 }
197 }
198
199 // We now have a box defined by three orthogonal line segments
200 // that intersect at the center of the box. Each line segment
201 // is defined as result.center + t * result.axes[i], where the
202 // range of t is [min[i], max[i]].
203
204 // Calculate new center
205 const CartVect mid = 0.5 * (min + max);
206 result.center += mid[0] * result.axes.col(0) +
207 mid[1] * result.axes.col(1) +
208 mid[2] * result.axes.col(2);
209
210 // reorder axes by length
211 CartVect range = 0.5 * (max - min);
212 if (range[2] < range[1])
213 {
214 if (range[2] < range[0]) {
215 std::swap( range[0], range[2] );
216 result.axes.swapcol( 0, 2 );
217 }
218 }
219 else if (range[1] < range[0]) {
220 std::swap( range[0], range[1] );
221 result.axes.swapcol( 0, 1 );
222 }
223 if (range[1] > range[2]) {
224 std::swap( range[1], range[2] );
225 result.axes.swapcol( 1, 2 );
226 }
227
228 // scale axis to encompass all points, divide in half
229 #if MB_ORIENTED_BOX_UNIT_VECTORS
230 result.length = range;
231 #else
232 result.axes.colscale(0, range[0]);
233 result.axes.colscale(1, range[1]);
234 result.axes.colscale(2, range[2]);
235 #endif
236
237 #if MB_ORIENTED_BOX_OUTER_RADIUS
238 result.radius = range.length();
239 #endif
240
241 return MB_SUCCESS;
242 }
243
244
compute_from_vertices(OrientedBox & result,Interface * instance,const Range & vertices)245 ErrorCode OrientedBox::compute_from_vertices( OrientedBox& result,
246 Interface* instance,
247 const Range& vertices )
248 {
249 const Range::iterator begin = vertices.lower_bound( MBVERTEX );
250 const Range::iterator end = vertices.upper_bound( MBVERTEX );
251 size_t count = 0;
252
253 // compute mean
254 CartVect v;
255 result.center = CartVect( 0, 0, 0 );
256 for (Range::iterator i = begin; i != end; ++i)
257 {
258 ErrorCode rval = instance->get_coords( &*i, 1, v.array() );
259 if (MB_SUCCESS != rval)
260 return rval;
261 result.center += v;
262 ++count;
263 }
264 result.center /= count;
265
266 // compute covariance matrix
267 Matrix3 a( 0.0 );
268 for (Range::iterator i = begin; i != end; ++i)
269 {
270 ErrorCode rval = instance->get_coords( &*i, 1, v.array() );
271 if (MB_SUCCESS != rval)
272 return rval;
273
274 v -= result.center;
275 a += outer_product( v, v );
276 }
277 a /= count;
278
279 // Get axes (Eigenvectors) from covariance matrix
280 CartVect lambda;
281 a.eigen_decomposition(lambda, result.axes);
282
283 // Calculate center and extents of box given orientation defined by axes
284 return box_from_axes( result, instance, vertices );
285 }
286
covariance_data_from_tris(CovarienceData & result,Interface * instance,const Range & elements)287 ErrorCode OrientedBox::covariance_data_from_tris( CovarienceData& result,
288 Interface* instance,
289 const Range& elements )
290 {
291 ErrorCode rval;
292 const Range::iterator begin = elements.lower_bound( CN::TypeDimensionMap[2].first );
293 const Range::iterator end = elements.lower_bound( CN::TypeDimensionMap[3].first );
294
295 // compute mean and moments
296 result.matrix = Matrix3(0.0);
297 result.center = CartVect(0.0);
298 result.area = 0.0;
299 for (Range::iterator i = begin; i != end; ++i)
300 {
301 const EntityHandle* conn = NULL;
302 int conn_len = 0;
303 rval = instance->get_connectivity( *i, conn, conn_len );
304 if (MB_SUCCESS != rval)
305 return rval;
306
307 // for each triangle in the 2-D cell
308 for (int j = 2; j < conn_len; ++j)
309 {
310 EntityHandle vertices[3] = { conn[0], conn[j-1], conn[j] };
311 CartVect coords[3];
312 rval = instance->get_coords( vertices, 3, coords[0].array() );
313 if (MB_SUCCESS != rval)
314 return rval;
315
316 // edge vectors
317 const CartVect edge0 = coords[1] - coords[0];
318 const CartVect edge1 = coords[2] - coords[0];
319 const CartVect centroid = (coords[0] + coords[1] + coords[2]) / 3;
320 const double tri_area2 = (edge0 * edge1).length();
321 result.area += tri_area2;
322 result.center += tri_area2 * centroid;
323
324 result.matrix += tri_area2 * (9 * outer_product( centroid, centroid ) +
325 outer_product( coords[0], coords[0] ) +
326 outer_product( coords[1], coords[1] ) +
327 outer_product( coords[2], coords[2] ));
328 } // for each triangle
329 } // for each element
330
331 return MB_SUCCESS;
332 }
333
334
compute_from_2d_cells(OrientedBox & result,Interface * instance,const Range & elements)335 ErrorCode OrientedBox::compute_from_2d_cells( OrientedBox& result,
336 Interface* instance,
337 const Range& elements )
338 {
339 // Get orientation data from elements
340 CovarienceData data;
341 ErrorCode rval = covariance_data_from_tris( data, instance, elements );
342 if (MB_SUCCESS != rval)
343 return rval;
344
345 // get vertices from elements
346 Range points;
347 rval = instance->get_adjacencies( elements, 0, false, points, Interface::UNION );
348 if (MB_SUCCESS != rval)
349 return rval;
350
351 // Calculate box given points and orientation data
352 return compute_from_covariance_data( result, instance, data, points );
353 }
354
compute_from_covariance_data(OrientedBox & result,Interface * instance,CovarienceData & data,const Range & vertices)355 ErrorCode OrientedBox::compute_from_covariance_data(
356 OrientedBox& result,
357 Interface* instance,
358 CovarienceData& data,
359 const Range& vertices )
360 {
361 if (data.area <= 0.0) {
362 Matrix3 empty_axes (0.0);
363 result = OrientedBox( empty_axes, CartVect(0.) );
364 return MB_SUCCESS;
365 }
366
367 // get center from sum
368 result.center = data.center / data.area;
369
370 // get covariance matrix from moments
371 data.matrix /= 12 * data.area;
372 data.matrix -= outer_product( result.center, result.center );
373
374 // get axes (Eigenvectors) from covariance matrix
375 CartVect lambda;
376 data.matrix.eigen_decomposition(lambda, result.axes);
377
378 // We now have only the axes. Calculate proper center
379 // and extents for enclosed points.
380 return box_from_axes( result, instance, vertices );
381 }
382
contained(const CartVect & point,double tol) const383 bool OrientedBox::contained( const CartVect& point, double tol ) const
384 {
385 CartVect from_center = point - center;
386 #if MB_ORIENTED_BOX_UNIT_VECTORS
387 return fabs(from_center % axes.col(0)) - length[0] <= tol &&
388 fabs(from_center % axes.col(1)) - length[1] <= tol &&
389 fabs(from_center % axes.col(2)) - length[2] <= tol ;
390 #else
391 for (int i = 0; i < 3; ++i) {
392 double length = axes.col(i).length();
393 if (fabs(from_center % axes.col(i)) - length*length > length*tol)
394 return false;
395 }
396 return true;
397 #endif
398 }
399
compute_from_covariance_data(OrientedBox & result,Interface * moab_instance,const CovarienceData * data,unsigned data_length,const Range & vertices)400 ErrorCode OrientedBox::compute_from_covariance_data( OrientedBox& result,
401 Interface* moab_instance,
402 const CovarienceData* data,
403 unsigned data_length,
404 const Range& vertices )
405 {
406 // Sum input CovarienceData structures
407 CovarienceData data_sum( Matrix3(0.0), CartVect(0.0), 0.0 );
408 for (const CovarienceData* const end = data+data_length; data != end; ++data) {
409 data_sum.matrix += data->matrix;
410 data_sum.center += data->center;
411 data_sum.area += data->area;
412 }
413 // Compute box from sum of structs
414 return compute_from_covariance_data( result, moab_instance, data_sum, vertices );
415 }
416
417
418
419 //bool OrientedBox::contained( const OrientedBox& box, double tol ) const
420 //{
421 // for (int i = -1; i < 2; i += 2)
422 // {
423 // for (int j = -1; j < 2; j += 2)
424 // {
425 // for (int k = -1; k < 2; k += 2)
426 // {
427 // CartVect corner( center );
428 //#ifdef MB_ORIENTED_BOX_UNIT_VECTORS
429 // corner += i * box.length[0] * box.axis.col(0);
430 // corner += j * box.length[1] * box.axis.col(1);
431 // corner += k * box.length[2] * box.axis.col(2);
432 //#else
433 // corner += i * box.axis.col(0);
434 // corner += j * box.axis.col(1);
435 // corner += k * box.axis.col(2);
436 //#endif
437 // if (!contained( corner, tol ))
438 // return false;
439 // }
440 // }
441 // }
442 // return true;
443 //}
444
445
446 /* This is a helper function to check limits on ray length, turning the box-ray
447 * intersection test into a box-segment intersection test. Use this to test the
448 * limits against one side (plane) of the box. The side of the box (plane) is
449 * normal to an axis.
450 *
451 * normal_par_pos Coordinate of particle's position along axis normal to side of box
452 * normal_par_dir Coordinate of particle's direction along axis normal to side of box
453 * half_extent Distance between center of box and side of box
454 * nonneg_ray_len Maximum ray length in positive direction (in front of origin)
455 * neg_ray_len Maximum ray length in negative direction (behind origin)
456 * return true if intersection with plane occurs within distance limits
457 *
458 * ray equation: intersection = origin + dist*direction
459 * plane equation: intersection.plane_normal = half_extent
460 *
461 * Assume plane_normal and direction are unit vectors. Combine equations.
462 *
463 * (origin + dist*direction).plane_normal = half_extent
464 * origin.plane_normal + dist*direction.plane_normal = half_extent
465 * dist = (half_extent - origin.plane_normal)/(direction.plane_normal)
466 *
467 * Although this solves for distance, avoid floating point division.
468 *
469 * dist*direction.plane_normal = half_extent - origin.plane_normal
470 *
471 * Use inequalities to test dist against ray length limits. Be aware that
472 * inequalities change due to sign of direction.plane_normal.
473 */
check_ray_limits(const double normal_par_pos,const double normal_par_dir,const double half_extent,const double * nonneg_ray_len,const double * neg_ray_len)474 inline bool check_ray_limits(const double normal_par_pos,
475 const double normal_par_dir,
476 const double half_extent,
477 const double* nonneg_ray_len,
478 const double* neg_ray_len ) {
479
480 const double extent_pos_diff = half_extent - normal_par_pos;
481
482 // limit in positive direction
483 if(nonneg_ray_len) { // should be 0 <= t <= nonneg_ray_len
484 assert(0 <= *nonneg_ray_len);
485 if (normal_par_dir>0) { // if/else if needed for pos/neg divisor
486 if(*nonneg_ray_len*normal_par_dir>=extent_pos_diff && extent_pos_diff>=0) return true;
487 } else if(normal_par_dir<0) {
488 if(*nonneg_ray_len*normal_par_dir<=extent_pos_diff && extent_pos_diff<=0) return true;
489 }
490 } else { // should be 0 <= t
491 if (normal_par_dir>0) { // if/else if needed for pos/neg divisor
492 if(extent_pos_diff>=0) return true;
493 } else if(normal_par_dir<0) {
494 if(extent_pos_diff<=0) return true;
495 }
496 }
497
498 // limit in negative direction
499 if(neg_ray_len) { // should be neg_ray_len <= t < 0
500 assert(0 >= *neg_ray_len);
501 if (normal_par_dir>0) { // if/else if needed for pos/neg divisor
502 if(*neg_ray_len*normal_par_dir<=extent_pos_diff && extent_pos_diff<0) return true;
503 } else if(normal_par_dir<0) {
504 if(*neg_ray_len*normal_par_dir>=extent_pos_diff && extent_pos_diff>0) return true;
505 }
506 }
507
508 return false;
509 }
510
511 /* This implementation copied from cgmMC (overlap.C).
512 * Original author: Tim Tautges?
513 */
intersect_ray(const CartVect & ray_origin,const CartVect & ray_direction,const double reps,const double * nonneg_ray_len,const double * neg_ray_len) const514 bool OrientedBox::intersect_ray( const CartVect& ray_origin,
515 const CartVect& ray_direction,
516 const double reps,
517 const double* nonneg_ray_len,
518 const double* neg_ray_len ) const
519 {
520 // test distance from box center to line
521 const CartVect cx = center - ray_origin;
522 const double dist_s = cx % ray_direction;
523 const double dist_sq = cx % cx - (dist_s*dist_s);
524 const double max_diagsq = outer_radius_squared(reps);
525
526 // For the largest sphere, no intersections exist if discriminant is negative.
527 // Geometrically, if distance from box center to line is greater than the
528 // longest diagonal, there is no intersection.
529 // manipulate the discriminant: 0 > dist_s*dist_s - cx%cx + max_diagsq
530 if(dist_sq > max_diagsq) return false;
531
532 // If the closest possible intersection must be closer than nonneg_ray_len. Be
533 // careful with absolute value, squaring distances, and subtracting squared
534 // distances.
535 if (nonneg_ray_len) {
536 assert(0<=*nonneg_ray_len);
537 double max_len;
538 if(neg_ray_len) {
539 assert(0>=*neg_ray_len);
540 max_len = std::max(*nonneg_ray_len,-(*neg_ray_len));
541 } else {
542 max_len = *nonneg_ray_len;
543 }
544 const double temp = fabs(dist_s) - max_len;
545 if(0.0<temp && temp*temp>max_diagsq) return false;
546 }
547
548 // if smaller than shortest diagonal, we do hit
549 if (dist_sq < inner_radius_squared(reps)) {
550 // nonnegative direction
551 if(dist_s>=0.0 ) {
552 if(nonneg_ray_len) {
553 if(*nonneg_ray_len>dist_s) return true;
554 } else {
555 return true;
556 }
557 // negative direction
558 } else {
559 if(neg_ray_len && *neg_ray_len<dist_s) return true;
560 }
561 }
562
563 // get transpose of axes
564 Matrix3 B = axes.transpose();
565
566 // transform ray to box coordintae system
567 CartVect par_pos = B * (ray_origin - center);
568 CartVect par_dir = B * ray_direction;
569
570 // Fast Rejection Test: Ray will not intersect if it is going away from the box.
571 // This will not work for rays with neg_ray_len. length[0] is half of box width
572 // along axes.col(0).
573 const double half_x = length[0] + reps;
574 const double half_y = length[1] + reps;
575 const double half_z = length[2] + reps;
576 if(!neg_ray_len) {
577 if ((par_pos[0] > half_x && par_dir[0] >= 0) ||
578 (par_pos[0] < -half_x && par_dir[0] <= 0))
579 return false;
580
581 if ((par_pos[1] > half_y && par_dir[1] >= 0) ||
582 (par_pos[1] < -half_y && par_dir[1] <= 0))
583 return false;
584
585 if ((par_pos[2] > half_z && par_dir[2] >= 0) ||
586 (par_pos[2] < -half_z && par_dir[2] <= 0))
587 return false;
588 }
589
590 // test if ray_origin is inside box
591 if (par_pos[0] <= half_x && par_pos[0] >= -half_x &&
592 par_pos[1] <= half_y && par_pos[1] >= -half_y &&
593 par_pos[2] <= half_z && par_pos[2] >= -half_z)
594 return true;
595
596 //test two xy plane
597 if (fabs(par_dir[0] * (half_z - par_pos[2]) + par_dir[2] * par_pos[0])
598 <= fabs(par_dir[2] * half_x) && // test against x extents using z
599 fabs(par_dir[1] * (half_z - par_pos[2]) + par_dir[2] * par_pos[1])
600 <= fabs(par_dir[2] * half_y) && // test against y extents using z
601 check_ray_limits( par_pos[2], par_dir[2], half_z, nonneg_ray_len, neg_ray_len ) )
602 return true;
603 if (fabs(par_dir[0] * (-half_z - par_pos[2]) + par_dir[2] * par_pos[0])
604 <= fabs(par_dir[2] * half_x) &&
605 fabs(par_dir[1] * (-half_z - par_pos[2]) + par_dir[2] * par_pos[1])
606 <= fabs(par_dir[2] * half_y) &&
607 check_ray_limits( par_pos[2], par_dir[2], -half_z, nonneg_ray_len, neg_ray_len ) )
608 return true;
609
610 //test two xz plane
611 if (fabs(par_dir[0] * (half_y - par_pos[1]) + par_dir[1] * par_pos[0])
612 <= fabs(par_dir[1] * half_x) &&
613 fabs(par_dir[2] * (half_y - par_pos[1]) + par_dir[1] * par_pos[2])
614 <= fabs(par_dir[1] * half_z) &&
615 check_ray_limits( par_pos[1], par_dir[1], half_y, nonneg_ray_len, neg_ray_len ) )
616 return true;
617 if (fabs(par_dir[0] * (-half_y - par_pos[1]) + par_dir[1] * par_pos[0])
618 <= fabs(par_dir[1] * half_x) &&
619 fabs(par_dir[2] * (-half_y - par_pos[1]) + par_dir[1] * par_pos[2])
620 <= fabs(par_dir[1] * half_z) &&
621 check_ray_limits( par_pos[1], par_dir[1], -half_y, nonneg_ray_len, neg_ray_len ) )
622 return true;
623
624 //test two yz plane
625 if (fabs(par_dir[1] * (half_x - par_pos[0]) + par_dir[0] * par_pos[1])
626 <= fabs(par_dir[0] * half_y) &&
627 fabs(par_dir[2] * (half_x - par_pos[0]) + par_dir[0] * par_pos[2])
628 <= fabs(par_dir[0] * half_z) &&
629 check_ray_limits( par_pos[0], par_dir[0], half_x, nonneg_ray_len, neg_ray_len ) )
630 return true;
631 if (fabs(par_dir[1] * (-half_x - par_pos[0]) + par_dir[0] * par_pos[1])
632 <= fabs(par_dir[0] * half_y) &&
633 fabs(par_dir[2] * (-half_x - par_pos[0]) + par_dir[0] * par_pos[2])
634 <= fabs(par_dir[0] * half_z) &&
635 check_ray_limits( par_pos[0], par_dir[0], -half_x, nonneg_ray_len, neg_ray_len ) )
636 return true;
637
638 return false;
639 }
640
make_hex(EntityHandle & hex,Interface * instance)641 ErrorCode OrientedBox::make_hex( EntityHandle& hex, Interface* instance )
642 {
643 ErrorCode rval;
644 int signs[8][3] = { { -1, -1, -1 },
645 { 1, -1, -1 },
646 { 1, 1, -1 },
647 { -1, 1, -1 },
648 { -1, -1, 1 },
649 { 1, -1, 1 },
650 { 1, 1, 1 },
651 { -1, 1, 1 } };
652
653 std::vector<EntityHandle> vertices;
654 for (int i = 0; i < 8; ++i)
655 {
656 CartVect coords(center);
657 for (int j = 0; j < 3; ++j){
658 #if MB_ORIENTED_BOX_UNIT_VECTORS
659 coords += signs[i][j] * (axes.col(j)*length[j]);
660 #else
661 coords += signs[i][j] * axes.col(j);
662 #endif
663 }
664 EntityHandle handle;
665 rval = instance->create_vertex( coords.array(), handle );
666 if (MB_SUCCESS != rval) {
667 instance->delete_entities( &vertices[0], vertices.size() );
668 return rval;
669 }
670 vertices.push_back( handle );
671 }
672
673 rval = instance->create_element( MBHEX, &vertices[0], vertices.size(), hex );
674 if (MB_SUCCESS != rval) {
675 instance->delete_entities( &vertices[0], vertices.size() );
676 return rval;
677 }
678
679 return MB_SUCCESS;
680 }
681
closest_location_in_box(const CartVect & input_position,CartVect & output_position) const682 void OrientedBox::closest_location_in_box(
683 const CartVect& input_position,
684 CartVect& output_position ) const
685 {
686 // get coordinates on box axes
687 const CartVect from_center = input_position - center;
688
689 #if MB_ORIENTED_BOX_UNIT_VECTORS
690 CartVect local( from_center % axes.col(0),
691 from_center % axes.col(1),
692 from_center % axes.col(2) );
693
694 for (int i = 0; i < 3; ++i) {
695 if (local[i] < -length[i])
696 local[i] = -length[i];
697 else if (local[i] > length[i])
698 local[i] = length[i];
699 }
700 #else
701 CartVect local( (from_center % axes.col(0)) / (axes.col(0) % axes.col(0)),
702 (from_center % axes.col(1)) / (axes.col(1) % axes.col(1)),
703 (from_center % axes.col(2)) / (axes.col(2) % axes.col(2)) );
704
705 for (int i = 0; i < 3; ++i) {
706 if (local[i] < -1.0)
707 local[i] = -1.0;
708 else if (local[i] > 1.0)
709 local[i] = 1.0;
710 }
711 #endif
712
713 output_position = center
714 + local[0] * axes.col(0)
715 + local[1] * axes.col(1)
716 + local[2] * axes.col(2);
717 }
718
719 } // namespace moab
720