Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
GeomUtil.cpp
Go to the documentation of this file.
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 Geometry.cpp
17  *\author Jason Kraftcheck ([email protected])
18  *\date 2006-07-27
19  */
20 
21 #include "moab/CartVect.hpp"
22 #include "moab/CN.hpp"
23 #include "moab/GeomUtil.hpp"
24 #include "moab/Matrix3.hpp"
25 #include "moab/Util.hpp"
26 #include <cmath>
27 #include <algorithm>
28 #include <cassert>
29 #include <iostream>
30 #include <limits>
31 
32 namespace moab
33 {
34 
35 namespace GeomUtil
36 {
37 
38  static inline void min_max_3( double a, double b, double c, double& min, double& max )
39  {
40  if( a < b )
41  {
42  if( a < c )
43  {
44  min = a;
45  max = b > c ? b : c;
46  }
47  else
48  {
49  min = c;
50  max = b;
51  }
52  }
53  else if( b < c )
54  {
55  min = b;
56  max = a > c ? a : c;
57  }
58  else
59  {
60  min = c;
61  max = a;
62  }
63  }
64 
65  static inline double dot_abs( const CartVect& u, const CartVect& v )
66  {
67  return fabs( u[0] * v[0] ) + fabs( u[1] * v[1] ) + fabs( u[2] * v[2] );
68  }
69 
72  const CartVect& seg_pt,
73  const CartVect& seg_unit_dir,
74  double& seg_start,
75  double& seg_end )
76  {
77  // translate so that seg_pt is at origin
78  box_min -= seg_pt;
79  box_max -= seg_pt;
80 
81  for( unsigned i = 0; i < 3; ++i )
82  { // X, Y, and Z slabs
83 
84  // intersect line with slab planes
85  const double t_min = box_min[i] / seg_unit_dir[i];
86  const double t_max = box_max[i] / seg_unit_dir[i];
87 
88  // check if line is parallel to planes
89  if( !Util::is_finite( t_min ) )
90  {
91  if( box_min[i] > 0.0 || box_max[i] < 0.0 ) return false;
92  continue;
93  }
94 
95  if( seg_unit_dir[i] < 0 )
96  {
97  if( t_min < seg_end ) seg_end = t_min;
98  if( t_max > seg_start ) seg_start = t_max;
99  }
100  else
101  { // seg_unit_dir[i] > 0
102  if( t_min > seg_start ) seg_start = t_min;
103  if( t_max < seg_end ) seg_end = t_max;
104  }
105  }
106 
107  return seg_start <= seg_end;
108  }
109 
110  /* Function to return the vertex with the lowest coordinates. To force the same
111  ray-edge computation, the Plücker test needs to use consistent edge
112  representation. This would be more simple with MOAB handles instead of
113  coordinates... */
114  inline bool first( const CartVect& a, const CartVect& b )
115  {
116  if( a[0] < b[0] )
117  {
118  return true;
119  }
120  else if( a[0] == b[0] )
121  {
122  if( a[1] < b[1] )
123  {
124  return true;
125  }
126  else if( a[1] == b[1] )
127  {
128  if( a[2] < b[2] )
129  {
130  return true;
131  }
132  else
133  {
134  return false;
135  }
136  }
137  else
138  {
139  return false;
140  }
141  }
142  else
143  {
144  return false;
145  }
146  }
147 
148  double plucker_edge_test( const CartVect& vertexa,
149  const CartVect& vertexb,
150  const CartVect& ray,
151  const CartVect& ray_normal )
152  {
153 
154  double pip;
155  const double near_zero = 10 * std::numeric_limits< double >::epsilon();
156 
157  if( first( vertexa, vertexb ) )
158  {
159  const CartVect edge = vertexb - vertexa;
160  const CartVect edge_normal = edge * vertexa;
161  pip = ray % edge_normal + ray_normal % edge;
162  }
163  else
164  {
165  const CartVect edge = vertexa - vertexb;
166  const CartVect edge_normal = edge * vertexb;
167  pip = ray % edge_normal + ray_normal % edge;
168  pip = -pip;
169  }
170 
171  if( near_zero > fabs( pip ) ) pip = 0.0;
172 
173  return pip;
174  }
175 
176 #define EXIT_EARLY \
177  if( type ) *type = NONE; \
178  return false;
179 
180  /* This test uses the same edge-ray computation for adjacent triangles so that
181  rays passing close to edges/nodes are handled consistently.
182 
183  Reports intersection type for post processing of special cases. Optionally
184  screen by orientation and negative/nonnegative distance limits.
185 
186  If screening by orientation, substantial pruning can occur. Indicate
187  desired orientation by passing 1 (forward), -1 (reverse), or 0 (no preference).
188  Note that triangle orientation is not always the same as surface
189  orientation due to non-manifold surfaces.
190 
191  N. Platis and T. Theoharis, "Fast Ray-Tetrahedron Intersection using Plücker
192  Coordinates", Journal of Graphics Tools, Vol. 8, Part 4, Pages 37-48 (2003). */
193  bool plucker_ray_tri_intersect( const CartVect vertices[3],
194  const CartVect& origin,
195  const CartVect& direction,
196  double& dist_out,
197  const double* nonneg_ray_len,
198  const double* neg_ray_len,
199  const int* orientation,
200  intersection_type* type )
201  {
202 
203  const CartVect raya = direction;
204  const CartVect rayb = direction * origin;
205 
206  // Determine the value of the first Plucker coordinate from edge 0
207  double plucker_coord0 = plucker_edge_test( vertices[0], vertices[1], raya, rayb );
208 
209  // If orientation is set, confirm that sign of plucker_coordinate indicate
210  // correct orientation of intersection
211  if( orientation && ( *orientation ) * plucker_coord0 > 0 )
212  {
213  EXIT_EARLY
214  }
215 
216  // Determine the value of the second Plucker coordinate from edge 1
217  double plucker_coord1 = plucker_edge_test( vertices[1], vertices[2], raya, rayb );
218 
219  // If orientation is set, confirm that sign of plucker_coordinate indicate
220  // correct orientation of intersection
221  if( orientation )
222  {
223  if( ( *orientation ) * plucker_coord1 > 0 )
224  {
225  EXIT_EARLY
226  }
227  // If the orientation is not specified, all plucker_coords must be the same sign or
228  // zero.
229  }
230  else if( ( 0.0 < plucker_coord0 && 0.0 > plucker_coord1 ) || ( 0.0 > plucker_coord0 && 0.0 < plucker_coord1 ) )
231  {
232  EXIT_EARLY
233  }
234 
235  // Determine the value of the second Plucker coordinate from edge 2
236  double plucker_coord2 = plucker_edge_test( vertices[2], vertices[0], raya, rayb );
237 
238  // If orientation is set, confirm that sign of plucker_coordinate indicate
239  // correct orientation of intersection
240  if( orientation )
241  {
242  if( ( *orientation ) * plucker_coord2 > 0 )
243  {
244  EXIT_EARLY
245  }
246  // If the orientation is not specified, all plucker_coords must be the same sign or
247  // zero.
248  }
249  else if( ( 0.0 < plucker_coord1 && 0.0 > plucker_coord2 ) || ( 0.0 > plucker_coord1 && 0.0 < plucker_coord2 ) ||
250  ( 0.0 < plucker_coord0 && 0.0 > plucker_coord2 ) || ( 0.0 > plucker_coord0 && 0.0 < plucker_coord2 ) )
251  {
252  EXIT_EARLY
253  }
254 
255  // check for coplanar case to avoid dividing by zero
256  if( 0.0 == plucker_coord0 && 0.0 == plucker_coord1 && 0.0 == plucker_coord2 )
257  {
258  EXIT_EARLY
259  }
260 
261  // get the distance to intersection
262  const double inverse_sum = 1.0 / ( plucker_coord0 + plucker_coord1 + plucker_coord2 );
263  assert( 0.0 != inverse_sum );
264  const CartVect intersection( plucker_coord0 * inverse_sum * vertices[2] +
265  plucker_coord1 * inverse_sum * vertices[0] +
266  plucker_coord2 * inverse_sum * vertices[1] );
267 
268  // To minimize numerical error, get index of largest magnitude direction.
269  int idx = 0;
270  double max_abs_dir = 0;
271  for( unsigned int i = 0; i < 3; ++i )
272  {
273  if( fabs( direction[i] ) > max_abs_dir )
274  {
275  idx = i;
276  max_abs_dir = fabs( direction[i] );
277  }
278  }
279  const double dist = ( intersection[idx] - origin[idx] ) / direction[idx];
280 
281  // is the intersection within distance limits?
282  if( ( nonneg_ray_len && *nonneg_ray_len < dist ) || // intersection is beyond positive limit
283  ( neg_ray_len && *neg_ray_len >= dist ) || // intersection is behind negative limit
284  ( !neg_ray_len && 0 > dist ) )
285  { // Unless a neg_ray_len is used, don't return negative distances
286  EXIT_EARLY
287  }
288 
289  dist_out = dist;
290 
291  if( type )
292  *type = type_list[( ( 0.0 == plucker_coord2 ) << 2 ) + ( ( 0.0 == plucker_coord1 ) << 1 ) +
293  ( 0.0 == plucker_coord0 )];
294 
295  return true;
296  }
297 
298  /* Implementation copied from cgmMC ray_tri_contact (overlap.C) */
299  bool ray_tri_intersect( const CartVect vertices[3],
300  const CartVect& b,
301  const CartVect& v,
302  double& t_out,
303  const double* ray_length )
304  {
305  const CartVect p0 = vertices[0] - vertices[1]; // abc
306  const CartVect p1 = vertices[0] - vertices[2]; // def
307  // ghi<-v
308  const CartVect p = vertices[0] - b; // jkl
309  const CartVect c = p1 * v; // eiMinushf,gfMinusdi,dhMinuseg
310  const double mP = p0 % c;
311  const double betaP = p % c;
312  if( mP > 0 )
313  {
314  if( betaP < 0 ) return false;
315  }
316  else if( mP < 0 )
317  {
318  if( betaP > 0 ) return false;
319  }
320  else
321  {
322  return false;
323  }
324 
325  const CartVect d = p0 * p; // jcMinusal,blMinuskc,akMinusjb
326  double gammaP = v % d;
327  if( mP > 0 )
328  {
329  if( gammaP < 0 || betaP + gammaP > mP ) return false;
330  }
331  else if( betaP + gammaP < mP || gammaP > 0 )
332  return false;
333 
334  const double tP = p1 % d;
335  const double m = 1.0 / mP;
336  const double beta = betaP * m;
337  const double gamma = gammaP * m;
338  const double t = -tP * m;
339  if( ray_length && t > *ray_length ) return false;
340 
341  if( beta < 0 || gamma < 0 || beta + gamma > 1 || t < 0.0 ) return false;
342 
343  t_out = t;
344  return true;
345  }
346 
348  const CartVect& box_max,
349  const CartVect& ray_pt,
350  const CartVect& ray_dir,
351  double& t_enter,
352  double& t_exit )
353  {
354  const double epsilon = 1e-12;
355  double t1, t2;
356 
357  // Use 'slabs' method from 13.6.1 of Akenine-Moller
358  t_enter = 0.0;
359  t_exit = std::numeric_limits< double >::infinity();
360 
361  // Intersect with each pair of axis-aligned planes bounding
362  // opposite faces of the leaf box
363  bool ray_is_valid = false; // is ray direction vector zero?
364  for( int axis = 0; axis < 3; ++axis )
365  {
366  if( fabs( ray_dir[axis] ) < epsilon )
367  { // ray parallel to planes
368  if( ray_pt[axis] >= box_min[axis] && ray_pt[axis] <= box_max[axis] )
369  continue;
370  else
371  return false;
372  }
373 
374  // find t values at which ray intersects each plane
375  ray_is_valid = true;
376  t1 = ( box_min[axis] - ray_pt[axis] ) / ray_dir[axis];
377  t2 = ( box_max[axis] - ray_pt[axis] ) / ray_dir[axis];
378 
379  // t_enter = max( t_enter_x, t_enter_y, t_enter_z )
380  // t_exit = min( t_exit_x, t_exit_y, t_exit_z )
381  // where
382  // t_enter_x = min( t1_x, t2_x );
383  // t_exit_x = max( t1_x, t2_x )
384  if( t1 < t2 )
385  {
386  if( t_enter < t1 ) t_enter = t1;
387  if( t_exit > t2 ) t_exit = t2;
388  }
389  else
390  {
391  if( t_enter < t2 ) t_enter = t2;
392  if( t_exit > t1 ) t_exit = t1;
393  }
394  }
395 
396  return ray_is_valid && ( t_enter <= t_exit );
397  }
398 
399  bool box_plane_overlap( const CartVect& normal, double d, CartVect min, CartVect max )
400  {
401  if( normal[0] < 0.0 ) std::swap( min[0], max[0] );
402  if( normal[1] < 0.0 ) std::swap( min[1], max[1] );
403  if( normal[2] < 0.0 ) std::swap( min[2], max[2] );
404 
405  return ( normal % min <= -d ) && ( normal % max >= -d );
406  }
407 
408 #define CHECK_RANGE( A, B, R ) \
409  if( ( A ) < ( B ) ) \
410  { \
411  if( ( A ) > ( R ) || ( B ) < -( R ) ) return false; \
412  } \
413  else if( ( B ) > ( R ) || ( A ) < -( R ) ) \
414  return false
415 
416  /* Adapted from: http://jgt.akpeters.com/papers/AkenineMoller01/tribox.html
417  * Use separating axis theorem to test for overlap between triangle
418  * and axis-aligned box.
419  *
420  * Test for overlap in these directions:
421  * 1) {x,y,z}-directions
422  * 2) normal of triangle
423  * 3) crossprod of triangle edge with {x,y,z}-direction
424  */
425  bool box_tri_overlap( const CartVect vertices[3], const CartVect& box_center, const CartVect& box_dims )
426  {
427  // translate everything such that box is centered at origin
428  const CartVect v0( vertices[0] - box_center );
429  const CartVect v1( vertices[1] - box_center );
430  const CartVect v2( vertices[2] - box_center );
431 
432  // do case 1) tests
433  if( v0[0] > box_dims[0] && v1[0] > box_dims[0] && v2[0] > box_dims[0] ) return false;
434  if( v0[1] > box_dims[1] && v1[1] > box_dims[1] && v2[1] > box_dims[1] ) return false;
435  if( v0[2] > box_dims[2] && v1[2] > box_dims[2] && v2[2] > box_dims[2] ) return false;
436  if( v0[0] < -box_dims[0] && v1[0] < -box_dims[0] && v2[0] < -box_dims[0] ) return false;
437  if( v0[1] < -box_dims[1] && v1[1] < -box_dims[1] && v2[1] < -box_dims[1] ) return false;
438  if( v0[2] < -box_dims[2] && v1[2] < -box_dims[2] && v2[2] < -box_dims[2] ) return false;
439 
440  // compute triangle edge vectors
441  const CartVect e0( vertices[1] - vertices[0] );
442  const CartVect e1( vertices[2] - vertices[1] );
443  const CartVect e2( vertices[0] - vertices[2] );
444 
445  // do case 3) tests
446  double fex, fey, fez, p0, p1, p2, rad;
447  fex = fabs( e0[0] );
448  fey = fabs( e0[1] );
449  fez = fabs( e0[2] );
450 
451  p0 = e0[2] * v0[1] - e0[1] * v0[2];
452  p2 = e0[2] * v2[1] - e0[1] * v2[2];
453  rad = fez * box_dims[1] + fey * box_dims[2];
454  CHECK_RANGE( p0, p2, rad );
455 
456  p0 = -e0[2] * v0[0] + e0[0] * v0[2];
457  p2 = -e0[2] * v2[0] + e0[0] * v2[2];
458  rad = fez * box_dims[0] + fex * box_dims[2];
459  CHECK_RANGE( p0, p2, rad );
460 
461  p1 = e0[1] * v1[0] - e0[0] * v1[1];
462  p2 = e0[1] * v2[0] - e0[0] * v2[1];
463  rad = fey * box_dims[0] + fex * box_dims[1];
464  CHECK_RANGE( p1, p2, rad );
465 
466  fex = fabs( e1[0] );
467  fey = fabs( e1[1] );
468  fez = fabs( e1[2] );
469 
470  p0 = e1[2] * v0[1] - e1[1] * v0[2];
471  p2 = e1[2] * v2[1] - e1[1] * v2[2];
472  rad = fez * box_dims[1] + fey * box_dims[2];
473  CHECK_RANGE( p0, p2, rad );
474 
475  p0 = -e1[2] * v0[0] + e1[0] * v0[2];
476  p2 = -e1[2] * v2[0] + e1[0] * v2[2];
477  rad = fez * box_dims[0] + fex * box_dims[2];
478  CHECK_RANGE( p0, p2, rad );
479 
480  p0 = e1[1] * v0[0] - e1[0] * v0[1];
481  p1 = e1[1] * v1[0] - e1[0] * v1[1];
482  rad = fey * box_dims[0] + fex * box_dims[1];
483  CHECK_RANGE( p0, p1, rad );
484 
485  fex = fabs( e2[0] );
486  fey = fabs( e2[1] );
487  fez = fabs( e2[2] );
488 
489  p0 = e2[2] * v0[1] - e2[1] * v0[2];
490  p1 = e2[2] * v1[1] - e2[1] * v1[2];
491  rad = fez * box_dims[1] + fey * box_dims[2];
492  CHECK_RANGE( p0, p1, rad );
493 
494  p0 = -e2[2] * v0[0] + e2[0] * v0[2];
495  p1 = -e2[2] * v1[0] + e2[0] * v1[2];
496  rad = fez * box_dims[0] + fex * box_dims[2];
497  CHECK_RANGE( p0, p1, rad );
498 
499  p1 = e2[1] * v1[0] - e2[0] * v1[1];
500  p2 = e2[1] * v2[0] - e2[0] * v2[1];
501  rad = fey * box_dims[0] + fex * box_dims[1];
502  CHECK_RANGE( p1, p2, rad );
503 
504  // do case 2) test
505  CartVect n = e0 * e1;
506  return box_plane_overlap( n, -( n % v0 ), -box_dims, box_dims );
507  }
508 
509  bool box_tri_overlap( const CartVect triangle_corners[3],
510  const CartVect& box_min_corner,
511  const CartVect& box_max_corner,
512  double tolerance )
513  {
514  const CartVect box_center = 0.5 * ( box_max_corner + box_min_corner );
515  const CartVect box_hf_dim = 0.5 * ( box_max_corner - box_min_corner );
516  return box_tri_overlap( triangle_corners, box_center, box_hf_dim + CartVect( tolerance ) );
517  }
518 
519  bool box_elem_overlap( const CartVect* elem_corners,
520  EntityType elem_type,
521  const CartVect& center,
522  const CartVect& dims,
523  int nodecount )
524  {
525 
526  switch( elem_type )
527  {
528  case MBTRI:
529  return box_tri_overlap( elem_corners, center, dims );
530  case MBTET:
531  return box_tet_overlap( elem_corners, center, dims );
532  case MBHEX:
533  return box_hex_overlap( elem_corners, center, dims );
534  case MBPOLYGON: {
535  CartVect vt[3];
536  vt[0] = elem_corners[0];
537  vt[1] = elem_corners[1];
538  for( int j = 2; j < nodecount; j++ )
539  {
540  vt[2] = elem_corners[j];
541  if( box_tri_overlap( vt, center, dims ) ) return true;
542  }
543  // none of the triangles overlap, then we return false
544  return false;
545  }
546  case MBPOLYHEDRON:
547  assert( false );
548  return false;
549  default:
550  return box_linear_elem_overlap( elem_corners, elem_type, center, dims );
551  }
552  }
553 
554  static inline CartVect quad_norm( const CartVect& v1, const CartVect& v2, const CartVect& v3, const CartVect& v4 )
555  {
556  return ( -v1 + v2 + v3 - v4 ) * ( -v1 - v2 + v3 + v4 );
557  }
558 
559  static inline CartVect tri_norm( const CartVect& v1, const CartVect& v2, const CartVect& v3 )
560  {
561  return ( v2 - v1 ) * ( v3 - v1 );
562  }
563 
564  bool box_linear_elem_overlap( const CartVect* elem_corners,
565  EntityType type,
566  const CartVect& box_center,
567  const CartVect& box_halfdims )
568  {
569  CartVect corners[8];
570  const unsigned num_corner = CN::VerticesPerEntity( type );
571  assert( num_corner <= sizeof( corners ) / sizeof( corners[0] ) );
572  for( unsigned i = 0; i < num_corner; ++i )
573  corners[i] = elem_corners[i] - box_center;
574  return box_linear_elem_overlap( corners, type, box_halfdims );
575  }
576 
577  bool box_linear_elem_overlap( const CartVect* elem_corners, EntityType type, const CartVect& dims )
578  {
579  // Do Separating Axis Theorem:
580  // If the element and the box overlap, then the 1D projections
581  // onto at least one of the axes in the following three sets
582  // must overlap (assuming convex polyhedral element).
583  // 1) The normals of the faces of the box (the principal axes)
584  // 2) The crossproduct of each element edge with each box edge
585  // (crossproduct of each edge with each principal axis)
586  // 3) The normals of the faces of the element
587 
588  int e, f; // loop counters
589  int i;
590  double dot, cross[2], tmp;
591  CartVect norm;
592  int indices[4]; // element edge/face vertex indices
593 
594  // test box face normals (principal axes)
595  const int num_corner = CN::VerticesPerEntity( type );
596  int not_less[3] = { num_corner, num_corner, num_corner };
597  int not_greater[3] = { num_corner, num_corner, num_corner };
598  int not_inside;
599  for( i = 0; i < num_corner; ++i )
600  { // for each element corner
601  not_inside = 3;
602 
603  if( elem_corners[i][0] < -dims[0] )
604  --not_less[0];
605  else if( elem_corners[i][0] > dims[0] )
606  --not_greater[0];
607  else
608  --not_inside;
609 
610  if( elem_corners[i][1] < -dims[1] )
611  --not_less[1];
612  else if( elem_corners[i][1] > dims[1] )
613  --not_greater[1];
614  else
615  --not_inside;
616 
617  if( elem_corners[i][2] < -dims[2] )
618  --not_less[2];
619  else if( elem_corners[i][2] > dims[2] )
620  --not_greater[2];
621  else
622  --not_inside;
623 
624  if( !not_inside ) return true;
625  }
626  // If all points less than min_x of box, then
627  // not_less[0] == 0, and therefore
628  // the following product is zero.
629  if( not_greater[0] * not_greater[1] * not_greater[2] * not_less[0] * not_less[1] * not_less[2] == 0 )
630  return false;
631 
632  // Test edge-edge crossproducts
633 
634  // Edge directions for box are principal axis, so
635  // for each element edge, check along the cross-product
636  // of that edge with each of the tree principal axes.
637  const int num_edge = CN::NumSubEntities( type, 1 );
638  for( e = 0; e < num_edge; ++e )
639  { // for each element edge
640  // get which element vertices bound the edge
641  CN::SubEntityVertexIndices( type, 1, e, indices );
642 
643  // X-Axis
644 
645  // calculate crossproduct: axis x (v1 - v0),
646  // where v1 and v0 are edge vertices.
647  cross[0] = elem_corners[indices[0]][2] - elem_corners[indices[1]][2];
648  cross[1] = elem_corners[indices[1]][1] - elem_corners[indices[0]][1];
649  // skip if parallel
650  if( ( cross[0] * cross[0] + cross[1] * cross[1] ) >= std::numeric_limits< double >::epsilon() )
651  {
652  dot = fabs( cross[0] * dims[1] ) + fabs( cross[1] * dims[2] );
653  not_less[0] = not_greater[0] = num_corner - 1;
654  for( i = ( indices[0] + 1 ) % num_corner; i != indices[0]; i = ( i + 1 ) % num_corner )
655  { // for each element corner
656  tmp = cross[0] * elem_corners[i][1] + cross[1] * elem_corners[i][2];
657  not_less[0] -= ( tmp < -dot );
658  not_greater[0] -= ( tmp > dot );
659  }
660 
661  if( not_less[0] * not_greater[0] == 0 ) return false;
662  }
663 
664  // Y-Axis
665 
666  // calculate crossproduct: axis x (v1 - v0),
667  // where v1 and v0 are edge vertices.
668  cross[0] = elem_corners[indices[0]][0] - elem_corners[indices[1]][0];
669  cross[1] = elem_corners[indices[1]][2] - elem_corners[indices[0]][2];
670  // skip if parallel
671  if( ( cross[0] * cross[0] + cross[1] * cross[1] ) >= std::numeric_limits< double >::epsilon() )
672  {
673  dot = fabs( cross[0] * dims[2] ) + fabs( cross[1] * dims[0] );
674  not_less[0] = not_greater[0] = num_corner - 1;
675  for( i = ( indices[0] + 1 ) % num_corner; i != indices[0]; i = ( i + 1 ) % num_corner )
676  { // for each element corner
677  tmp = cross[0] * elem_corners[i][2] + cross[1] * elem_corners[i][0];
678  not_less[0] -= ( tmp < -dot );
679  not_greater[0] -= ( tmp > dot );
680  }
681 
682  if( not_less[0] * not_greater[0] == 0 ) return false;
683  }
684 
685  // Z-Axis
686 
687  // calculate crossproduct: axis x (v1 - v0),
688  // where v1 and v0 are edge vertices.
689  cross[0] = elem_corners[indices[0]][1] - elem_corners[indices[1]][1];
690  cross[1] = elem_corners[indices[1]][0] - elem_corners[indices[0]][0];
691  // skip if parallel
692  if( ( cross[0] * cross[0] + cross[1] * cross[1] ) >= std::numeric_limits< double >::epsilon() )
693  {
694  dot = fabs( cross[0] * dims[0] ) + fabs( cross[1] * dims[1] );
695  not_less[0] = not_greater[0] = num_corner - 1;
696  for( i = ( indices[0] + 1 ) % num_corner; i != indices[0]; i = ( i + 1 ) % num_corner )
697  { // for each element corner
698  tmp = cross[0] * elem_corners[i][0] + cross[1] * elem_corners[i][1];
699  not_less[0] -= ( tmp < -dot );
700  not_greater[0] -= ( tmp > dot );
701  }
702 
703  if( not_less[0] * not_greater[0] == 0 ) return false;
704  }
705  }
706 
707  // test element face normals
708  const int num_face = CN::NumSubEntities( type, 2 );
709  for( f = 0; f < num_face; ++f )
710  {
711  CN::SubEntityVertexIndices( type, 2, f, indices );
712  switch( CN::SubEntityType( type, 2, f ) )
713  {
714  case MBTRI:
715  norm = tri_norm( elem_corners[indices[0]], elem_corners[indices[1]], elem_corners[indices[2]] );
716  break;
717  case MBQUAD:
718  norm = quad_norm( elem_corners[indices[0]], elem_corners[indices[1]], elem_corners[indices[2]],
719  elem_corners[indices[3]] );
720  break;
721  default:
722  assert( false );
723  continue;
724  }
725 
726  dot = dot_abs( norm, dims );
727 
728  // for each element vertex
729  not_less[0] = not_greater[0] = num_corner;
730  for( i = 0; i < num_corner; ++i )
731  {
732  tmp = norm % elem_corners[i];
733  not_less[0] -= ( tmp < -dot );
734  not_greater[0] -= ( tmp > dot );
735  }
736 
737  if( not_less[0] * not_greater[0] == 0 ) return false;
738  }
739 
740  // Overlap on all tested axes.
741  return true;
742  }
743 
744  bool box_hex_overlap( const CartVect* elem_corners, const CartVect& center, const CartVect& dims )
745  {
746  // Do Separating Axis Theorem:
747  // If the element and the box overlap, then the 1D projections
748  // onto at least one of the axes in the following three sets
749  // must overlap (assuming convex polyhedral element).
750  // 1) The normals of the faces of the box (the principal axes)
751  // 2) The crossproduct of each element edge with each box edge
752  // (crossproduct of each edge with each principal axis)
753  // 3) The normals of the faces of the element
754 
755  unsigned i, e, f; // loop counters
756  double dot, cross[2], tmp;
757  CartVect norm;
758  const CartVect corners[8] = { elem_corners[0] - center, elem_corners[1] - center, elem_corners[2] - center,
759  elem_corners[3] - center, elem_corners[4] - center, elem_corners[5] - center,
760  elem_corners[6] - center, elem_corners[7] - center };
761 
762  // test box face normals (principal axes)
763  int not_less[3] = { 8, 8, 8 };
764  int not_greater[3] = { 8, 8, 8 };
765  int not_inside;
766  for( i = 0; i < 8; ++i )
767  { // for each element corner
768  not_inside = 3;
769 
770  if( corners[i][0] < -dims[0] )
771  --not_less[0];
772  else if( corners[i][0] > dims[0] )
773  --not_greater[0];
774  else
775  --not_inside;
776 
777  if( corners[i][1] < -dims[1] )
778  --not_less[1];
779  else if( corners[i][1] > dims[1] )
780  --not_greater[1];
781  else
782  --not_inside;
783 
784  if( corners[i][2] < -dims[2] )
785  --not_less[2];
786  else if( corners[i][2] > dims[2] )
787  --not_greater[2];
788  else
789  --not_inside;
790 
791  if( !not_inside ) return true;
792  }
793  // If all points less than min_x of box, then
794  // not_less[0] == 0, and therefore
795  // the following product is zero.
796  if( not_greater[0] * not_greater[1] * not_greater[2] * not_less[0] * not_less[1] * not_less[2] == 0 )
797  return false;
798 
799  // Test edge-edge crossproducts
800  const unsigned edges[12][2] = { { 0, 1 }, { 0, 4 }, { 0, 3 }, { 2, 3 }, { 2, 1 }, { 2, 6 },
801  { 5, 6 }, { 5, 1 }, { 5, 4 }, { 7, 4 }, { 7, 3 }, { 7, 6 } };
802 
803  // Edge directions for box are principal axis, so
804  // for each element edge, check along the cross-product
805  // of that edge with each of the tree principal axes.
806  for( e = 0; e < 12; ++e )
807  { // for each element edge
808  // get which element vertices bound the edge
809  const CartVect& v0 = corners[edges[e][0]];
810  const CartVect& v1 = corners[edges[e][1]];
811 
812  // X-Axis
813 
814  // calculate crossproduct: axis x (v1 - v0),
815  // where v1 and v0 are edge vertices.
816  cross[0] = v0[2] - v1[2];
817  cross[1] = v1[1] - v0[1];
818  // skip if parallel
819  if( ( cross[0] * cross[0] + cross[1] * cross[1] ) >= std::numeric_limits< double >::epsilon() )
820  {
821  dot = fabs( cross[0] * dims[1] ) + fabs( cross[1] * dims[2] );
822  not_less[0] = not_greater[0] = 7;
823  for( i = ( edges[e][0] + 1 ) % 8; i != edges[e][0]; i = ( i + 1 ) % 8 )
824  { // for each element corner
825  tmp = cross[0] * corners[i][1] + cross[1] * corners[i][2];
826  not_less[0] -= ( tmp < -dot );
827  not_greater[0] -= ( tmp > dot );
828  }
829 
830  if( not_less[0] * not_greater[0] == 0 ) return false;
831  }
832 
833  // Y-Axis
834 
835  // calculate crossproduct: axis x (v1 - v0),
836  // where v1 and v0 are edge vertices.
837  cross[0] = v0[0] - v1[0];
838  cross[1] = v1[2] - v0[2];
839  // skip if parallel
840  if( ( cross[0] * cross[0] + cross[1] * cross[1] ) >= std::numeric_limits< double >::epsilon() )
841  {
842  dot = fabs( cross[0] * dims[2] ) + fabs( cross[1] * dims[0] );
843  not_less[0] = not_greater[0] = 7;
844  for( i = ( edges[e][0] + 1 ) % 8; i != edges[e][0]; i = ( i + 1 ) % 8 )
845  { // for each element corner
846  tmp = cross[0] * corners[i][2] + cross[1] * corners[i][0];
847  not_less[0] -= ( tmp < -dot );
848  not_greater[0] -= ( tmp > dot );
849  }
850 
851  if( not_less[0] * not_greater[0] == 0 ) return false;
852  }
853 
854  // Z-Axis
855 
856  // calculate crossproduct: axis x (v1 - v0),
857  // where v1 and v0 are edge vertices.
858  cross[0] = v0[1] - v1[1];
859  cross[1] = v1[0] - v0[0];
860  // skip if parallel
861  if( ( cross[0] * cross[0] + cross[1] * cross[1] ) >= std::numeric_limits< double >::epsilon() )
862  {
863  dot = fabs( cross[0] * dims[0] ) + fabs( cross[1] * dims[1] );
864  not_less[0] = not_greater[0] = 7;
865  for( i = ( edges[e][0] + 1 ) % 8; i != edges[e][0]; i = ( i + 1 ) % 8 )
866  { // for each element corner
867  tmp = cross[0] * corners[i][0] + cross[1] * corners[i][1];
868  not_less[0] -= ( tmp < -dot );
869  not_greater[0] -= ( tmp > dot );
870  }
871 
872  if( not_less[0] * not_greater[0] == 0 ) return false;
873  }
874  }
875 
876  // test element face normals
877  const unsigned faces[6][4] = { { 0, 1, 2, 3 }, { 0, 1, 5, 4 }, { 1, 2, 6, 5 },
878  { 2, 6, 7, 3 }, { 3, 7, 4, 0 }, { 7, 4, 5, 6 } };
879  for( f = 0; f < 6; ++f )
880  {
881  norm = quad_norm( corners[faces[f][0]], corners[faces[f][1]], corners[faces[f][2]], corners[faces[f][3]] );
882 
883  dot = dot_abs( norm, dims );
884 
885  // for each element vertex
886  not_less[0] = not_greater[0] = 8;
887  for( i = 0; i < 8; ++i )
888  {
889  tmp = norm % corners[i];
890  not_less[0] -= ( tmp < -dot );
891  not_greater[0] -= ( tmp > dot );
892  }
893 
894  if( not_less[0] * not_greater[0] == 0 ) return false;
895  }
896 
897  // Overlap on all tested axes.
898  return true;
899  }
900 
901  static inline bool box_tet_overlap_edge( const CartVect& dims,
902  const CartVect& edge,
903  const CartVect& ve,
904  const CartVect& v1,
905  const CartVect& v2 )
906  {
907  double dot, dot1, dot2, dot3, min, max;
908 
909  // edge x X
910  if( fabs( edge[1] * edge[2] ) > std::numeric_limits< double >::epsilon() )
911  {
912  dot = fabs( edge[2] ) * dims[1] + fabs( edge[1] ) * dims[2];
913  dot1 = edge[2] * ve[1] - edge[1] * ve[2];
914  dot2 = edge[2] * v1[1] - edge[1] * v1[2];
915  dot3 = edge[2] * v2[1] - edge[1] * v2[2];
916  min_max_3( dot1, dot2, dot3, min, max );
917  if( max < -dot || min > dot ) return false;
918  }
919 
920  // edge x Y
921  if( fabs( edge[1] * edge[2] ) > std::numeric_limits< double >::epsilon() )
922  {
923  dot = fabs( edge[2] ) * dims[0] + fabs( edge[0] ) * dims[2];
924  dot1 = -edge[2] * ve[0] + edge[0] * ve[2];
925  dot2 = -edge[2] * v1[0] + edge[0] * v1[2];
926  dot3 = -edge[2] * v2[0] + edge[0] * v2[2];
927  min_max_3( dot1, dot2, dot3, min, max );
928  if( max < -dot || min > dot ) return false;
929  }
930 
931  // edge x Z
932  if( fabs( edge[1] * edge[2] ) > std::numeric_limits< double >::epsilon() )
933  {
934  dot = fabs( edge[1] ) * dims[0] + fabs( edge[0] ) * dims[1];
935  dot1 = edge[1] * ve[0] - edge[0] * ve[1];
936  dot2 = edge[1] * v1[0] - edge[0] * v1[1];
937  dot3 = edge[1] * v2[0] - edge[0] * v2[1];
938  min_max_3( dot1, dot2, dot3, min, max );
939  if( max < -dot || min > dot ) return false;
940  }
941 
942  return true;
943  }
944 
945  bool box_tet_overlap( const CartVect* corners_in, const CartVect& center, const CartVect& dims )
946  {
947  // Do Separating Axis Theorem:
948  // If the element and the box overlap, then the 1D projections
949  // onto at least one of the axes in the following three sets
950  // must overlap (assuming convex polyhedral element).
951  // 1) The normals of the faces of the box (the principal axes)
952  // 2) The crossproduct of each element edge with each box edge
953  // (crossproduct of each edge with each principal axis)
954  // 3) The normals of the faces of the element
955 
956  // Translate problem such that box center is at origin.
957  const CartVect corners[4] = { corners_in[0] - center, corners_in[1] - center, corners_in[2] - center,
958  corners_in[3] - center };
959 
960  // 0) Check if any vertex is within the box
961  if( fabs( corners[0][0] ) <= dims[0] && fabs( corners[0][1] ) <= dims[1] && fabs( corners[0][2] ) <= dims[2] )
962  return true;
963  if( fabs( corners[1][0] ) <= dims[0] && fabs( corners[1][1] ) <= dims[1] && fabs( corners[1][2] ) <= dims[2] )
964  return true;
965  if( fabs( corners[2][0] ) <= dims[0] && fabs( corners[2][1] ) <= dims[1] && fabs( corners[2][2] ) <= dims[2] )
966  return true;
967  if( fabs( corners[3][0] ) <= dims[0] && fabs( corners[3][1] ) <= dims[1] && fabs( corners[3][2] ) <= dims[2] )
968  return true;
969 
970  // 1) Check for overlap on each principal axis (box face normal)
971  // X
972  if( corners[0][0] < -dims[0] && corners[1][0] < -dims[0] && corners[2][0] < -dims[0] &&
973  corners[3][0] < -dims[0] )
974  return false;
975  if( corners[0][0] > dims[0] && corners[1][0] > dims[0] && corners[2][0] > dims[0] && corners[3][0] > dims[0] )
976  return false;
977  // Y
978  if( corners[0][1] < -dims[1] && corners[1][1] < -dims[1] && corners[2][1] < -dims[1] &&
979  corners[3][1] < -dims[1] )
980  return false;
981  if( corners[0][1] > dims[1] && corners[1][1] > dims[1] && corners[2][1] > dims[1] && corners[3][1] > dims[1] )
982  return false;
983  // Z
984  if( corners[0][2] < -dims[2] && corners[1][2] < -dims[2] && corners[2][2] < -dims[2] &&
985  corners[3][2] < -dims[2] )
986  return false;
987  if( corners[0][2] > dims[2] && corners[1][2] > dims[2] && corners[2][2] > dims[2] && corners[3][2] > dims[2] )
988  return false;
989 
990  // 3) test element face normals
991  CartVect norm;
992  double dot, dot1, dot2;
993 
994  const CartVect v01 = corners[1] - corners[0];
995  const CartVect v02 = corners[2] - corners[0];
996  norm = v01 * v02;
997  dot = dot_abs( norm, dims );
998  dot1 = norm % corners[0];
999  dot2 = norm % corners[3];
1000  if( dot1 > dot2 ) std::swap( dot1, dot2 );
1001  if( dot2 < -dot || dot1 > dot ) return false;
1002 
1003  const CartVect v03 = corners[3] - corners[0];
1004  norm = v03 * v01;
1005  dot = dot_abs( norm, dims );
1006  dot1 = norm % corners[0];
1007  dot2 = norm % corners[2];
1008  if( dot1 > dot2 ) std::swap( dot1, dot2 );
1009  if( dot2 < -dot || dot1 > dot ) return false;
1010 
1011  norm = v02 * v03;
1012  dot = dot_abs( norm, dims );
1013  dot1 = norm % corners[0];
1014  dot2 = norm % corners[1];
1015  if( dot1 > dot2 ) std::swap( dot1, dot2 );
1016  if( dot2 < -dot || dot1 > dot ) return false;
1017 
1018  const CartVect v12 = corners[2] - corners[1];
1019  const CartVect v13 = corners[3] - corners[1];
1020  norm = v13 * v12;
1021  dot = dot_abs( norm, dims );
1022  dot1 = norm % corners[0];
1023  dot2 = norm % corners[1];
1024  if( dot1 > dot2 ) std::swap( dot1, dot2 );
1025  if( dot2 < -dot || dot1 > dot ) return false;
1026 
1027  // 2) test edge-edge cross products
1028 
1029  const CartVect v23 = corners[3] - corners[2];
1030  return box_tet_overlap_edge( dims, v01, corners[0], corners[2], corners[3] ) &&
1031  box_tet_overlap_edge( dims, v02, corners[0], corners[1], corners[3] ) &&
1032  box_tet_overlap_edge( dims, v03, corners[0], corners[1], corners[2] ) &&
1033  box_tet_overlap_edge( dims, v12, corners[1], corners[0], corners[3] ) &&
1034  box_tet_overlap_edge( dims, v13, corners[1], corners[0], corners[2] ) &&
1035  box_tet_overlap_edge( dims, v23, corners[2], corners[0], corners[1] );
1036  }
1037 
1038  // from:
1039  // http://www.geometrictools.com/Documentation/DistancePoint3Triangle3.pdf#search=%22closest%20point%20on%20triangle%22
1040  /* t
1041  * \‍(2)^
1042  * \ |
1043  * \ |
1044  * \|
1045  * \
1046  * |\
1047  * | \
1048  * | \ (1)
1049  * (3) tv \
1050  * | \
1051  * | (0) \
1052  * | \
1053  *-------+---sv--\----> s
1054  * | \ (6)
1055  * (4) | (5) \
1056  */
1057  // Worst case is either 61 flops and 5 compares or 53 flops and 6 compares,
1058  // depending on relative costs. For all paths that do not return one of the
1059  // corner vertices, exactly one of the flops is a divide.
1060  void closest_location_on_tri( const CartVect& location, const CartVect* vertices, CartVect& closest_out )
1061  { // ops comparisons
1062  const CartVect sv( vertices[1] - vertices[0] ); // +3 = 3
1063  const CartVect tv( vertices[2] - vertices[0] ); // +3 = 6
1064  const CartVect pv( vertices[0] - location ); // +3 = 9
1065  const double ss = sv % sv; // +5 = 14
1066  const double st = sv % tv; // +5 = 19
1067  const double tt = tv % tv; // +5 = 24
1068  const double sp = sv % pv; // +5 = 29
1069  const double tp = tv % pv; // +5 = 34
1070  const double det = ss * tt - st * st; // +3 = 37
1071  double s = st * tp - tt * sp; // +3 = 40
1072  double t = st * sp - ss * tp; // +3 = 43
1073  if( s + t < det )
1074  { // +1 = 44, +1 = 1
1075  if( s < 0 )
1076  { // +1 = 2
1077  if( t < 0 )
1078  { // +1 = 3
1079  // region 4
1080  if( sp < 0 )
1081  { // +1 = 4
1082  if( -sp > ss ) // +1 = 5
1083  closest_out = vertices[1]; // 44 5
1084  else
1085  closest_out = vertices[0] - ( sp / ss ) * sv; // +7 = 51, 5
1086  }
1087  else if( tp < 0 )
1088  { // +1 = 5
1089  if( -tp > tt ) // +1 = 6
1090  closest_out = vertices[2]; // 44, 6
1091  else
1092  closest_out = vertices[0] - ( tp / tt ) * tv; // +7 = 51, 6
1093  }
1094  else
1095  {
1096  closest_out = vertices[0]; // 44, 5
1097  }
1098  }
1099  else
1100  {
1101  // region 3
1102  if( tp >= 0 ) // +1 = 4
1103  closest_out = vertices[0]; // 44, 4
1104  else if( -tp >= tt ) // +1 = 5
1105  closest_out = vertices[2]; // 44, 5
1106  else
1107  closest_out = vertices[0] - ( tp / tt ) * tv; // +7 = 51, 5
1108  }
1109  }
1110  else if( t < 0 )
1111  { // +1 = 3
1112  // region 5;
1113  if( sp >= 0.0 ) // +1 = 4
1114  closest_out = vertices[0]; // 44, 4
1115  else if( -sp >= ss ) // +1 = 5
1116  closest_out = vertices[1]; // 44 5
1117  else
1118  closest_out = vertices[0] - ( sp / ss ) * sv; // +7 = 51, 5
1119  }
1120  else
1121  {
1122  // region 0
1123  const double inv_det = 1.0 / det; // +1 = 45
1124  s *= inv_det; // +1 = 46
1125  t *= inv_det; // +1 = 47
1126  closest_out = vertices[0] + s * sv + t * tv; //+12 = 59, 3
1127  }
1128  }
1129  else
1130  {
1131  if( s < 0 )
1132  { // +1 = 2
1133  // region 2
1134  s = st + sp; // +1 = 45
1135  t = tt + tp; // +1 = 46
1136  if( t > s )
1137  { // +1 = 3
1138  const double num = t - s; // +1 = 47
1139  const double den = ss - 2 * st + tt; // +3 = 50
1140  if( num > den ) // +1 = 4
1141  closest_out = vertices[1]; // 50, 4
1142  else
1143  {
1144  s = num / den; // +1 = 51
1145  t = 1 - s; // +1 = 52
1146  closest_out = s * vertices[1] + t * vertices[2]; // +9 = 61, 4
1147  }
1148  }
1149  else if( t <= 0 ) // +1 = 4
1150  closest_out = vertices[2]; // 46, 4
1151  else if( tp >= 0 ) // +1 = 5
1152  closest_out = vertices[0]; // 46, 5
1153  else
1154  closest_out = vertices[0] - ( tp / tt ) * tv; // +7 = 53, 5
1155  }
1156  else if( t < 0 )
1157  { // +1 = 3
1158  // region 6
1159  t = st + tp; // +1 = 45
1160  s = ss + sp; // +1 = 46
1161  if( s > t )
1162  { // +1 = 4
1163  const double num = t - s; // +1 = 47
1164  const double den = tt - 2 * st + ss; // +3 = 50
1165  if( num > den ) // +1 = 5
1166  closest_out = vertices[2]; // 50, 5
1167  else
1168  {
1169  t = num / den; // +1 = 51
1170  s = 1 - t; // +1 = 52
1171  closest_out = s * vertices[1] + t * vertices[2]; // +9 = 61, 5
1172  }
1173  }
1174  else if( s <= 0 ) // +1 = 5
1175  closest_out = vertices[1]; // 46, 5
1176  else if( sp >= 0 ) // +1 = 6
1177  closest_out = vertices[0]; // 46, 6
1178  else
1179  closest_out = vertices[0] - ( sp / ss ) * sv; // +7 = 53, 6
1180  }
1181  else
1182  {
1183  // region 1
1184  const double num = tt + tp - st - sp; // +3 = 47
1185  if( num <= 0 )
1186  { // +1 = 4
1187  closest_out = vertices[2]; // 47, 4
1188  }
1189  else
1190  {
1191  const double den = ss - 2 * st + tt; // +3 = 50
1192  if( num >= den ) // +1 = 5
1193  closest_out = vertices[1]; // 50, 5
1194  else
1195  {
1196  s = num / den; // +1 = 51
1197  t = 1 - s; // +1 = 52
1198  closest_out = s * vertices[1] + t * vertices[2]; // +9 = 61, 5
1199  }
1200  }
1201  }
1202  }
1203  }
1204 
1205  void closest_location_on_tri( const CartVect& location,
1206  const CartVect* vertices,
1207  double tolerance,
1208  CartVect& closest_out,
1209  int& closest_topo )
1210  {
1211  const double tsqr = tolerance * tolerance;
1212  int i;
1213  CartVect pv[3], ev, ep;
1214  double t;
1215 
1216  closest_location_on_tri( location, vertices, closest_out );
1217 
1218  for( i = 0; i < 3; ++i )
1219  {
1220  pv[i] = vertices[i] - closest_out;
1221  if( ( pv[i] % pv[i] ) <= tsqr )
1222  {
1223  closest_topo = i;
1224  return;
1225  }
1226  }
1227 
1228  for( i = 0; i < 3; ++i )
1229  {
1230  ev = vertices[( i + 1 ) % 3] - vertices[i];
1231  t = ( ev % pv[i] ) / ( ev % ev );
1232  ep = closest_out - ( vertices[i] + t * ev );
1233  if( ( ep % ep ) <= tsqr )
1234  {
1235  closest_topo = i + 3;
1236  return;
1237  }
1238  }
1239 
1240  closest_topo = 6;
1241  }
1242 
1243  // We assume polygon is *convex*, but *not* planar.
1244  void closest_location_on_polygon( const CartVect& location,
1245  const CartVect* vertices,
1246  int num_vertices,
1247  CartVect& closest_out )
1248  {
1249  const int n = num_vertices;
1250  CartVect d, p, v;
1251  double shortest_sqr, dist_sqr, t_closest, t;
1252  int i, e;
1253 
1254  // Find closest edge of polygon.
1255  e = n - 1;
1256  v = vertices[0] - vertices[e];
1257  t_closest = ( v % ( location - vertices[e] ) ) / ( v % v );
1258  if( t_closest < 0.0 )
1259  d = location - vertices[e];
1260  else if( t_closest > 1.0 )
1261  d = location - vertices[0];
1262  else
1263  d = location - vertices[e] - t_closest * v;
1264  shortest_sqr = d % d;
1265  for( i = 0; i < n - 1; ++i )
1266  {
1267  v = vertices[i + 1] - vertices[i];
1268  t = ( v % ( location - vertices[i] ) ) / ( v % v );
1269  if( t < 0.0 )
1270  d = location - vertices[i];
1271  else if( t > 1.0 )
1272  d = location - vertices[i + 1];
1273  else
1274  d = location - vertices[i] - t * v;
1275  dist_sqr = d % d;
1276  if( dist_sqr < shortest_sqr )
1277  {
1278  e = i;
1279  shortest_sqr = dist_sqr;
1280  t_closest = t;
1281  }
1282  }
1283 
1284  // If we are beyond the bounds of the edge, then
1285  // the point is outside and closest to a vertex
1286  if( t_closest <= 0.0 )
1287  {
1288  closest_out = vertices[e];
1289  return;
1290  }
1291  else if( t_closest >= 1.0 )
1292  {
1293  closest_out = vertices[( e + 1 ) % n];
1294  return;
1295  }
1296 
1297  // Now check which side of the edge we are one
1298  const CartVect v0 = vertices[e] - vertices[( e + n - 1 ) % n];
1299  const CartVect v1 = vertices[( e + 1 ) % n] - vertices[e];
1300  const CartVect v2 = vertices[( e + 2 ) % n] - vertices[( e + 1 ) % n];
1301  const CartVect norm = ( 1.0 - t_closest ) * ( v0 * v1 ) + t_closest * ( v1 * v2 );
1302  // if on outside of edge, result is closest point on edge
1303  if( ( norm % ( ( vertices[e] - location ) * v1 ) ) <= 0.0 )
1304  {
1305  closest_out = vertices[e] + t_closest * v1;
1306  return;
1307  }
1308 
1309  // Inside. Project to plane defined by point and normal at
1310  // closest edge
1311  const double D = -( norm % ( vertices[e] + t_closest * v1 ) );
1312  closest_out = ( location - ( norm % location + D ) * norm ) / ( norm % norm );
1313  }
1314 
1315  void closest_location_on_box( const CartVect& min, const CartVect& max, const CartVect& point, CartVect& closest )
1316  {
1317  closest[0] = point[0] < min[0] ? min[0] : point[0] > max[0] ? max[0] : point[0];
1318  closest[1] = point[1] < min[1] ? min[1] : point[1] > max[1] ? max[1] : point[1];
1319  closest[2] = point[2] < min[2] ? min[2] : point[2] > max[2] ? max[2] : point[2];
1320  }
1321 
1322  bool box_point_overlap( const CartVect& box_min_corner,
1323  const CartVect& box_max_corner,
1324  const CartVect& point,
1325  double tolerance )
1326  {
1327  CartVect closest;
1328  closest_location_on_box( box_min_corner, box_max_corner, point, closest );
1329  closest -= point;
1330  return closest % closest < tolerance * tolerance;
1331  }
1332 
1333  bool boxes_overlap( const CartVect& box_min1,
1334  const CartVect& box_max1,
1335  const CartVect& box_min2,
1336  const CartVect& box_max2,
1337  double tolerance )
1338  {
1339 
1340  for( int k = 0; k < 3; k++ )
1341  {
1342  double b1min = box_min1[k], b1max = box_max1[k];
1343  double b2min = box_min2[k], b2max = box_max2[k];
1344  if( b1min - tolerance > b2max ) return false;
1345  if( b2min - tolerance > b1max ) return false;
1346  }
1347  return true;
1348  }
1349 
1350  // see if boxes formed by 2 lists of "CartVect"s overlap
1351  bool bounding_boxes_overlap( const CartVect* list1, int num1, const CartVect* list2, int num2, double tolerance )
1352  {
1353  assert( num1 >= 1 && num2 >= 1 );
1354  CartVect box_min1 = list1[0], box_max1 = list1[0];
1355  CartVect box_min2 = list2[0], box_max2 = list2[0];
1356  for( int i = 1; i < num1; i++ )
1357  {
1358  for( int k = 0; k < 3; k++ )
1359  {
1360  double val = list1[i][k];
1361  if( box_min1[k] > val ) box_min1[k] = val;
1362  if( box_max1[k] < val ) box_max1[k] = val;
1363  }
1364  }
1365  for( int i = 1; i < num2; i++ )
1366  {
1367  for( int k = 0; k < 3; k++ )
1368  {
1369  double val = list2[i][k];
1370  if( box_min2[k] > val ) box_min2[k] = val;
1371  if( box_max2[k] < val ) box_max2[k] = val;
1372  }
1373  }
1374 
1375  return boxes_overlap( box_min1, box_max1, box_min2, box_max2, tolerance );
1376  }
1377 
1378  // see if boxes formed by 2 lists of 2d coordinates overlap (num1>=3, num2>=3, do not check)
1379  bool bounding_boxes_overlap_2d( const double* list1, int num1, const double* list2, int num2, double tolerance )
1380  {
1381  /*
1382  * box1:
1383  * (bmax11, bmax12)
1384  * |-------|
1385  * | |
1386  * |-------|
1387  * (bmin11, bmin12)
1388 
1389  * box2:
1390  * (bmax21, bmax22)
1391  * |----------|
1392  * | |
1393  * |----------|
1394  * (bmin21, bmin22)
1395  */
1396  double bmin11, bmax11, bmin12, bmax12;
1397  bmin11 = bmax11 = list1[0];
1398  bmin12 = bmax12 = list1[1];
1399 
1400  double bmin21, bmax21, bmin22, bmax22;
1401  bmin21 = bmax21 = list2[0];
1402  bmin22 = bmax22 = list2[1];
1403 
1404  for( int i = 1; i < num1; i++ )
1405  {
1406  if( bmin11 > list1[2 * i] ) bmin11 = list1[2 * i];
1407  if( bmax11 < list1[2 * i] ) bmax11 = list1[2 * i];
1408  if( bmin12 > list1[2 * i + 1] ) bmin12 = list1[2 * i + 1];
1409  if( bmax12 < list1[2 * i + 1] ) bmax12 = list1[2 * i + 1];
1410  }
1411  for( int i = 1; i < num2; i++ )
1412  {
1413  if( bmin21 > list2[2 * i] ) bmin21 = list2[2 * i];
1414  if( bmax21 < list2[2 * i] ) bmax21 = list2[2 * i];
1415  if( bmin22 > list2[2 * i + 1] ) bmin22 = list2[2 * i + 1];
1416  if( bmax22 < list2[2 * i + 1] ) bmax22 = list2[2 * i + 1];
1417  }
1418 
1419  if( ( bmax11 < bmin21 + tolerance ) || ( bmax21 < bmin11 + tolerance ) ) return false;
1420 
1421  if( ( bmax12 < bmin22 + tolerance ) || ( bmax22 < bmin12 + tolerance ) ) return false;
1422 
1423  return true;
1424  }
1425 
1426  /**\brief Class representing a 3-D mapping function (e.g. shape function for volume element) */
1427  class VolMap
1428  {
1429  public:
1430  /**\brief Return \f$\vec \xi\f$ corresponding to logical center of element */
1431  virtual CartVect center_xi() const = 0;
1432  /**\brief Evaluate mapping function (calculate \f$\vec x = F($\vec \xi)\f$ )*/
1433  virtual CartVect evaluate( const CartVect& xi ) const = 0;
1434  /**\brief Evaluate Jacobian of mapping function */
1435  virtual Matrix3 jacobian( const CartVect& xi ) const = 0;
1436  /**\brief Evaluate inverse of mapping function (calculate \f$\vec \xi = F^-1($\vec x)\f$ )*/
1437  bool solve_inverse( const CartVect& x, CartVect& xi, double tol ) const;
1438  };
1439 
1440  bool VolMap::solve_inverse( const CartVect& x, CartVect& xi, double tol ) const
1441  {
1442  const double error_tol_sqr = tol * tol;
1443  double det;
1444  xi = center_xi();
1445  CartVect delta = evaluate( xi ) - x;
1446  Matrix3 J;
1447  while( delta % delta > error_tol_sqr )
1448  {
1449  J = jacobian( xi );
1450  det = J.determinant();
1451  if( det < std::numeric_limits< double >::epsilon() ) return false;
1452  xi -= J.inverse() * delta;
1453  delta = evaluate( xi ) - x;
1454  }
1455  return true;
1456  }
1457 
1458  /**\brief Shape function for trilinear hexahedron */
1459  class LinearHexMap : public VolMap
1460  {
1461  public:
1462  LinearHexMap( const CartVect* corner_coords ) : corners( corner_coords ) {}
1463  virtual CartVect center_xi() const;
1464  virtual CartVect evaluate( const CartVect& xi ) const;
1465  virtual Matrix3 jacobian( const CartVect& xi ) const;
1466 
1467  private:
1469  static const double corner_xi[8][3];
1470  };
1471 
1472  const double LinearHexMap::corner_xi[8][3] = { { -1, -1, -1 }, { 1, -1, -1 }, { 1, 1, -1 }, { -1, 1, -1 },
1473  { -1, -1, 1 }, { 1, -1, 1 }, { 1, 1, 1 }, { -1, 1, 1 } };
1475  {
1476  return CartVect( 0.0 );
1477  }
1478 
1480  {
1481  CartVect x( 0.0 );
1482  for( unsigned i = 0; i < 8; ++i )
1483  {
1484  const double N_i =
1485  ( 1 + xi[0] * corner_xi[i][0] ) * ( 1 + xi[1] * corner_xi[i][1] ) * ( 1 + xi[2] * corner_xi[i][2] );
1486  x += N_i * corners[i];
1487  }
1488  x *= 0.125;
1489  return x;
1490  }
1491 
1493  {
1494  Matrix3 J( 0.0 );
1495  for( unsigned i = 0; i < 8; ++i )
1496  {
1497  const double xi_p = 1 + xi[0] * corner_xi[i][0];
1498  const double eta_p = 1 + xi[1] * corner_xi[i][1];
1499  const double zeta_p = 1 + xi[2] * corner_xi[i][2];
1500  const double dNi_dxi = corner_xi[i][0] * eta_p * zeta_p;
1501  const double dNi_deta = corner_xi[i][1] * xi_p * zeta_p;
1502  const double dNi_dzeta = corner_xi[i][2] * xi_p * eta_p;
1503  J( 0, 0 ) += dNi_dxi * corners[i][0];
1504  J( 1, 0 ) += dNi_dxi * corners[i][1];
1505  J( 2, 0 ) += dNi_dxi * corners[i][2];
1506  J( 0, 1 ) += dNi_deta * corners[i][0];
1507  J( 1, 1 ) += dNi_deta * corners[i][1];
1508  J( 2, 1 ) += dNi_deta * corners[i][2];
1509  J( 0, 2 ) += dNi_dzeta * corners[i][0];
1510  J( 1, 2 ) += dNi_dzeta * corners[i][1];
1511  J( 2, 2 ) += dNi_dzeta * corners[i][2];
1512  }
1513  return J *= 0.125;
1514  }
1515 
1516  bool nat_coords_trilinear_hex( const CartVect* corner_coords, const CartVect& x, CartVect& xi, double tol )
1517  {
1518  return LinearHexMap( corner_coords ).solve_inverse( x, xi, tol );
1519  }
1520 
1521  bool point_in_trilinear_hex( const CartVect* hex, const CartVect& xyz, double etol )
1522  {
1523  CartVect xi;
1524  return nat_coords_trilinear_hex( hex, xyz, xi, etol ) && fabs( xi[0] ) - 1 < etol && fabs( xi[1] ) - 1 < etol &&
1525  fabs( xi[2] ) - 1 < etol;
1526  }
1527 
1528 } // namespace GeomUtil
1529 
1530 } // namespace moab