Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
moab::GeomQueryTool Class Reference

Tool for querying different aspects of geometric topology sets in MOAB. More...

#include <GeomQueryTool.hpp>

+ Collaboration diagram for moab::GeomQueryTool:

Classes

class  RayHistory
 

Public Member Functions

 GeomQueryTool (Interface *impl, bool find_geoments=false, EntityHandle modelRootSet=0, bool p_rootSets_vector=true, bool restore_rootSets=true, bool trace_counting=false, double overlap_thickness=0., double numerical_precision=0.001)
 
 GeomQueryTool (GeomTopoTool *geomtopotool, bool trace_counting=false, double overlap_thickness=0., double numerical_precision=0.001)
 
 ~GeomQueryTool ()
 
ErrorCode initialize ()
 
ErrorCode ray_fire (const EntityHandle volume, const double ray_start[3], const double ray_dir[3], EntityHandle &next_surf, double &next_surf_dist, RayHistory *history=NULL, double dist_limit=0, int ray_orientation=1, OrientedBoxTreeTool::TrvStats *stats=NULL)
 find the next surface crossing from a given point in a given direction More...
 
ErrorCode point_in_volume (const EntityHandle volume, const double xyz[3], int &result, const double *uvw=NULL, const RayHistory *history=NULL)
 Test if a point is inside or outside a volume. More...
 
ErrorCode point_in_volume_slow (const EntityHandle volume, const double xyz[3], int &result)
 Robust test if a point is inside or outside a volume using unit sphere area method. More...
 
ErrorCode find_volume (const double xyz[3], EntityHandle &volume, const double *dir=NULL)
 Find volume for a given location. More...
 
ErrorCode find_volume_slow (const double xyz[3], EntityHandle &volume, const double *dir=NULL)
 Find volume for a given location using loop. (slow) More...
 
ErrorCode point_in_box (const EntityHandle volume, const double point[3], int &inside)
 Test if a point is inside or outsize a volume's axis-aligned bounding box. More...
 
ErrorCode test_volume_boundary (const EntityHandle volume, const EntityHandle surface, const double xyz[3], const double uvw[3], int &result, const RayHistory *history=NULL)
 Given a ray starting at a surface of a volume, check whether the ray enters or exits the volume. More...
 
ErrorCode closest_to_location (EntityHandle volume, const double point[3], double &result, EntityHandle *closest_surface=0)
 Find the distance to the point on the boundary of the volume closest to the test point. More...
 
ErrorCode measure_volume (EntityHandle volume, double &result)
 
ErrorCode measure_area (EntityHandle surface, double &result)
 
ErrorCode get_normal (EntityHandle surf, const double xyz[3], double angle[3], const RayHistory *history=NULL)
 
void set_overlap_thickness (double new_overlap_thickness)
 State object used in calls to ray_fire() More...
 
void set_numerical_precision (double new_precision)
 
void set_verbosity (bool value)
 
bool get_verbosity () const
 
double get_numerical_precision ()
 
double get_overlap_thickness ()
 
GeomTopoToolgttool ()
 
Interfacemoab_instance ()
 

Private Member Functions

ErrorCode boundary_case (EntityHandle volume, int &result, double u, double v, double w, EntityHandle facet, EntityHandle surface)
 determine the point membership when the point is effectively on the boundary More...
 
ErrorCode poly_solid_angle (EntityHandle face, const CartVect &point, double &area)
 

Private Attributes

GeomTopoToolgeomTopoTool
 
bool verbose
 
bool owns_gtt
 
InterfaceMBI
 
OrientedBoxTreeToolobbTreeTool
 
bool counting
 
long long int n_pt_in_vol_calls
 
long long int n_ray_fire_calls
 
double overlapThickness
 
double numericalPrecision
 
Tag senseTag
 

Detailed Description

Tool for querying different aspects of geometric topology sets in MOAB.

Given the conventions established in GeomTopoTool for representing geometric topology through a hierarchy of meshsets, this tool provides a set of methods to query different geometric aspects of those geometric topology sets including:

  • measures of surface area and volume
  • distance to a bounding surface from a point within a volume
  • test the inclusion of a point within a volume
  • find the angle of a surface at a point

A feature of these queries is that there is some support for overlapping geometries.

Definition at line 45 of file GeomQueryTool.hpp.

Constructor & Destructor Documentation

◆ GeomQueryTool() [1/2]

moab::GeomQueryTool::GeomQueryTool ( Interface impl,
bool  find_geoments = false,
EntityHandle  modelRootSet = 0,
bool  p_rootSets_vector = true,
bool  restore_rootSets = true,
bool  trace_counting = false,
double  overlap_thickness = 0.,
double  numerical_precision = 0.001 
)

Definition at line 617 of file GeomQueryTool.cpp.

625  : verbose( false ), owns_gtt( true )
626 {
627  geomTopoTool = new GeomTopoTool( impl, find_geomsets, modelRootSet, p_rootSets_vector, restore_rootSets );
628 
630 
633 
634  counting = trace_counting;
635  overlapThickness = overlap_thickness;
636  numericalPrecision = numerical_precision;
637 
638  // reset query counters
639  n_pt_in_vol_calls = 0;
640  n_ray_fire_calls = 0;
641 }

References counting, geomTopoTool, moab::GeomTopoTool::get_moab_instance(), moab::GeomTopoTool::get_sense_tag(), MBI, n_pt_in_vol_calls, n_ray_fire_calls, numericalPrecision, moab::GeomTopoTool::obb_tree(), obbTreeTool, overlapThickness, and senseTag.

◆ GeomQueryTool() [2/2]

moab::GeomQueryTool::GeomQueryTool ( GeomTopoTool geomtopotool,
bool  trace_counting = false,
double  overlap_thickness = 0.,
double  numerical_precision = 0.001 
)

Definition at line 643 of file GeomQueryTool.cpp.

647  : verbose( false ), owns_gtt( false )
648 {
649 
650  geomTopoTool = geomtopotool;
651 
653 
656 
657  counting = trace_counting;
658  overlapThickness = overlap_thickness;
659  numericalPrecision = numerical_precision;
660 
661  // reset query counters
662  n_pt_in_vol_calls = 0;
663  n_ray_fire_calls = 0;
664 }

References counting, geomTopoTool, moab::GeomTopoTool::get_moab_instance(), moab::GeomTopoTool::get_sense_tag(), MBI, n_pt_in_vol_calls, n_ray_fire_calls, numericalPrecision, moab::GeomTopoTool::obb_tree(), obbTreeTool, overlapThickness, and senseTag.

◆ ~GeomQueryTool()

moab::GeomQueryTool::~GeomQueryTool ( )

Definition at line 666 of file GeomQueryTool.cpp.

667 {
668  if( owns_gtt )
669  {
670  delete geomTopoTool;
671  }
672 }

References geomTopoTool, and owns_gtt.

Member Function Documentation

◆ boundary_case()

ErrorCode moab::GeomQueryTool::boundary_case ( EntityHandle  volume,
int &  result,
double  u,
double  v,
double  w,
EntityHandle  facet,
EntityHandle  surface 
)
private

determine the point membership when the point is effectively on the boundary

Called by point_in_volume when the point is with tolerance of the boundary. Compares the ray direction with the surface normal to determine a volume membership.

Definition at line 1493 of file GeomQueryTool.cpp.

1500 {
1501  // test to see if uvw is provided
1502  if( u <= 1.0 && v <= 1.0 && w <= 1.0 )
1503  {
1504 
1505  const CartVect ray_vector( u, v, w );
1506  CartVect coords[3], normal( 0.0 );
1507  const EntityHandle* conn;
1508  int len, sense_out;
1509 
1510  MB_CHK_SET_ERR( MBI->get_connectivity( facet, conn, len ), "Failed to get the triangle's connectivity" );
1511  if( 3 != len )
1512  {
1513  MB_SET_ERR( MB_FAILURE, "Incorrect connectivity length for triangle" );
1514  }
1515 
1516  MB_CHK_SET_ERR( MBI->get_coords( conn, 3, coords[0].array() ), "Failed to get vertex coordinates" );
1517 
1518  MB_CHK_SET_ERR( geomTopoTool->get_sense( surface, volume, sense_out ),
1519  "Failed to get the surface's sense with respect to it's volume" );
1520 
1521  coords[1] -= coords[0];
1522  coords[2] -= coords[0];
1523  normal = sense_out * ( coords[1] * coords[2] );
1524 
1525  double sense = ray_vector % normal;
1526 
1527  if( sense < 0.0 )
1528  {
1529  result = 1; // inside or entering
1530  }
1531  else if( sense > 0.0 )
1532  {
1533  result = 0; // outside or leaving
1534  }
1535  else if( sense == 0.0 )
1536  {
1537  result = -1; // tangent, therefore on boundary
1538  }
1539  else
1540  {
1541  result = -1; // failure
1542  MB_SET_ERR( MB_FAILURE, "Failed to resolve boundary case" );
1543  }
1544 
1545  // if uvw not provided, return on_boundary.
1546  }
1547  else
1548  {
1549  result = -1; // on boundary
1550  return MB_SUCCESS;
1551  }
1552 
1553  return MB_SUCCESS;
1554 }

References moab::CartVect::array(), geomTopoTool, moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::GeomTopoTool::get_sense(), MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, and MBI.

Referenced by point_in_volume(), and test_volume_boundary().

◆ closest_to_location()

ErrorCode moab::GeomQueryTool::closest_to_location ( EntityHandle  volume,
const double  point[3],
double &  result,
EntityHandle closest_surface = 0 
)

Find the distance to the point on the boundary of the volume closest to the test point.

Parameters
volumeVolume to query
pointCoordinates of test point
resultSet to the minimum distance from point to a surface in volume

Definition at line 1309 of file GeomQueryTool.cpp.

1313 {
1314  // Get OBB Tree for volume
1315  EntityHandle root;
1316  MB_CHK_SET_ERR( geomTopoTool->get_root( volume, root ), "Failed to get the volume's obb tree root" );
1317 
1318  // Get closest triangles in volume
1319  const CartVect point( coords );
1320  CartVect nearest;
1321  EntityHandle facet_out;
1322 
1323  MB_CHK_SET_ERR( geomTopoTool->obb_tree()->closest_to_location( point.array(), root, nearest.array(), facet_out,
1324  closest_surface ),
1325  "Failed to get the closest intersection to location" );
1326  // calculate distance between point and nearest facet
1327  result = ( point - nearest ).length();
1328 
1329  return MB_SUCCESS;
1330 }

References moab::CartVect::array(), moab::OrientedBoxTreeTool::closest_to_location(), geomTopoTool, moab::GeomTopoTool::get_root(), length(), MB_CHK_SET_ERR, MB_SUCCESS, and moab::GeomTopoTool::obb_tree().

◆ find_volume()

ErrorCode moab::GeomQueryTool::find_volume ( const double  xyz[3],
EntityHandle volume,
const double *  dir = NULL 
)

Find volume for a given location.

Determines which volume contains the point if possible. If no volume is found, a null EntityHandle is returned along with a MB_ENTITY_NOT_FOUND ErrorCode.

Parameters
xyzThe location to test
volumeSet to volume handle containing the location if found
dirOptional direction to use for underlying ray fire query. Used to ensure consistent results when a ray direction is known. If NULL or {0,0,0} is given, a random direction will be used.

Definition at line 1173 of file GeomQueryTool.cpp.

1174 {
1175  volume = 0;
1176 
1177  EntityHandle global_surf_tree_root = geomTopoTool->get_one_vol_root();
1178 
1179  // fast check - make sure point is in the implicit complement bounding box
1180  int ic_result;
1181  EntityHandle ic_handle;
1183  "Failed to get the implicit complement handle" );
1184 
1185  MB_CHK_SET_ERR( point_in_box( ic_handle, xyz, ic_result ), "Failed to check implicit complement for containment" );
1186  if( ic_result == 0 )
1187  {
1188  volume = 0;
1189  return MB_ENTITY_NOT_FOUND;
1190  }
1191 
1192  // if geomTopoTool doesn't have a global tree, use a loop over vols (slow)
1193  if( !global_surf_tree_root )
1194  {
1195  return find_volume_slow( xyz, volume, dir );
1196  }
1197 
1198  moab::CartVect uvw( 0.0 );
1199 
1200  if( dir )
1201  {
1202  uvw[0] = dir[0];
1203  uvw[1] = dir[1];
1204  uvw[2] = dir[2];
1205  }
1206 
1207  if( uvw == 0.0 )
1208  {
1209  uvw[0] = rand();
1210  uvw[1] = rand();
1211  uvw[2] = rand();
1212  }
1213 
1214  // always normalize direction
1215  uvw.normalize();
1216 
1217  // fire a ray along dir and get surface
1218  const double huge_val = std::numeric_limits< double >::max();
1219  double pos_ray_len = huge_val;
1220  double neg_ray_len = -huge_val;
1221 
1222  // RIS output data
1223  std::vector< double > dists;
1224  std::vector< EntityHandle > surfs;
1225  std::vector< EntityHandle > facets;
1226 
1227  FindVolumeIntRegCtxt find_vol_reg_ctxt;
1228  OrientedBoxTreeTool::IntersectSearchWindow search_win( &pos_ray_len, &neg_ray_len );
1229  MB_CHK_SET_ERR( geomTopoTool->obb_tree()->ray_intersect_sets( dists, surfs, facets, global_surf_tree_root,
1230  numericalPrecision, xyz, uvw.array(), search_win,
1231  find_vol_reg_ctxt ),
1232  "Failed in global tree ray fire" );
1233 
1234  // if there was no intersection, no volume is found
1235  if( surfs.size() == 0 || surfs[0] == 0 )
1236  {
1237  volume = 0;
1238  return MB_ENTITY_NOT_FOUND;
1239  }
1240 
1241  // get the positive distance facet, surface hit
1242  EntityHandle facet = facets[0];
1243  EntityHandle surf = surfs[0];
1244 
1245  // get these now, we're going to use them no matter what
1246  EntityHandle fwd_vol, bwd_vol;
1247  MB_CHK_SET_ERR( geomTopoTool->get_surface_senses( surf, fwd_vol, bwd_vol ), "Failed to get sense data" );
1248 
1249  // define parent volumes
1250  EntityHandle parent_vols[2];
1251  parent_vols[0] = fwd_vol;
1252  parent_vols[1] = bwd_vol;
1253 
1254  // get triangle normal
1255  std::vector< EntityHandle > conn;
1256  CartVect coords[3];
1257  MB_CHK_SET_ERR( MBI->get_connectivity( &facet, 1, conn ), "Failed to get triangle connectivity" );
1258 
1259  MB_CHK_SET_ERR( MBI->get_coords( &conn[0], 3, coords[0].array() ), "Failed to get triangle coordinates" );
1260 
1261  CartVect normal = ( coords[1] - coords[0] ) * ( coords[2] - coords[0] );
1262  normal.normalize();
1263 
1264  // reverse direction if a hit in the negative direction is found
1265  if( dists[0] < 0 )
1266  {
1267  uvw *= -1;
1268  }
1269 
1270  // if this is a "forward" intersection return the first sense entity
1271  // otherwise return the second, "reverse" sense entity
1272  double dot_prod = uvw % normal;
1273  int idx = dot_prod > 0.0 ? 0 : 1;
1274 
1275  if( dot_prod == 0.0 )
1276  {
1277  std::cerr << "Tangent dot product in find_volume. Shouldn't be here." << std::endl;
1278  volume = 0;
1279  return MB_FAILURE;
1280  }
1281 
1282  volume = parent_vols[idx];
1283 
1284  return MB_SUCCESS;
1285 }

References moab::CartVect::array(), find_volume_slow(), geomTopoTool, moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::GeomTopoTool::get_implicit_complement(), moab::GeomTopoTool::get_one_vol_root(), moab::GeomTopoTool::get_surface_senses(), MB_CHK_SET_ERR, MB_ENTITY_NOT_FOUND, MB_SUCCESS, MBI, moab::CartVect::normalize(), numericalPrecision, moab::GeomTopoTool::obb_tree(), point_in_box(), and moab::OrientedBoxTreeTool::ray_intersect_sets().

◆ find_volume_slow()

ErrorCode moab::GeomQueryTool::find_volume_slow ( const double  xyz[3],
EntityHandle volume,
const double *  dir = NULL 
)

Find volume for a given location using loop. (slow)

Loops over all volumes in the model, checking for point containment

Parameters
xyzThe location to test
volumeSet to volume handle containing the location if found
dirOptional direction to use for underlying ray fire query. Used to ensure consistent results when a ray direction is known. If NULL or {0,0,0} is given, a random direction will be used.

Definition at line 1287 of file GeomQueryTool.cpp.

1288 {
1289  volume = 0;
1290  // get all volumes
1291  Range all_vols;
1292  MB_CHK_SET_ERR( geomTopoTool->get_gsets_by_dimension( 3, all_vols ), "Failed to get all volumes in the model" );
1293 
1294  Range::iterator it;
1295  int result = 0;
1296  for( it = all_vols.begin(); it != all_vols.end(); it++ )
1297  {
1298  MB_CHK_SET_ERR( point_in_volume( *it, xyz, result, dir ), "Failed in point in volume loop" );
1299  if( result )
1300  {
1301  volume = *it;
1302  break;
1303  }
1304  }
1305  return volume ? MB_SUCCESS : MB_ENTITY_NOT_FOUND;
1306 }

References moab::Range::begin(), moab::Range::end(), geomTopoTool, moab::GeomTopoTool::get_gsets_by_dimension(), MB_CHK_SET_ERR, MB_ENTITY_NOT_FOUND, MB_SUCCESS, and point_in_volume().

Referenced by find_volume().

◆ get_normal()

ErrorCode moab::GeomQueryTool::get_normal ( EntityHandle  surf,
const double  xyz[3],
double  angle[3],
const RayHistory history = NULL 
)

Get the normal to a given surface at the point on the surface closest to a given point

This method first identifies which facet contains this point and then calculates the unit outward normal of that facet. The facet of the provided volume that is nearest the provided point is used for this calculation. The search for that facet can be circumvented by providing a RayHistory, in which case the last facet of the history will be used.

Parameters
surfSurface on which to get normal
xyzPoint on surf
angleSet to coordinates of surface normal nearest xyz
historyOptional ray history from a previous call to ray_fire(). If present and non-empty, return the normal of the most recently intersected facet, ignoring xyz.

Definition at line 1440 of file GeomQueryTool.cpp.

1444 {
1445  EntityHandle root;
1446  MB_CHK_SET_ERR( geomTopoTool->get_root( surf, root ), "Failed to get the surface's obb tree root" );
1447 
1448  std::vector< EntityHandle > facets;
1449 
1450  // if no history or history empty, use nearby facets
1451  if( !history || ( history->prev_facets.size() == 0 ) )
1452  {
1454  "Failed to get closest intersection to location" );
1455  }
1456  // otherwise use most recent facet in history
1457  else
1458  {
1459  facets.push_back( history->prev_facets.back() );
1460  }
1461 
1462  CartVect coords[3], normal( 0.0 );
1463  const EntityHandle* conn;
1464  int len;
1465  for( unsigned i = 0; i < facets.size(); ++i )
1466  {
1467  MB_CHK_SET_ERR( MBI->get_connectivity( facets[i], conn, len ), "Failed to get facet connectivity" );
1468  if( 3 != len )
1469  {
1470  MB_SET_ERR( MB_FAILURE, "Incorrect connectivity length for triangle" );
1471  }
1472 
1473  MB_CHK_SET_ERR( MBI->get_coords( conn, 3, coords[0].array() ), "Failed to get vertex coordinates" );
1474 
1475  coords[1] -= coords[0];
1476  coords[2] -= coords[0];
1477  normal += coords[1] * coords[2];
1478  }
1479 
1480  normal.normalize();
1481  normal.get( angle );
1482 
1483  return MB_SUCCESS;
1484 }

References moab::angle(), moab::CartVect::array(), moab::OrientedBoxTreeTool::closest_to_location(), geomTopoTool, moab::CartVect::get(), moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::GeomTopoTool::get_root(), MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, MBI, moab::CartVect::normalize(), numericalPrecision, moab::GeomTopoTool::obb_tree(), and moab::GeomQueryTool::RayHistory::prev_facets.

◆ get_numerical_precision()

double moab::GeomQueryTool::get_numerical_precision ( )
inline

Definition at line 376 of file GeomQueryTool.hpp.

377  {
378  return numericalPrecision;
379  }

References numericalPrecision.

◆ get_overlap_thickness()

double moab::GeomQueryTool::get_overlap_thickness ( )
inline

Definition at line 381 of file GeomQueryTool.hpp.

382  {
383  return overlapThickness;
384  }

References overlapThickness.

◆ get_verbosity()

bool moab::GeomQueryTool::get_verbosity ( ) const
inline

Definition at line 371 of file GeomQueryTool.hpp.

372  {
373  return verbose;
374  }

References verbose.

◆ gttool()

GeomTopoTool* moab::GeomQueryTool::gttool ( )
inline

Definition at line 386 of file GeomQueryTool.hpp.

387  {
388  return geomTopoTool;
389  }

References geomTopoTool.

◆ initialize()

ErrorCode moab::GeomQueryTool::initialize ( )

Definition at line 674 of file GeomQueryTool.cpp.

675 {
676  MB_CHK_SET_ERR( geomTopoTool->find_geomsets(), "Failed to find geometry sets" );
677 
678  MB_CHK_SET_ERR( geomTopoTool->setup_implicit_complement(), "Couldn't setup the implicit complement" );
679 
680  MB_CHK_SET_ERR( geomTopoTool->construct_obb_trees(), "Failed to construct OBB trees" );
681 
682  return MB_SUCCESS;
683 }

References moab::GeomTopoTool::construct_obb_trees(), moab::GeomTopoTool::find_geomsets(), geomTopoTool, MB_CHK_SET_ERR, MB_SUCCESS, and moab::GeomTopoTool::setup_implicit_complement().

◆ measure_area()

ErrorCode moab::GeomQueryTool::measure_area ( EntityHandle  surface,
double &  result 
)

Calculate sum of area of triangles

Definition at line 1400 of file GeomQueryTool.cpp.

1401 {
1402  // get triangles in surface
1403  Range triangles;
1404  MB_CHK_SET_ERR( MBI->get_entities_by_dimension( surface, 2, triangles ), "Failed to get the surface entities" );
1405  if( !triangles.all_of_type( MBTRI ) )
1406  {
1407  std::cout << "WARNING: Surface " << surface // todo: use geomtopotool to get id by entity handle
1408  << " contains non-triangle elements. Area calculation may be incorrect." << std::endl;
1409  triangles.clear();
1410  MB_CHK_SET_ERR( MBI->get_entities_by_type( surface, MBTRI, triangles ),
1411  "Failed to the surface's triangle entities" );
1412  }
1413 
1414  // calculate sum of area of triangles
1415  result = 0.0;
1416  const EntityHandle* conn;
1417  int len;
1418  CartVect coords[3];
1419  for( Range::iterator j = triangles.begin(); j != triangles.end(); ++j )
1420  {
1421  MB_CHK_SET_ERR( MBI->get_connectivity( *j, conn, len, true ),
1422  "Failed to get the current triangle's connectivity" );
1423  if( 3 != len )
1424  {
1425  MB_SET_ERR( MB_FAILURE, "Incorrect connectivity length for triangle" );
1426  }
1427  MB_CHK_SET_ERR( MBI->get_coords( conn, 3, coords[0].array() ),
1428  "Failed to get the current triangle's vertex coordinates" );
1429 
1430  // calculated area using cross product of triangle edges
1431  CartVect v1 = coords[1] - coords[0];
1432  CartVect v2 = coords[2] - coords[0];
1433  CartVect xp = v1 * v2;
1434  result += xp.length();
1435  }
1436  result *= 0.5;
1437  return MB_SUCCESS;
1438 }

References moab::Range::all_of_type(), moab::CartVect::array(), moab::Range::begin(), moab::Range::clear(), moab::Range::end(), moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::Interface::get_entities_by_dimension(), moab::Interface::get_entities_by_type(), moab::CartVect::length(), MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, MBI, and MBTRI.

◆ measure_volume()

ErrorCode moab::GeomQueryTool::measure_volume ( EntityHandle  volume,
double &  result 
)

Calculate the volume contained in a 'volume'

Definition at line 1333 of file GeomQueryTool.cpp.

1334 {
1335  std::vector< EntityHandle > surfaces;
1336  result = 0.0;
1337 
1338  // don't try to calculate volume of implicit complement
1339  if( geomTopoTool->is_implicit_complement( volume ) )
1340  {
1341  result = 1.0;
1342  return MB_SUCCESS;
1343  }
1344 
1345  // get surfaces from volume
1346  MB_CHK_SET_ERR( MBI->get_child_meshsets( volume, surfaces ), "Failed to get the volume's child surfaces" );
1347 
1348  // get surface senses
1349  std::vector< int > senses( surfaces.size() );
1350  MB_CHK_SET_ERR( geomTopoTool->get_surface_senses( volume, surfaces.size(), &surfaces[0], &senses[0] ),
1351  "Failed to retrieve surface-volume sense data. Cannot calculate volume" );
1352 
1353  for( unsigned i = 0; i < surfaces.size(); ++i )
1354  {
1355  // skip non-manifold surfaces
1356  if( !senses[i] ) continue;
1357 
1358  // get triangles in surface
1359  Range triangles;
1360  MB_CHK_SET_ERR( MBI->get_entities_by_dimension( surfaces[i], 2, triangles ),
1361  "Failed to get the surface triangles" );
1362 
1363  if( !triangles.all_of_type( MBTRI ) )
1364  {
1365  std::cout << "WARNING: Surface " << surfaces[i] // todo: use geomtopotool to get id by entity handle
1366  << " contains non-triangle elements. Volume calculation may be incorrect." << std::endl;
1367  triangles.clear();
1368  MB_CHK_SET_ERR( MBI->get_entities_by_type( surfaces[i], MBTRI, triangles ),
1369  "Failed to get the surface triangles" );
1370  }
1371 
1372  // calculate signed volume beneath surface (x 6.0)
1373  double surf_sum = 0.0;
1374  const EntityHandle* conn;
1375  int len;
1376  CartVect coords[3];
1377  for( Range::iterator j = triangles.begin(); j != triangles.end(); ++j )
1378  {
1379  MB_CHK_SET_ERR( MBI->get_connectivity( *j, conn, len, true ),
1380  "Failed to get the connectivity of the current triangle" );
1381  if( 3 != len )
1382  {
1383  MB_SET_ERR( MB_FAILURE, "Incorrect connectivity length for triangle" );
1384  }
1385  MB_CHK_SET_ERR( MBI->get_coords( conn, 3, coords[0].array() ),
1386  "Failed to get the coordinates of the current triangle's vertices" );
1387 
1388  coords[1] -= coords[0];
1389  coords[2] -= coords[0];
1390  surf_sum += ( coords[0] % ( coords[1] * coords[2] ) );
1391  }
1392  result += senses[i] * surf_sum;
1393  }
1394 
1395  result /= 6.0;
1396  return MB_SUCCESS;
1397 }

References moab::Range::all_of_type(), moab::CartVect::array(), moab::Range::begin(), moab::Range::clear(), moab::Range::end(), geomTopoTool, moab::Interface::get_child_meshsets(), moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::Interface::get_entities_by_dimension(), moab::Interface::get_entities_by_type(), moab::GeomTopoTool::get_surface_senses(), moab::GeomTopoTool::is_implicit_complement(), MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, MBI, and MBTRI.

◆ moab_instance()

Interface* moab::GeomQueryTool::moab_instance ( )
inline

Definition at line 391 of file GeomQueryTool.hpp.

392  {
393  return MBI;
394  }

References MBI.

◆ point_in_box()

ErrorCode moab::GeomQueryTool::point_in_box ( const EntityHandle  volume,
const double  point[3],
int &  inside 
)

Test if a point is inside or outsize a volume's axis-aligned bounding box.

For the volume pointed to and the point wished to be tested, returns whether the point is inside or outside the bounding box of the volume. inside = 0, not inside, inside = 1, inside.

This is used as a fast way to determine whether a point is inside or outside of a volume before performing a point_in_volume test which involves firing a ray.

Parameters
volumeThe volume to test
pointThe location to test for bounding box containment
insideset to 0 if point is outside the box, 1 if inside

Definition at line 1068 of file GeomQueryTool.cpp.

1069 {
1070  double minpt[3];
1071  double maxpt[3];
1072  MB_CHK_SET_ERR( geomTopoTool->get_bounding_coords( volume, minpt, maxpt ),
1073  "Failed to get the bounding coordinates of the volume" );
1074 
1075  // early exits
1076  if( point[0] > maxpt[0] || point[0] < minpt[0] )
1077  {
1078  inside = 0;
1079  return MB_SUCCESS;
1080  }
1081  if( point[1] > maxpt[1] || point[1] < minpt[1] )
1082  {
1083  inside = 0;
1084  return MB_SUCCESS;
1085  }
1086  if( point[2] > maxpt[2] || point[2] < minpt[2] )
1087  {
1088  inside = 0;
1089  return MB_SUCCESS;
1090  }
1091  inside = 1;
1092  return MB_SUCCESS;
1093 }

References geomTopoTool, moab::GeomTopoTool::get_bounding_coords(), MB_CHK_SET_ERR, and MB_SUCCESS.

Referenced by find_volume(), and point_in_volume().

◆ point_in_volume()

ErrorCode moab::GeomQueryTool::point_in_volume ( const EntityHandle  volume,
const double  xyz[3],
int &  result,
const double *  uvw = NULL,
const RayHistory history = NULL 
)

Test if a point is inside or outside a volume.

This method finds the point on the boundary of the volume that is nearest the test point (x,y,z). If that point is "close" to a surface, a boundary test is performed based on the normal of the surface at that point and the optional ray direction (u,v,w).

Parameters
volumeThe volume to test
xyzThe location to test for volume containment
resultSet to 0 if xyz it outside volume, 1 if inside, and -1 if on boundary.
Optionaldirection to use for underlying ray fire query. Used to ensure consistent results when a ray direction is known. If NULL or {0,0,0} is given, a random direction will be used.
historyOptional RayHistory object to pass to underlying ray fire query. The history is not modified by this call.

Definition at line 904 of file GeomQueryTool.cpp.

909 {
910  // take some stats that are independent of nps
911  if( counting ) ++n_pt_in_vol_calls;
912 
913  // early fail for piv - see if point inside the root level obb
914  // if its not even in the box dont bother doing anything else
915  MB_CHK_SET_ERR( point_in_box( volume, xyz, result ), "failed to query point in box" );
916  if( !result )
917  {
918  result = 0;
919  return MB_SUCCESS;
920  }
921 
922  // get OBB Tree for volume
923  EntityHandle root;
924  MB_CHK_SET_ERR( geomTopoTool->get_root( volume, root ), "Failed to find the volume's obb tree root" );
925 
926  // Don't recreate these every call. These cannot be the same as the ray_fire
927  // vectors because both are used simultaneously.
928  std::vector< double > dists;
929  std::vector< EntityHandle > surfs;
930  std::vector< EntityHandle > facets;
931  std::vector< int > dirs;
932 
933  // if uvw is not given or is full of zeros, use a random direction
934  double u = 0, v = 0, w = 0;
935 
936  if( uvw )
937  {
938  u = uvw[0];
939  v = uvw[1], w = uvw[2];
940  }
941 
942  if( u == 0 && v == 0 && w == 0 )
943  {
944  u = rand();
945  v = rand();
946  w = rand();
947  const double magnitude = sqrt( u * u + v * v + w * w );
948  u /= magnitude;
949  v /= magnitude;
950  w /= magnitude;
951  }
952 
953  const double ray_direction[] = { u, v, w };
954 
955  // if overlaps, ray must be cast to infinity and all RTIs must be returned
956  const double large = 1e15;
957  double ray_length = large;
958 
959  // If overlaps occur, the pt is inside if traveling along the ray from the
960  // origin, there are ever more exits than entrances. In lieu of implementing
961  // that, all intersections to infinity are required if overlaps occur (expensive)
962  int min_tolerance_intersections;
963  if( 0 != overlapThickness )
964  {
965  min_tolerance_intersections = -1;
966  // only the first intersection is needed if overlaps do not occur (cheap)
967  }
968  else
969  {
970  min_tolerance_intersections = 1;
971  }
972 
973  // Get intersection(s) of forward and reverse orientation. Do not return
974  // glancing intersections or previous facets.
975  GQT_IntRegCtxt int_reg_ctxt( geomTopoTool->obb_tree(), xyz, ray_direction, numericalPrecision,
976  min_tolerance_intersections, &root, &volume, &senseTag, NULL,
977  history ? &( history->prev_facets ) : NULL );
978 
979  OrientedBoxTreeTool::IntersectSearchWindow search_win( &ray_length, (double*)NULL );
980  MB_CHK_SET_ERR( geomTopoTool->obb_tree()->ray_intersect_sets( dists, surfs, facets, root, numericalPrecision, xyz,
981  ray_direction, search_win, int_reg_ctxt ),
982  "Ray fire query failed" );
983 
984  // determine orientation of all intersections
985  // 1 for entering, 0 for leaving, -1 for tangent
986  // Tangent intersections are not returned from ray_tri_intersect.
987  dirs.resize( dists.size() );
988  for( unsigned i = 0; i < dists.size(); ++i )
989  {
990  MB_CHK_SET_ERR( boundary_case( volume, dirs[i], u, v, w, facets[i], surfs[i] ),
991  "Failed to resolve boundary case" );
992  }
993 
994  // count all crossings
995  if( 0 != overlapThickness )
996  {
997  int sum = 0;
998  for( unsigned i = 0; i < dirs.size(); ++i )
999  {
1000  if( 1 == dirs[i] )
1001  sum += 1; // +1 for entering
1002  else if( 0 == dirs[i] )
1003  sum -= 1; // -1 for leaving
1004  else if( -1 == dirs[i] )
1005  { // 0 for tangent
1006  std::cout << "direction==tangent" << std::endl;
1007  sum += 0;
1008  }
1009  else
1010  {
1011  MB_SET_ERR( MB_FAILURE, "Error: unknown direction" );
1012  }
1013  }
1014 
1015  // inside/outside depends on the sum
1016  if( 0 < sum )
1017  result = 0; // pt is outside (for all vols)
1018  else if( 0 > sum )
1019  result = 1; // pt is inside (for all vols)
1020  else if( geomTopoTool->is_implicit_complement( volume ) )
1021  result = 1; // pt is inside (for impl_compl_vol)
1022  else
1023  result = 0; // pt is outside (for all other vols)
1024 
1025  // Only use the first crossing
1026  }
1027  else
1028  {
1029  if( dirs.empty() )
1030  {
1031  result = 0; // pt is outside
1032  }
1033  else
1034  {
1035  int smallest = std::min_element( dists.begin(), dists.end() ) - dists.begin();
1036  if( 1 == dirs[smallest] )
1037  result = 0; // pt is outside
1038  else if( 0 == dirs[smallest] )
1039  result = 1; // pt is inside
1040  else if( -1 == dirs[smallest] )
1041  {
1042  // Should not be here because Plucker ray-triangle test does not
1043  // return coplanar rays as intersections.
1044  std::cerr << "direction==tangent" << std::endl;
1045  result = -1;
1046  }
1047  else
1048  {
1049  MB_SET_ERR( MB_FAILURE, "Error: unknown direction" );
1050  }
1051  }
1052  }
1053 
1054 #ifdef MB_GQT_DEBUG
1055  std::cout << "pt_in_vol: result=" << result << " xyz=" << xyz[0] << " " << xyz[1] << " " << xyz[2] << " uvw=" << u
1056  << " " << v << " " << w << " vol_id=" << volume
1057  << std::endl; // todo: use geomtopotool to get id by entity handle
1058 #endif
1059 
1060  return MB_SUCCESS;
1061 }

References boundary_case(), counting, geomTopoTool, moab::GeomTopoTool::get_root(), moab::GeomTopoTool::is_implicit_complement(), MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, n_pt_in_vol_calls, numericalPrecision, moab::GeomTopoTool::obb_tree(), overlapThickness, point_in_box(), moab::GeomQueryTool::RayHistory::prev_facets, moab::OrientedBoxTreeTool::ray_intersect_sets(), senseTag, and moab::sum().

Referenced by moab::GeomTopoTool::A_is_in_B(), find_volume_slow(), and ray_fire().

◆ point_in_volume_slow()

ErrorCode moab::GeomQueryTool::point_in_volume_slow ( const EntityHandle  volume,
const double  xyz[3],
int &  result 
)

Robust test if a point is inside or outside a volume using unit sphere area method.

This test may be more robust that the standard point_in_volume, but is much slower. It does not detect 'on boundary' situations as point_in_volume does.

Parameters
volumeThe volume to test
xyzThe location to test for volume containment
resultSet to 0 if xyz it outside volume, 1 if inside.

Definition at line 1135 of file GeomQueryTool.cpp.

1136 {
1137  Range faces;
1138  std::vector< EntityHandle > surfs;
1139  std::vector< int > senses;
1140  double sum = 0.0;
1141  const CartVect point( xyz );
1142 
1143  MB_CHK_SET_ERR( MBI->get_child_meshsets( volume, surfs ), "Failed to get the volume's child surfaces" );
1144 
1145  senses.resize( surfs.size() );
1146  MB_CHK_SET_ERR( geomTopoTool->get_surface_senses( volume, surfs.size(), &surfs[0], &senses[0] ),
1147  "Failed to get the volume's surface senses" );
1148 
1149  for( unsigned i = 0; i < surfs.size(); ++i )
1150  {
1151  if( !senses[i] ) // skip non-manifold surfaces
1152  continue;
1153 
1154  double surf_area = 0.0, face_area;
1155  faces.clear();
1156  MB_CHK_SET_ERR( MBI->get_entities_by_dimension( surfs[i], 2, faces ),
1157  "Failed to get the surface entities by dimension" );
1158 
1159  for( Range::iterator j = faces.begin(); j != faces.end(); ++j )
1160  {
1161  MB_CHK_SET_ERR( poly_solid_angle( *j, point, face_area ), "Failed to determin the polygon's solid angle" );
1162 
1163  surf_area += face_area;
1164  }
1165 
1166  sum += senses[i] * surf_area;
1167  }
1168 
1169  result = fabs( sum ) > 2.0 * M_PI;
1170  return MB_SUCCESS;
1171 }

References moab::Range::begin(), moab::Range::clear(), moab::Range::end(), geomTopoTool, moab::Interface::get_child_meshsets(), moab::Interface::get_entities_by_dimension(), moab::GeomTopoTool::get_surface_senses(), MB_CHK_SET_ERR, MB_SUCCESS, MBI, poly_solid_angle(), and moab::sum().

◆ poly_solid_angle()

ErrorCode moab::GeomQueryTool::poly_solid_angle ( EntityHandle  face,
const CartVect point,
double &  area 
)
private

get the solid angle projected by a facet on a unit sphere around a point

  • used by point_in_volume_slow

Definition at line 1564 of file GeomQueryTool.cpp.

1565 {
1566  // Get connectivity
1567  const EntityHandle* conn;
1568  int len;
1569  MB_CHK_SET_ERR( MBI->get_connectivity( face, conn, len, true ), "Failed to get the connectivity of the polygon" );
1570 
1571  // Allocate space to store vertices
1572  CartVect coords_static[4];
1573  std::vector< CartVect > coords_dynamic;
1574  CartVect* coords = coords_static;
1575  if( (unsigned)len > ( sizeof( coords_static ) / sizeof( coords_static[0] ) ) )
1576  {
1577  coords_dynamic.resize( len );
1578  coords = &coords_dynamic[0];
1579  }
1580 
1581  // get coordinates
1582  MB_CHK_SET_ERR( MBI->get_coords( conn, len, coords->array() ),
1583  "Failed to get the coordinates of the polygon vertices" );
1584 
1585  // calculate normal
1586  CartVect norm( 0.0 ), v1, v0 = coords[1] - coords[0];
1587  for( int i = 2; i < len; ++i )
1588  {
1589  v1 = coords[i] - coords[0];
1590  norm += v0 * v1;
1591  v0 = v1;
1592  }
1593 
1594  // calculate area
1595  double s, ang;
1596  area = 0.0;
1597  CartVect r, n1, n2, b, a = coords[len - 1] - coords[0];
1598  for( int i = 0; i < len; ++i )
1599  {
1600  r = coords[i] - point;
1601  b = coords[( i + 1 ) % len] - coords[i];
1602  n1 = a * r; // = norm1 (magnitude is important)
1603  n2 = r * b; // = norm2 (magnitude is important)
1604  s = ( n1 % n2 ) / ( n1.length() * n2.length() ); // = cos(angle between norm1,norm2)
1605  ang = s <= -1.0 ? M_PI : s >= 1.0 ? 0.0 : acos( s ); // = acos(s)
1606  s = ( b * a ) % norm; // =orientation of triangle wrt point
1607  area += s > 0.0 ? M_PI - ang : M_PI + ang;
1608  a = -b;
1609  }
1610 
1611  area -= M_PI * ( len - 2 );
1612  if( ( norm % r ) > 0 ) area = -area;
1613  return MB_SUCCESS;
1614 }

References moab::CartVect::array(), moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::CartVect::length(), MB_CHK_SET_ERR, MB_SUCCESS, and MBI.

Referenced by point_in_volume_slow().

◆ ray_fire()

ErrorCode moab::GeomQueryTool::ray_fire ( const EntityHandle  volume,
const double  ray_start[3],
const double  ray_dir[3],
EntityHandle next_surf,
double &  next_surf_dist,
RayHistory history = NULL,
double  dist_limit = 0,
int  ray_orientation = 1,
OrientedBoxTreeTool::TrvStats stats = NULL 
)

find the next surface crossing from a given point in a given direction

This is the primary method to enable ray tracing through a geometry. Given a volume and a ray, it determines the distance to the nearest intersection with a bounding surface of that volume and returns that distance and the EntityHandle indicating on which surface that intersection occurs. The caller can compute the location of the intersection by adding the distance to the ray.

When a series of calls to this function are made along the same ray (e.g. for the purpose of tracking a ray through several volumes), the optional history argument should be given. The history prevents previously intersected facets from being intersected again. A single history should be used as long as a ray is proceeding forward without changing direction. This situation is sometimes referred to as "streaming."

If a ray changes direction at an intersection site, the caller should call reset_to_last_intersection() on the history object before the next ray fire.

Parameters
volumeThe volume at which to fire the ray
ray_startAn array of x,y,z coordinates from which to start the ray.
ray_dirAn array of x,y,z coordinates indicating the direction of the ray. Must be of unit length.
next_surfOutput parameter indicating the next surface intersected by the ray. If no intersection is found, will be set to 0.
next_surf_distOutput parameter indicating distance to next_surf. If next_surf is 0, this value is undefined and should not be used.
historyOptional RayHistory object. If provided, the facets in the history are assumed to not intersect with the given ray. The facet intersected by this query will also be added to the history.
dist_limitOptional distance limit. If provided and > 0, no intersections at a distance further than this value will be returned.
ray_orientationOptional ray orientation. If provided determines intersections along the normal provided, e.g. if -1 allows intersections back along the the ray direction, Default is 1, i.e. exit intersections
statsOptional TrvStats object used to measure performance of underlying OBB ray-firing query. See OrientedBoxTreeTool.hpp for details.

Definition at line 728 of file GeomQueryTool.cpp.

737 {
738 
739  // take some stats that are independent of nps
740  if( counting )
741  {
743  if( 0 == n_ray_fire_calls % 10000000 )
744  {
745  std::cout << "n_ray_fires=" << n_ray_fire_calls << " n_pt_in_vols=" << n_pt_in_vol_calls << std::endl;
746  }
747  }
748 
749 #ifdef MB_GQT_DEBUG
750  std::cout << "ray_fire:"
751  << " xyz=" << point[0] << " " << point[1] << " " << point[2] << " uvw=" << dir[0] << " " << dir[1] << " "
752  << dir[2] << " entity_handle=" << volume << std::endl;
753 #endif
754 
755  const double huge_val = std::numeric_limits< double >::max();
756  double dist_limit = huge_val;
757  if( user_dist_limit > 0 ) dist_limit = user_dist_limit;
758 
759  // don't recreate these every call
760  std::vector< double > dists;
761  std::vector< EntityHandle > surfs;
762  std::vector< EntityHandle > facets;
763 
764  EntityHandle root;
765  MB_CHK_SET_ERR( geomTopoTool->get_root( volume, root ), "Failed to get the obb tree root of the volume" );
766 
767  // check behind the ray origin for intersections
768  double neg_ray_len;
769  if( 0 == overlapThickness )
770  {
771  neg_ray_len = -numericalPrecision;
772  }
773  else
774  {
775  neg_ray_len = -overlapThickness;
776  }
777 
778  // optionally, limit the nonneg_ray_len with the distance to next collision.
779  double nonneg_ray_len = dist_limit;
780 
781  // the nonneg_ray_len should not be less than -neg_ray_len, or an overlap
782  // may be missed due to optimization within ray_intersect_sets
783  if( nonneg_ray_len < -neg_ray_len ) nonneg_ray_len = -neg_ray_len;
784  if( 0 > nonneg_ray_len || 0 <= neg_ray_len )
785  {
786  MB_SET_ERR( MB_FAILURE, "Incorrect ray length provided" );
787  }
788 
789  // min_tolerance_intersections is passed but not used in this call
790  const int min_tolerance_intersections = 0;
791 
792  // numericalPrecision is used for box.intersect_ray and find triangles in the
793  // neighborhood of edge/node intersections.
794  GQT_IntRegCtxt int_reg_ctxt( geomTopoTool->obb_tree(), point, dir, numericalPrecision, min_tolerance_intersections,
795  &root, &volume, &senseTag, &ray_orientation,
796  history ? &( history->prev_facets ) : NULL );
797 
798  OrientedBoxTreeTool::IntersectSearchWindow search_win( &nonneg_ray_len, &neg_ray_len );
799  MB_CHK_SET_ERR( geomTopoTool->obb_tree()->ray_intersect_sets( dists, surfs, facets, root, numericalPrecision, point,
800  dir, search_win, int_reg_ctxt, stats ),
801  "Ray query failed" );
802 
803  // If no distances are returned, the particle is lost unless the physics limit
804  // is being used. If the physics limit is being used, there is no way to tell
805  // if the particle is lost. To avoid ambiguity, DO NOT use the distance limit
806  // unless you know lost particles do not occur.
807  if( dists.empty() )
808  {
809  next_surf = 0;
810 #ifdef MB_GQT_DEBUG
811  std::cout << " next_surf=0 dist=(undef)" << std::endl;
812 #endif
813  return MB_SUCCESS;
814  }
815 
816  // Assume that a (neg, nonneg) pair of RTIs could be returned,
817  // however, only one or the other may exist. dists[] may be populated, but
818  // intersections are ONLY indicated by nonzero surfs[] and facets[].
819  if( 2 != dists.size() || 2 != facets.size() )
820  {
821  MB_SET_ERR( MB_FAILURE, "Incorrect number of facets/distances" );
822  }
823  if( 0.0 < dists[0] || 0.0 > dists[1] )
824  {
825  MB_SET_ERR( MB_FAILURE, "Invalid intersection distance signs" );
826  }
827 
828  // If both negative and nonnegative RTIs are returned, the negative RTI must
829  // closer to the origin.
830  if( ( 0 != facets[0] && 0 != facets[1] ) && ( -dists[0] > dists[1] ) )
831  {
832  MB_SET_ERR( MB_FAILURE, "Invalid intersection distance values" );
833  }
834 
835  // If an RTI is found at negative distance, perform a PMT to see if the
836  // particle is inside an overlap.
837  int exit_idx = -1;
838  if( 0 != facets[0] )
839  {
840  // get the next volume
841  std::vector< EntityHandle > vols;
842  EntityHandle nx_vol;
843  MB_CHK_SET_ERR( MBI->get_parent_meshsets( surfs[0], vols ), "Failed to get the parent meshsets" );
844  if( 2 != vols.size() )
845  {
846  MB_SET_ERR( MB_FAILURE, "Invaid number of parent volumes found" );
847  }
848  if( vols.front() == volume )
849  {
850  nx_vol = vols.back();
851  }
852  else
853  {
854  nx_vol = vols.front();
855  }
856  // Check to see if the point is actually in the next volume.
857  // The list of previous facets is used to topologically identify the
858  // "on_boundary" result of the PMT. This avoids a test that uses proximity
859  // (a tolerance).
860  int result;
861  MB_CHK_SET_ERR( point_in_volume( nx_vol, point, result, dir, history ), "Point in volume query failed" );
862  if( 1 == result ) exit_idx = 0;
863  }
864 
865  // if the negative distance is not the exit, try the nonnegative distance
866  if( -1 == exit_idx && 0 != facets[1] ) exit_idx = 1;
867 
868  // if the exit index is still unknown, the particle is lost
869  if( -1 == exit_idx )
870  {
871  next_surf = 0;
872 #ifdef MB_GQT_DEBUG
873  std::cout << "next surf hit = 0, dist = (undef)" << std::endl;
874 #endif
875  return MB_SUCCESS;
876  }
877 
878  // return the intersection
879  next_surf = surfs[exit_idx];
880  next_surf_dist = ( 0 > dists[exit_idx] ? 0 : dists[exit_idx] );
881 
882  if( history )
883  {
884  history->prev_facets.push_back( facets[exit_idx] );
885  }
886 
887 #ifdef MB_GQT_DEBUG
888  if( 0 > dists[exit_idx] )
889  {
890  std::cout << " OVERLAP track length=" << dists[exit_idx] << std::endl;
891  }
892  std::cout << " next_surf = " << next_surf // todo: use geomtopotool to get id by entity handle
893  << ", dist = " << next_surf_dist << " new_pt=";
894  for( int i = 0; i < 3; ++i )
895  {
896  std::cout << point[i] + dir[i] * next_surf_dist << " ";
897  }
898  std::cout << std::endl;
899 #endif
900 
901  return MB_SUCCESS;
902 }

References counting, geomTopoTool, moab::Interface::get_parent_meshsets(), moab::GeomTopoTool::get_root(), MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, MBI, n_pt_in_vol_calls, n_ray_fire_calls, numericalPrecision, moab::GeomTopoTool::obb_tree(), overlapThickness, point_in_volume(), moab::GeomQueryTool::RayHistory::prev_facets, moab::OrientedBoxTreeTool::ray_intersect_sets(), and senseTag.

◆ set_numerical_precision()

void moab::GeomQueryTool::set_numerical_precision ( double  new_precision)

Attempt to set a new numerical precision , first checking for sanity Use of this function is discouraged.

Definition at line 1629 of file GeomQueryTool.cpp.

1630 {
1631  if( new_precision <= 0 || new_precision > 1 )
1632  {
1633  std::cerr << "Invalid numerical_precision = " << numericalPrecision << std::endl;
1634  }
1635  else
1636  {
1637  numericalPrecision = new_precision;
1638  }
1639  if( verbose ) std::cout << "Set numerical precision = " << numericalPrecision << std::endl;
1640 }

References numericalPrecision, and verbose.

◆ set_overlap_thickness()

void moab::GeomQueryTool::set_overlap_thickness ( double  new_overlap_thickness)

State object used in calls to ray_fire()

Storage for the "history" of a ray. This represents the surface facets that the ray is known to have crossed, which cannot be crossed again as long as the ray does not change direction. It is intended to be used with a series of consecutive calls to ray_fire(), in which a ray passes over potentially many surfaces. Attempt to set a new overlap thickness tolerance, first checking for sanity

Definition at line 1616 of file GeomQueryTool.cpp.

1617 {
1618  if( new_thickness < 0 || new_thickness > 100 )
1619  {
1620  std::cerr << "Invalid overlap_thickness = " << new_thickness << std::endl;
1621  }
1622  else
1623  {
1624  overlapThickness = new_thickness;
1625  }
1626  if( verbose ) std::cout << "Set overlap thickness = " << overlapThickness << std::endl;
1627 }

References overlapThickness, and verbose.

◆ set_verbosity()

void moab::GeomQueryTool::set_verbosity ( bool  value)
inline

Definition at line 366 of file GeomQueryTool.hpp.

367  {
368  verbose = value;
369  }

References verbose.

◆ test_volume_boundary()

ErrorCode moab::GeomQueryTool::test_volume_boundary ( const EntityHandle  volume,
const EntityHandle  surface,
const double  xyz[3],
const double  uvw[3],
int &  result,
const RayHistory history = NULL 
)

Given a ray starting at a surface of a volume, check whether the ray enters or exits the volume.

This function is most useful for rays that change directions at a surface crossing. It can be used to check whether a direction change redirects the ray back into the originating volume.

Parameters
volumeThe volume to test
surfaceA surface on volume
xyzA point location on surface
uvwA (unit) direction vector
resultSet to 1 if ray is entering volume, or 0 if it is leaving
historyOptional ray history object from a previous call to ray_fire. If present and non-empty, the history is used to look up the surface facet at which the ray begins. Absent a history, the facet nearest to xyz will be looked up. The history should always be provided if available, as it avoids the computational expense of a nearest-facet query.

Definition at line 1095 of file GeomQueryTool.cpp.

1101 {
1102  int dir;
1103 
1104  if( history && history->prev_facets.size() )
1105  {
1106  // the current facet is already available
1107  MB_CHK_SET_ERR( boundary_case( volume, dir, uvw[0], uvw[1], uvw[2], history->prev_facets.back(), surface ),
1108  "Failed to resolve the boundary case" );
1109  }
1110  else
1111  {
1112  // Get OBB Tree for surface
1113  EntityHandle root;
1114  MB_CHK_SET_ERR( geomTopoTool->get_root( volume, root ), "Failed to get the volume's OBB tree root" );
1115 
1116  // Get closest triangle on surface
1117  const CartVect point( xyz );
1118  CartVect nearest;
1119  EntityHandle facet_out;
1120  // look up nearest facet
1121  MB_CHK_SET_ERR( geomTopoTool->obb_tree()->closest_to_location( point.array(), root, nearest.array(),
1122  facet_out ),
1123  "Failed to find the closest point to location" );
1124 
1125  MB_CHK_SET_ERR( boundary_case( volume, dir, uvw[0], uvw[1], uvw[2], facet_out, surface ),
1126  "Failed to resolve the boundary case" );
1127  }
1128 
1129  result = dir;
1130 
1131  return MB_SUCCESS;
1132 }

References moab::CartVect::array(), boundary_case(), moab::OrientedBoxTreeTool::closest_to_location(), geomTopoTool, moab::GeomTopoTool::get_root(), MB_CHK_SET_ERR, MB_SUCCESS, moab::GeomTopoTool::obb_tree(), and moab::GeomQueryTool::RayHistory::prev_facets.

Member Data Documentation

◆ counting

bool moab::GeomQueryTool::counting
private

Definition at line 402 of file GeomQueryTool.hpp.

Referenced by GeomQueryTool(), point_in_volume(), and ray_fire().

◆ geomTopoTool

◆ MBI

◆ n_pt_in_vol_calls

long long int moab::GeomQueryTool::n_pt_in_vol_calls
private

Definition at line 403 of file GeomQueryTool.hpp.

Referenced by GeomQueryTool(), point_in_volume(), and ray_fire().

◆ n_ray_fire_calls

long long int moab::GeomQueryTool::n_ray_fire_calls
private

Definition at line 404 of file GeomQueryTool.hpp.

Referenced by GeomQueryTool(), and ray_fire().

◆ numericalPrecision

double moab::GeomQueryTool::numericalPrecision
private

◆ obbTreeTool

OrientedBoxTreeTool* moab::GeomQueryTool::obbTreeTool
private

Definition at line 401 of file GeomQueryTool.hpp.

Referenced by GeomQueryTool().

◆ overlapThickness

double moab::GeomQueryTool::overlapThickness
private

◆ owns_gtt

bool moab::GeomQueryTool::owns_gtt
private

Definition at line 399 of file GeomQueryTool.hpp.

Referenced by ~GeomQueryTool().

◆ senseTag

Tag moab::GeomQueryTool::senseTag
private

Definition at line 406 of file GeomQueryTool.hpp.

Referenced by GeomQueryTool(), point_in_volume(), and ray_fire().

◆ verbose

bool moab::GeomQueryTool::verbose
private

The documentation for this class was generated from the following files: