moab
DagMC.cpp
Go to the documentation of this file.
00001 #include "DagMC.hpp"
00002 #include "MBTagConventions.hpp"
00003 #include "moab/CartVect.hpp"
00004 #include "moab/Range.hpp"
00005 #include "moab/Core.hpp"
00006 #include "moab/GeomUtil.hpp"
00007 #include "moab/FileOptions.hpp"
00008 
00009 #ifdef CGM
00010 #include "InitCGMA.hpp"
00011 #include "CGMApp.hpp"
00012 #include "CubitDefines.h"
00013 #include "GeometryQueryTool.hpp"
00014 #include "CubitVector.hpp"
00015 #include "RefFace.hpp"
00016 #include "RefVolume.hpp"
00017 #endif
00018 
00019 #include <string>
00020 #include <iostream>
00021 #include <fstream>
00022 #include <sstream>
00023 #include <limits>
00024 #include <algorithm>
00025 #include <set>
00026 
00027 #include <ctype.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <stdio.h>
00031 
00032 #include <math.h>
00033 #ifndef M_PI  /* windows */
00034 # define M_PI 3.14159265358979323846
00035 #endif
00036 
00037 #define MB_OBB_TREE_TAG_NAME "OBB_TREE"
00038 #define FACETING_TOL_TAG_NAME "FACETING_TOL"
00039 #define CATEGORY_TAG_LENGTH 32
00040 
00041 #define MBI moab_instance()
00042 
00043 namespace moab {
00044 
00045 /* Tolerance Summary
00046  
00047    Facet Tolerance:
00048    Maximum distance between continuous solid model surface and faceted surface.
00049      Performance:  increasing tolerance increased performance (fewer triangles)
00050      Robustness:   should not be affected
00051      Knowledge:    user must understand how coarser faceting influences accuracy
00052                    of results
00053  
00054    Overlap Thickness:
00055    This tolerance is the maximum distance across an overlap. It should be zero 
00056    unless the geometry has overlaps. The overlap thickness is set using the dagmc 
00057    card. Overlaps must be small enough not to significantly affect physics.
00058      Performance: increasing tolerance decreases performance
00059      Robustness:  increasing tolerance increases robustness
00060      Knowledge:   user must have intuition of overlap thickness
00061 
00062    Numerical Precision:
00063    This tolerance is used for obb.intersect_ray, finding neighborhood of
00064    adjacent triangle for edge/node intersections, and error in advancing
00065    geometric position of particle (x' ~= x + d*u). When determining the
00066    neighborhood of adjacent triangles for edge/node intersections, the facet
00067    based model is expected to be watertight.
00068      Performance: increasing tolerance decreases performance (but not very much)
00069      Robustness:  increasing tolerance increases robustness
00070      Knowledge:   user should not change this tolerance
00071 
00072 */
00073 
00074   const bool debug    = false; /* controls print statements */
00075   const bool counting = false; /* controls counts of ray casts and pt_in_vols */
00076 
00077 DagMC *DagMC::instance_ = NULL;
00078 
00079 // Empty synonym map for DagMC::parse_metadata()
00080 const std::map<std::string, std::string> DagMC::no_synonyms;
00081 
00082 void DagMC::create_instance(Interface *mb_impl) 
00083 {
00084   if (NULL == mb_impl) mb_impl = new Core();
00085   instance_ = new DagMC(mb_impl);
00086 }
00087 
00088 float DagMC::version(std::string *version_string) 
00089 {
00090   if (NULL != version_string)
00091     *version_string = std::string("DagMC version ") + std::string(DAGMC_VERSION_STRING);
00092   return DAGMC_VERSION;
00093 }
00094 
00095 unsigned int DagMC::interface_revision()
00096 {
00097   unsigned int result = 0;
00098   const char* interface_string = DAGMC_INTERFACE_REVISION; 
00099   if( strlen(interface_string) >= 5 ){
00100     // start looking for the revision number after "$Rev: " 
00101     result = strtol( interface_string+5, NULL, 10 ); 
00102   }
00103   return result;
00104 }
00105 
00106 DagMC::DagMC(Interface *mb_impl) 
00107   : mbImpl(mb_impl), obbTree(mb_impl), have_cgm_geom(false),
00108     n_pt_in_vol_calls(0), n_ray_fire_calls(0)
00109 {
00110     // This is the correct place to uniquely define default values for the dagmc settings
00111   overlapThickness = 0; // must be nonnegative 
00112   defaultFacetingTolerance = .001;
00113   numericalPrecision = .001; 
00114   useCAD = false;  
00115   
00116   memset( implComplName, 0, NAME_TAG_SIZE );
00117   strcpy( implComplName , "impl_complement" );
00118 
00119 }
00120 
00121 
00122 
00123 
00124 /* SECTION I: Geometry Initialization */
00125 
00126 ErrorCode DagMC::load_file(const char* cfile,
00127                            const double facet_tolerance)
00128 {
00129   ErrorCode rval;
00130 
00131   std::cout << "Requested faceting tolerance: " << facet_tolerance << std::endl;
00132   
00133 #ifdef CGM
00134   // cgm must be initialized so we can check it for CAD data after the load
00135   InitCGMA::initialize_cgma();
00136 #endif
00137 
00138   facetingTolerance = defaultFacetingTolerance;
00139     // override default value of facetingTolerance with passed value
00140   if (facet_tolerance > 0 )
00141     facetingTolerance = facet_tolerance;
00142 
00143   char facetTolStr[16];
00144 
00145   sprintf(facetTolStr,"%g",facetingTolerance);
00146 
00147   char options[120] = "CGM_ATTRIBS=yes;FACET_DISTANCE_TOLERANCE=";
00148   strcat(options,facetTolStr);
00149   
00150   EntityHandle file_set;
00151   rval = MBI->create_meshset( MESHSET_SET, file_set );
00152   if (MB_SUCCESS != rval)
00153     return rval;
00154 
00155   rval = MBI->load_file(cfile, &file_set, options, NULL, 0, 0);
00156   
00157   if( MB_UNHANDLED_OPTION == rval ){
00158     // Some options were unhandled; this is common for loading h5m files.
00159     // Print a warning if an option was unhandled for a file that does not end in '.h5m'
00160     std::string filename(cfile);
00161     if( filename.length() < 4 || filename.substr(filename.length()-4) != ".h5m"){
00162       std::cerr << "DagMC warning: unhandled file loading options." << std::endl;
00163     }
00164   }
00165   else if (MB_SUCCESS != rval) {
00166     std::cerr << "DagMC Couldn't read file " << cfile << std::endl;
00167     std::string message;
00168     if (MB_SUCCESS == MBI->get_last_error(message) && !message.empty())
00169         std::cerr << "Error message: " << message << std::endl;
00170     
00171     return rval;
00172   }
00173 
00174 #ifdef CGM  
00175   // check to see if CGM has data; if so, assume it corresponds to the data we loaded in.
00176   if( GeometryQueryTool::instance()->num_ref_volumes() > 0 ){
00177     have_cgm_geom = true;
00178   }
00179 #endif
00180 
00181   return finish_loading();
00182 
00183 }
00184 
00185 ErrorCode DagMC::load_existing_contents( ){
00186   
00187   return finish_loading();
00188 }
00189 
00190 ErrorCode DagMC::finish_loading()
00191 {
00192 
00193   ErrorCode rval;
00194 
00195 
00196   nameTag = get_tag(NAME_TAG_NAME, NAME_TAG_SIZE, MB_TAG_SPARSE, MB_TYPE_OPAQUE, NULL, false);
00197   
00198   idTag = get_tag( GLOBAL_ID_TAG_NAME, 1, MB_TAG_DENSE, MB_TYPE_INTEGER );
00199   
00200   geomTag = get_tag( GEOM_DIMENSION_TAG_NAME, 1, MB_TAG_DENSE, MB_TYPE_INTEGER );
00201 
00202   obbTag = get_tag( MB_OBB_TREE_TAG_NAME, 1, MB_TAG_DENSE, MB_TYPE_HANDLE );
00203 
00204   facetingTolTag = get_tag(FACETING_TOL_TAG_NAME, 1, MB_TAG_SPARSE, MB_TYPE_DOUBLE );
00205   
00206     // get sense of surfaces wrt volumes
00207   senseTag = get_tag( "GEOM_SENSE_2", 2, MB_TAG_SPARSE, MB_TYPE_HANDLE );
00208 
00209   // search for a tag that has the faceting tolerance
00210   Range tagged_sets;
00211   double facet_tol_tagvalue = 0;
00212   bool other_set_tagged = false, root_tagged = false;
00213   
00214   // get list of entity sets that are tagged with faceting tolerance 
00215   // (possibly empty set)
00216   rval = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, &facetingTolTag,
00217                                             NULL, 1, tagged_sets );
00218   // if NOT empty set
00219   if (MB_SUCCESS == rval && !tagged_sets.empty()) {
00220     rval = MBI->tag_get_data( facetingTolTag, &(*tagged_sets.begin()), 1, &facet_tol_tagvalue );
00221     if (MB_SUCCESS != rval) return rval;
00222     other_set_tagged = true;
00223   }
00224   else if (MB_SUCCESS == rval) {
00225     // check to see if interface is tagged
00226     EntityHandle root = 0;
00227     rval = MBI->tag_get_data( facetingTolTag, &root, 1, &facet_tol_tagvalue );
00228     if (MB_SUCCESS == rval) root_tagged = true;
00229     else rval = MB_SUCCESS;
00230   }
00231   
00232   if ( (root_tagged || other_set_tagged) && facet_tol_tagvalue > 0) {
00233     facetingTolerance = facet_tol_tagvalue;
00234   }
00235 
00236   std::cout << "Using faceting tolerance: " << facetingTolerance << std::endl;
00237 
00238   return MB_SUCCESS;
00239 
00240 }
00241 
00242 ErrorCode DagMC::init_OBBTree() 
00243 {
00244 
00245   ErrorCode rval;
00246 
00247   Range surfs, vols;
00248   const int three = 3;
00249   const void* const three_val[] = {&three};
00250   rval = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, &geomTag, 
00251                                             three_val, 1, vols );
00252   if (MB_SUCCESS != rval)
00253     return rval;
00254 
00255   const int two = 2;
00256   const void* const two_val[] = {&two};
00257   rval = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, &geomTag, 
00258                                             two_val, 1, surfs );
00259   if (MB_SUCCESS != rval)
00260     return rval;
00261 
00262     // If it doesn't already exist, create implicit complement
00263     // Create data structures for implicit complement
00264   rval = get_impl_compl();
00265   if (MB_SUCCESS != rval) {
00266     std::cerr << "Failed to find or create implicit complement handle." << std::endl;
00267     return rval;
00268   }
00269 
00270   // Build OBB trees for everything, but only if we only read geometry
00271   // Changed to build obb tree if tree does not already exist. -- JK
00272   if (!have_obb_tree()) {
00273     rval = build_obbs(surfs, vols);
00274     if (MB_SUCCESS != rval) {
00275       std::cerr << "Failed to build obb." << std::endl;
00276       return rval;
00277     }
00278   }
00279 
00280   // build_indices expects the implicit complement to be in vols.
00281   if( vols.find(impl_compl_handle) == vols.end() ){
00282     vols.insert( vols.end(), impl_compl_handle );
00283   }
00284 
00285     // build the various index vectors used for efficiency
00286   rval = build_indices(surfs, vols);
00287   if (MB_SUCCESS != rval) {
00288     std::cerr << "Failed to build surface/volume indices." << std::endl;
00289     return rval;
00290   }
00291   
00292   return MB_SUCCESS;
00293 }
00294 
00295 /* SECTION I (private) */
00296 
00297 bool DagMC::have_obb_tree()
00298 {
00299   Range entities;
00300   ErrorCode rval = mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET,
00301                                                            &obbTag, 0, 1,
00302                                                            entities );
00303   return MB_SUCCESS == rval && !entities.empty();
00304 }                                                    
00305 
00306 
00307 ErrorCode DagMC::get_impl_compl()
00308 {
00309   Range entities;
00310   const void* const tagdata[] = {implComplName};
00311   ErrorCode rval = mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET,
00312                                                            &nameTag, tagdata, 1,
00313                                                            entities );
00314   // query error
00315   if (MB_SUCCESS != rval) {
00316     std::cerr << "Unable to query for implicit complement." << std::endl;
00317     return rval;
00318   }
00319 
00320   // found too many
00321   if (entities.size() > 1) {
00322     std::cerr << "Too many implicit complement sets." << std::endl;
00323     return MB_MULTIPLE_ENTITIES_FOUND;
00324   }
00325 
00326   // found none
00327   if (entities.empty()) {
00328     rval= MBI->create_meshset(MESHSET_SET,impl_compl_handle);
00329     if (MB_SUCCESS != rval) {
00330       std::cerr << "Failed to create mesh set for implicit complement." << std::endl;
00331       return rval;
00332     }
00333       // tag this entity with name for implicit complement
00334     rval = MBI->tag_set_data(nameTag,&impl_compl_handle,1,&implComplName);
00335     if (MB_SUCCESS != rval) {
00336       std::cerr << "Failed to tag new entity as implicit complement." << std::endl;
00337     }
00338 
00339     return rval;
00340 
00341   } else {
00342     // found a single implicit complement
00343     impl_compl_handle = entities.front();
00344     return MB_SUCCESS;
00345   }
00346   
00347   
00348 }
00349 
00350 ErrorCode DagMC::build_obbs(Range &surfs, Range &vols) 
00351 {
00352   ErrorCode rval = MB_SUCCESS;
00353   
00354   for (Range::iterator i = surfs.begin(); i != surfs.end(); ++i) {
00355     EntityHandle root;
00356     Range tris;
00357     rval = MBI->get_entities_by_dimension( *i, 2, tris );
00358     if (MB_SUCCESS != rval) 
00359       return rval;
00360     if (tris.empty()) 
00361       std::cerr << "WARNING: Surface " << get_entity_id(*i) << " has no facets." << std::endl;
00362     rval = obbTree.build( tris, root );
00363     if (MB_SUCCESS != rval) 
00364       return rval;
00365     rval = MBI->add_entities( root, &*i, 1 );
00366     if (MB_SUCCESS != rval)
00367       return rval;
00368     rval = MBI->tag_set_data( obbTag, &*i, 1, &root );
00369     if (MB_SUCCESS != rval)
00370       return rval;
00371   }
00372   
00373   for (Range::iterator i = vols.begin(); i != vols.end(); ++i) {
00374       // get all surfaces in volume
00375     Range tmp_surfs;
00376     rval = MBI->get_child_meshsets( *i, tmp_surfs );
00377     if (MB_SUCCESS != rval)
00378       return rval;
00379     
00380       // get OBB trees for each surface
00381     EntityHandle root;
00382     Range trees;
00383     for (Range::iterator j = tmp_surfs.begin();  j != tmp_surfs.end(); ++j) {
00384         // skip any surfaces that are non-manifold in the volume
00385         // because point containment code will get confused by them
00386       int sense;
00387       rval = surface_sense( *i, *j, sense );
00388       if (MB_SUCCESS != rval) {
00389         std::cerr << "Surface/Volume sense data missing." << std::endl;
00390         return rval;
00391       }
00392       if (!sense)
00393         continue;
00394       
00395       rval = MBI->tag_get_data( obbTag, &*j, 1, &root );
00396       if (MB_SUCCESS != rval || !root)  
00397         return MB_FAILURE;
00398       trees.insert( root );
00399     }
00400     
00401       // build OBB tree for volume
00402     rval = obbTree.join_trees( trees, root );
00403     if (MB_SUCCESS != rval)
00404       return rval;
00405     
00406     rval = MBI->tag_set_data( obbTag, &*i, 1, &root );
00407     if (MB_SUCCESS != rval)
00408       return rval;
00409 
00410   }
00411 
00412   rval = build_obb_impl_compl(surfs);
00413   if (MB_SUCCESS != rval) {
00414     std::cerr << "Unable to build OBB tree for implicit complement." << std::endl;
00415     return rval;
00416   }
00417 
00418   return MB_SUCCESS;
00419 }
00420 
00421 ErrorCode DagMC::build_obb_impl_compl(Range &surfs) 
00422 {
00423   EntityHandle comp_root, surf_obb_root;
00424   Range comp_tree;
00425   ErrorCode rval;
00426   std::vector<EntityHandle> parent_vols;
00427   
00428   int impl_compl_surf_count = 0;
00429   double impl_compl_surf_area = 0.0;
00430 
00431     // search through all surfaces  
00432   for (Range::iterator surf_i = surfs.begin(); surf_i != surfs.end(); ++surf_i) {
00433     
00434     parent_vols.clear();
00435       // get parents of each surface
00436     rval = MBI->get_parent_meshsets( *surf_i, parent_vols );
00437     if (MB_SUCCESS != rval)
00438       return rval;
00439 
00440       // if only one parent, get the OBB root for this surface
00441     if (parent_vols.size() == 1 ) {
00442 
00443       double a;
00444       measure_area( *surf_i, a );
00445       impl_compl_surf_count += 1;
00446       impl_compl_surf_area  += a;
00447 
00448       rval = MBI->tag_get_data( obbTag, &*surf_i, 1, &surf_obb_root );
00449       if (MB_SUCCESS != rval)
00450         return rval;
00451       if (!surf_obb_root)
00452         return MB_FAILURE;
00453       
00454         // add obb root to list of obb roots
00455       comp_tree.insert( surf_obb_root );
00456 
00457       // add this surf to the topology of the implicit complement volume
00458       rval = MBI->add_parent_child(impl_compl_handle,*surf_i);
00459       if (MB_SUCCESS != rval)
00460         return rval;
00461 
00462       // get the surface sense wrt original volume
00463       EntityHandle sense_data[2] = {0,0};
00464       rval = MBI->tag_get_data( sense_tag(), &(*surf_i), 1, sense_data );
00465       if (MB_SUCCESS != rval) return rval;
00466       
00467       // set the surface sense wrt implicit complement volume
00468       if(0==sense_data[0] && 0==sense_data[1]) return MB_FAILURE;
00469       if(0==sense_data[0])
00470         sense_data[0] = impl_compl_handle;
00471       else if(0==sense_data[1])
00472         sense_data[1] = impl_compl_handle;
00473       else
00474         return MB_FAILURE;
00475       rval = MBI->tag_set_data( sense_tag(), &(*surf_i), 1, sense_data );
00476       if (MB_SUCCESS != rval)  return rval;
00477 
00478     }  
00479   }
00480   // print info about the implicit complement if one was created
00481   if( impl_compl_surf_count ){
00482     bool one = (impl_compl_surf_count == 1);
00483     std::cout << "The implicit complement bounds " << impl_compl_surf_count
00484               << (one ? " surface" : " surfaces") << std::endl;
00485     std::cout << "The implicit complement's total surface area = " 
00486               << impl_compl_surf_area << std::endl;
00487   }
00488   
00489     // join surface trees to make OBB tree for implicit complement
00490   rval = obbTree.join_trees( comp_tree, comp_root );
00491   if (MB_SUCCESS != rval)
00492     return rval;
00493   
00494     // tag the implicit complement handle with the handle for its own OBB tree
00495   rval = MBI->tag_set_data( obbTag, &impl_compl_handle, 1, &comp_root );
00496   if (MB_SUCCESS != rval)
00497     return rval;
00498   
00499   // following ReadCGM, assign dimension and category tags
00500   int three = 3;
00501   rval = MBI->tag_set_data(geomTag, &impl_compl_handle, 1, &three );
00502   if (MB_SUCCESS != rval)
00503     return rval;
00504 
00505   Tag category_tag = get_tag(CATEGORY_TAG_NAME, CATEGORY_TAG_LENGTH, 
00506                              MB_TAG_SPARSE, MB_TYPE_OPAQUE);
00507   static const char volume_category[CATEGORY_TAG_SIZE] = "Volume\0";
00508   rval = MBI->tag_set_data(category_tag, &impl_compl_handle, 1, volume_category );
00509   if (MB_SUCCESS != rval)
00510     return rval;
00511 
00512   return MB_SUCCESS;
00513 
00514 }
00515 
00516   /* SECTION II: Fundamental Geometry Operations/Queries */
00517 void DagMC::RayHistory::reset() { 
00518   prev_facets.clear();
00519 }
00520 
00521 void DagMC::RayHistory::reset_to_last_intersection() {
00522 
00523   if( prev_facets.size() > 1 ){
00524     prev_facets[0] = prev_facets.back();
00525     prev_facets.resize( 1 );
00526   }
00527 
00528 }
00529 
00530 void DagMC::RayHistory::rollback_last_intersection() {
00531   if( prev_facets.size() )
00532     prev_facets.pop_back();
00533 }
00534 
00535 ErrorCode DagMC::ray_fire(const EntityHandle vol, 
00536                           const double point[3], const double dir[3],
00537                           EntityHandle& next_surf, double& next_surf_dist,
00538                           RayHistory* history, double user_dist_limit,
00539               int ray_orientation, 
00540                           OrientedBoxTreeTool::TrvStats* stats ) { 
00541 
00542   // take some stats that are independent of nps
00543   if(counting) {
00544     ++n_ray_fire_calls;
00545     if(0==n_ray_fire_calls%10000000) {
00546       std::cout << "n_ray_fires="   << n_ray_fire_calls 
00547                 << " n_pt_in_vols=" << n_pt_in_vol_calls << std::endl;
00548     }
00549   }
00550 
00551   if (debug) {
00552     std::cout << "ray_fire:" 
00553               << " xyz=" << point[0] << " " << point[1] << " " << point[2]
00554               << " uvw=" << dir[0] << " " << dir[1] << " " << dir[2]
00555               << " vol_id=" << id_by_index(3, index_by_handle(vol)) << std::endl;
00556     }
00557 
00558   const double huge_val = std::numeric_limits<double>::max();
00559   double dist_limit = huge_val;
00560   if( user_dist_limit > 0 )
00561     dist_limit = user_dist_limit;
00562 
00563   // don't recreate these every call
00564   std::vector<double>       &dists       = distList;
00565   std::vector<EntityHandle> &surfs       = surfList;
00566   std::vector<EntityHandle> &facets      = facetList;  
00567   dists.clear();
00568   surfs.clear();
00569   facets.clear();
00570 
00571   assert(vol - setOffset < rootSets.size());  
00572   const EntityHandle root = rootSets[vol - setOffset];
00573   ErrorCode rval;
00574  
00575   // check behind the ray origin for intersections
00576   double neg_ray_len;
00577   if(0 == overlapThickness) {
00578     neg_ray_len = -numericalPrecision;
00579   } else {
00580     neg_ray_len = -overlapThickness;
00581   }
00582 
00583   // optionally, limit the nonneg_ray_len with the distance to next collision.
00584   double nonneg_ray_len = dist_limit;
00585 
00586   // the nonneg_ray_len should not be less than -neg_ray_len, or an overlap 
00587   // may be missed due to optimization within ray_intersect_sets
00588   if(nonneg_ray_len < -neg_ray_len) nonneg_ray_len = -neg_ray_len;
00589   assert(0 <= nonneg_ray_len);
00590   assert(0 >     neg_ray_len);
00591   
00592   // min_tolerance_intersections is passed but not used in this call
00593   const int min_tolerance_intersections = 0;
00594 
00595   // numericalPrecision is used for box.intersect_ray and find triangles in the
00596   // neighborhood of edge/node intersections.
00597   rval = obbTree.ray_intersect_sets( dists, surfs, facets,
00598                                      root, numericalPrecision, 
00599                                      min_tolerance_intersections,
00600                                      point, dir, &nonneg_ray_len,
00601                                      stats, &neg_ray_len, &vol, &senseTag, 
00602                                      &ray_orientation, 
00603                                      history ? &(history->prev_facets) : NULL );
00604   assert( MB_SUCCESS == rval );
00605   if(MB_SUCCESS != rval) return rval;
00606 
00607   // if useCAD is true at this point, then we know we can call CGM's ray casting function.
00608   if (useCAD) {
00609     rval = CAD_ray_intersect( point, dir, huge_val, dists, surfs, nonneg_ray_len );
00610     if (MB_SUCCESS != rval) return rval;
00611   }
00612   
00613   // If no distances are returned, the particle is lost unless the physics limit
00614   // is being used. If the physics limit is being used, there is no way to tell
00615   // if the particle is lost. To avoid ambiguity, DO NOT use the distance limit 
00616   // unless you know lost particles do not occur.
00617   if( dists.empty() ) {
00618     next_surf = 0;
00619     if(debug) {
00620       std::cout << "          next_surf=0 dist=(undef)" << std::endl; 
00621     }
00622     return MB_SUCCESS;
00623   }
00624 
00625   // Assume that a (neg, nonneg) pair of RTIs could be returned,
00626   // however, only one or the other may exist. dists[] may be populated, but 
00627   // intersections are ONLY indicated by nonzero surfs[] and facets[].
00628   assert(2 == dists.size());
00629   assert(2 == facets.size());
00630   assert(0.0 >= dists[0]);
00631   assert(0.0 <= dists[1]);
00632 
00633   // If both negative and nonnegative RTIs are returned, the negative RTI must
00634   // closer to the origin.
00635   if(0!=facets[0] && 0!=facets[1]) {
00636     assert(-dists[0] <= dists[1]);
00637   }
00638 
00639   // If an RTI is found at negative distance, perform a PMT to see if the 
00640   // particle is inside an overlap.
00641   int exit_idx = -1;
00642   if(0!=facets[0]) {
00643     // get the next volume
00644     std::vector<EntityHandle> vols;
00645     EntityHandle nx_vol;
00646     rval = MBI->get_parent_meshsets( surfs[0], vols );
00647     if(MB_SUCCESS != rval) return rval;
00648     assert(2 == vols.size());
00649     if(vols.front() == vol) {
00650       nx_vol = vols.back();
00651     } else {
00652       nx_vol = vols.front();
00653     }
00654     // Check to see if the point is actually in the next volume.
00655     // The list of previous facets is used to topologically identify the 
00656     // "on_boundary" result of the PMT. This avoids a test that uses proximity 
00657     // (a tolerance).
00658     int result;
00659     rval = point_in_volume( nx_vol, point, result, dir, history );
00660     if(MB_SUCCESS != rval) return rval;
00661     if(1==result) exit_idx = 0;
00662 
00663   }
00664 
00665   // if the negative distance is not the exit, try the nonnegative distance
00666   if(-1==exit_idx && 0!=facets[1]) exit_idx = 1;
00667   
00668   // if the exit index is still unknown, the particle is lost
00669   if(-1 == exit_idx) {
00670     next_surf = 0;
00671     if (debug) {
00672       std::cout << "next surf hit = 0, dist = (undef)" << std::endl;
00673     }
00674     return MB_SUCCESS;
00675   }
00676 
00677   // return the intersection
00678   next_surf = surfs[exit_idx];
00679   next_surf_dist = ( 0>dists[exit_idx] ? 0 : dists[exit_idx]);
00680 
00681   if( history ){
00682     history->prev_facets.push_back( facets[exit_idx] );
00683   }
00684 
00685   if (debug) {
00686     if( 0 > dists[exit_idx] ){
00687       std::cout << "          OVERLAP track length=" << dists[exit_idx] << std::endl;
00688     }
00689     std::cout << "          next_surf = " <<  id_by_index(2, index_by_handle(next_surf)) 
00690               << ", dist = " << next_surf_dist << " new_pt=";
00691     for( int i = 0; i < 3; ++i ){
00692       std::cout << point[i]+dir[i]*next_surf_dist << " ";
00693     }
00694     std::cout << std::endl;
00695   }
00696 
00697   return MB_SUCCESS;
00698 }
00699 
00700 ErrorCode DagMC::point_in_volume(const EntityHandle volume, 
00701                                  const double xyz[3],
00702                                  int& result,
00703                                  const double *uvw,
00704                                  const RayHistory *history) {
00705   // take some stats that are independent of nps
00706   if(counting) ++n_pt_in_vol_calls;
00707 
00708   // get OBB Tree for volume
00709   assert(volume - setOffset < rootSets.size());
00710   EntityHandle root = rootSets[volume - setOffset];
00711 
00712   // Don't recreate these every call. These cannot be the same as the ray_fire
00713   // vectors because both are used simultaneously.
00714   std::vector<double>       &dists = disList;
00715   std::vector<EntityHandle> &surfs = surList;
00716   std::vector<EntityHandle> &facets= facList;
00717   std::vector<int>          &dirs  = dirList;
00718   dists.clear();
00719   surfs.clear();
00720   facets.clear();
00721   dirs.clear();
00722 
00723   // if uvw is not given or is full of zeros, use a random direction
00724   double u = 0, v = 0, w = 0;
00725 
00726   if( uvw ){
00727     u = uvw[0]; v=uvw[1], w=uvw[2];
00728   }
00729 
00730   if( u == 0 && v == 0 && w == 0 )
00731   { 
00732     u = rand();
00733     v = rand();
00734     w = rand();
00735     const double magnitude = sqrt( u*u + v*v + w*w );
00736     u /= magnitude;
00737     v /= magnitude;
00738     w /= magnitude;
00739   }
00740 
00741   const double ray_direction[] = { u, v, w };
00742   
00743   // if overlaps, ray must be cast to infinity and all RTIs must be returned
00744   const double   large       = 1e15;
00745   const double   ray_length  = large;
00746 
00747   // If overlaps occur, the pt is inside if traveling along the ray from the
00748   // origin, there are ever more exits than entrances. In lieu of implementing
00749   // that, all intersections to infinity are required if overlaps occur (expensive)
00750   int min_tolerance_intersections;
00751   if(0 != overlapThickness) {
00752     min_tolerance_intersections = -1;
00753   // only the first intersection is needed if overlaps do not occur (cheap)
00754   } else {
00755     min_tolerance_intersections = 1;
00756   }
00757 
00758   // Get intersection(s) of forward and reverse orientation. Do not return 
00759   // glancing intersections or previous facets.
00760   ErrorCode rval = obbTree.ray_intersect_sets( dists, surfs, facets, root,
00761                                                numericalPrecision, 
00762                                                min_tolerance_intersections,
00763                                                xyz, ray_direction,
00764                                                &ray_length, NULL, NULL, &volume,
00765                                                &senseTag, NULL, 
00766                                                history ? &(history->prev_facets) : NULL );
00767   if(MB_SUCCESS != rval) return rval;
00768 
00769   // determine orientation of all intersections
00770   // 1 for entering, 0 for leaving, -1 for tangent
00771   // Tangent intersections are not returned from ray_tri_intersect.
00772   dirs.resize(dists.size());
00773   for(unsigned i=0; i<dists.size(); ++i) {
00774     rval = boundary_case( volume, dirs[i], u, v, w, facets[i], surfs[i] );
00775     if(MB_SUCCESS != rval) return rval;
00776   }
00777 
00778   // count all crossings
00779   if(0 != overlapThickness) {
00780     int sum = 0;
00781     for(unsigned i=0; i<dirs.size(); ++i) {
00782       if     ( 1==dirs[i]) sum+=1; // +1 for entering
00783       else if( 0==dirs[i]) sum-=1; // -1 for leaving
00784       else if(-1==dirs[i]) {       //  0 for tangent
00785         std::cout << "direction==tangent" << std::endl;
00786         sum+=0;
00787       } else {
00788         std::cout << "error: unknown direction" << std::endl;
00789         return MB_FAILURE;
00790       }
00791     }
00792 
00793     // inside/outside depends on the sum
00794     if(0<sum)                          result = 0; // pt is outside (for all vols)
00795     else if(0>sum)                     result = 1; // pt is inside  (for all vols)
00796     else if(impl_compl_handle==volume) result = 1; // pt is inside  (for impl_compl_vol)
00797     else                               result = 0; // pt is outside (for all other vols)
00798 
00799   // Only use the first crossing
00800   } else {
00801       if( dirs.empty() ) {
00802       result = 0; // pt is outside
00803     } else {
00804       int smallest = std::min_element( dists.begin(), dists.end() ) - dists.begin();
00805       if     ( 1==dirs[smallest] ) result = 0; // pt is outside
00806       else if( 0==dirs[smallest] ) result = 1; // pt is inside
00807       else if(-1==dirs[smallest] ) {
00808         // Should not be here because Plucker ray-triangle test does not 
00809         // return coplanar rays as intersections. 
00810         std::cout << "direction==tangent" << std::endl;
00811         result = -1;
00812       } else {
00813         std::cout << "error: unknown direction" << std::endl;
00814         return MB_FAILURE;
00815       }
00816     }
00817   }
00818 
00819   if(debug)
00820     std::cout << "pt_in_vol: result=" << result
00821               << " xyz=" << xyz[0] << " " << xyz[1] << " " << xyz[2] << " uvw=" << u << " " << v << " " << w
00822               << " vol_id=" << id_by_index(3, index_by_handle(volume)) << std::endl;
00823   
00824   return MB_SUCCESS;
00825 }
00826 
00827 ErrorCode DagMC::test_volume_boundary( const EntityHandle volume, const EntityHandle surface,
00828                                        const double xyz[3], const double uvw[3], int& result,
00829                                        const RayHistory* history )
00830 {
00831   ErrorCode rval;
00832   int dir;
00833 
00834   if( history && history->prev_facets.size() ){
00835     // the current facet is already available
00836     rval = boundary_case( volume, dir, uvw[0], uvw[1], uvw[2], history->prev_facets.back(), surface );
00837     if (MB_SUCCESS != rval) return rval;
00838   }
00839   else{
00840     // look up nearest facet
00841 
00842     // Get OBB Tree for surface
00843     assert(volume - setOffset < rootSets.size());
00844     EntityHandle root = rootSets[volume - setOffset];
00845     
00846     // Get closest triangle on surface
00847     const CartVect point(xyz);
00848     CartVect nearest;
00849     EntityHandle facet_out;
00850     rval = obbTree.closest_to_location( point.array(), root, nearest.array(), facet_out );
00851     if (MB_SUCCESS != rval) return rval;
00852 
00853     rval = boundary_case( volume, dir, uvw[0], uvw[1], uvw[2], facet_out, surface );
00854     if (MB_SUCCESS != rval) return rval;
00855 
00856   }
00857 
00858   result = dir;
00859 
00860   return MB_SUCCESS;
00861 
00862 }
00863 
00864 // use spherical area test to determine inside/outside of a polyhedron.
00865 ErrorCode DagMC::point_in_volume_slow( EntityHandle volume, const double xyz[3], int& result )
00866 {
00867   ErrorCode rval;
00868   Range faces;
00869   std::vector<EntityHandle> surfs;
00870   std::vector<int> senses;
00871   double sum = 0.0;
00872   const CartVect point(xyz);
00873   
00874   rval = MBI->get_child_meshsets( volume, surfs );
00875   if (MB_SUCCESS != rval)
00876     return rval;
00877   
00878   senses.resize( surfs.size() );
00879   rval = surface_sense( volume, surfs.size(), &surfs[0], &senses[0] );
00880   if (MB_SUCCESS != rval)
00881     return rval;
00882   
00883   for (unsigned i = 0; i < surfs.size(); ++i) {
00884     if (!senses[i])  // skip non-manifold surfaces
00885       continue;
00886      
00887     double surf_area = 0.0, face_area;
00888     faces.clear();
00889     rval = MBI->get_entities_by_dimension( surfs[i], 2, faces );
00890     if (MB_SUCCESS != rval)
00891       return rval;
00892     
00893     for (Range::iterator j = faces.begin(); j != faces.end(); ++j) {
00894       rval = poly_solid_angle( *j, point, face_area );
00895       if (MB_SUCCESS != rval)
00896         return rval;
00897       
00898       surf_area += face_area;
00899     }
00900     
00901     sum += senses[i] * surf_area;
00902   }
00903   
00904   result = fabs(sum) > 2.0*M_PI;
00905   return MB_SUCCESS;
00906 }
00907 
00908 
00909 
00910 // detemine distance to nearest surface
00911 ErrorCode DagMC::closest_to_location( EntityHandle volume, const double coords[3], double& result)
00912 {
00913     // Get OBB Tree for volume
00914   assert(volume - setOffset < rootSets.size());
00915   EntityHandle root = rootSets[volume - setOffset];
00916 
00917     // Get closest triangles in volume
00918   const CartVect point(coords);
00919   CartVect nearest;
00920   EntityHandle facet_out;
00921   ErrorCode rval = obbTree.closest_to_location( point.array(), root, nearest.array(), facet_out );
00922   if (MB_SUCCESS != rval) return rval;
00923 
00924   // calculate distance between point and nearest facet
00925   result = (point-nearest).length();
00926   
00927   return MB_SUCCESS;
00928 
00929 }
00930 
00931 // calculate volume of polyhedron
00932 ErrorCode DagMC::measure_volume( EntityHandle volume, double& result )
00933 {
00934   ErrorCode rval;
00935   std::vector<EntityHandle> surfaces, surf_volumes;
00936   result = 0.0;
00937   
00938    // don't try to calculate volume of implicit complement
00939   if (volume == impl_compl_handle) {
00940     result = 1.0;
00941     return MB_SUCCESS;
00942   }
00943 
00944     // get surfaces from volume
00945   rval = MBI->get_child_meshsets( volume, surfaces );
00946   if (MB_SUCCESS != rval) return rval;
00947   
00948     // get surface senses
00949   std::vector<int> senses( surfaces.size() );
00950   rval = surface_sense( volume, surfaces.size(), &surfaces[0], &senses[0] );
00951   if (MB_SUCCESS != rval) {
00952     std::cerr << "ERROR: Surface-Volume relative sense not available. "
00953               << "Cannot calculate volume." << std::endl;
00954     return rval;
00955   }
00956   
00957   for (unsigned i = 0; i < surfaces.size(); ++i) {
00958       // skip non-manifold surfaces
00959     if (!senses[i])
00960       continue;
00961     
00962       // get triangles in surface
00963     Range triangles;
00964     rval = MBI->get_entities_by_dimension( surfaces[i], 2, triangles );
00965     if (MB_SUCCESS != rval) 
00966       return rval;
00967     if (!triangles.all_of_type(MBTRI)) {
00968       std::cout << "WARNING: Surface " << get_entity_id(surfaces[i])
00969                 << " contains non-triangle elements. Volume calculation may be incorrect." 
00970                 << std::endl;
00971       triangles.clear();
00972       rval = MBI->get_entities_by_type( surfaces[i], MBTRI, triangles );
00973       if (MB_SUCCESS != rval) return rval;
00974     }
00975     
00976       // calculate signed volume beneath surface (x 6.0)
00977     double surf_sum = 0.0;
00978     const EntityHandle *conn;
00979     int len;
00980     CartVect coords[3];
00981     for (Range::iterator j = triangles.begin(); j != triangles.end(); ++j) {
00982       rval = MBI->get_connectivity( *j, conn, len, true );
00983       if (MB_SUCCESS != rval) return rval;
00984       assert(3 == len);
00985       rval = MBI->get_coords( conn, 3, coords[0].array() );
00986       if (MB_SUCCESS != rval) return rval;
00987     
00988       coords[1] -= coords[0];
00989       coords[2] -= coords[0];
00990       surf_sum += (coords[0] % (coords[1] * coords[2]));
00991     }
00992     result += senses[i] * surf_sum;
00993   }
00994   
00995   result /= 6.0;
00996   return MB_SUCCESS;
00997 }
00998 
00999 // sum area of elements in surface
01000 ErrorCode DagMC::measure_area( EntityHandle surface, double& result )
01001 {
01002     // get triangles in surface
01003   Range triangles;
01004   ErrorCode rval = MBI->get_entities_by_dimension( surface, 2, triangles );
01005   if (MB_SUCCESS != rval) 
01006     return rval;
01007   if (!triangles.all_of_type(MBTRI)) {
01008     std::cout << "WARNING: Surface " << get_entity_id(surface)
01009               << " contains non-triangle elements. Area calculation may be incorrect." 
01010               << std::endl;
01011     triangles.clear();
01012     rval = MBI->get_entities_by_type( surface, MBTRI, triangles );
01013     if (MB_SUCCESS != rval) return rval;
01014   }
01015 
01016     // calculate sum of area of triangles
01017   result = 0.0;
01018   const EntityHandle *conn;
01019   int len;
01020   CartVect coords[3];
01021   for (Range::iterator j = triangles.begin(); j != triangles.end(); ++j) {
01022     rval = MBI->get_connectivity( *j, conn, len, true );
01023     if (MB_SUCCESS != rval) return rval;
01024     assert(3 == len);
01025     rval = MBI->get_coords( conn, 3, coords[0].array() );
01026     if (MB_SUCCESS != rval) return rval;
01027 
01028     coords[1] -= coords[0];
01029     coords[2] -= coords[0];
01030     coords[0] = coords[1] * coords[2];
01031     result += coords[0].length();
01032   }
01033   result *= 0.5;
01034   return MB_SUCCESS;
01035 }
01036 
01037 // get sense of surface(s) wrt volume
01038 ErrorCode DagMC::surface_sense( EntityHandle volume, 
01039                            int num_surfaces,
01040                            const EntityHandle* surfaces,
01041                            int* senses_out )
01042 {
01043 
01044   /* The sense tags do not reference the implicit complement handle.
01045      All surfaces that interact with the implicit complement should have
01046      a null handle in the direction of the implicit complement. */
01047   //if (volume == impl_compl_handle)
01048   //  volume = (EntityHandle) 0;
01049 
01050   std::vector<EntityHandle> surf_volumes( 2*num_surfaces );
01051   ErrorCode rval = MBI->tag_get_data( sense_tag(), surfaces, num_surfaces, &surf_volumes[0] );
01052   if (MB_SUCCESS != rval)  return rval;
01053   
01054   const EntityHandle* end = surfaces + num_surfaces;
01055   std::vector<EntityHandle>::const_iterator surf_vols = surf_volumes.begin();
01056   while (surfaces != end) {
01057     EntityHandle forward = *surf_vols; ++surf_vols;
01058     EntityHandle reverse = *surf_vols; ++surf_vols;
01059     if (volume == forward) 
01060       *senses_out = (volume != reverse); // zero if both, otherwise 1
01061     else if (volume == reverse)
01062       *senses_out = -1;
01063     else 
01064       return MB_ENTITY_NOT_FOUND;
01065     
01066     ++surfaces;
01067     ++senses_out;
01068   }
01069   
01070   return MB_SUCCESS;
01071 }
01072 
01073 // get sense of surface(s) wrt volume
01074 ErrorCode DagMC::surface_sense( EntityHandle volume, 
01075                                   EntityHandle surface,
01076                                   int& sense_out )
01077 {
01078   /* The sense tags do not reference the implicit complement handle.
01079      All surfaces that interact with the implicit complement should have
01080      a null handle in the direction of the implicit complement. */
01081   //if (volume == impl_compl_handle)
01082   //  volume = (EntityHandle) 0;
01083 
01084     // get sense of surfaces wrt volumes
01085   EntityHandle surf_volumes[2];
01086   ErrorCode rval = MBI->tag_get_data( sense_tag(), &surface, 1, surf_volumes );
01087   if (MB_SUCCESS != rval)  return rval;
01088   
01089   if (surf_volumes[0] == volume)
01090     sense_out = (surf_volumes[1] != volume); // zero if both, otherwise 1
01091   else if (surf_volumes[1] == volume) 
01092     sense_out = -1;
01093   else
01094     return MB_ENTITY_NOT_FOUND;
01095   
01096   return MB_SUCCESS;
01097 }
01098 
01099 ErrorCode DagMC::get_angle(EntityHandle surf, const double in_pt[3], double angle[3], const RayHistory* history )
01100 {
01101   EntityHandle root = rootSets[surf - setOffset];
01102   ErrorCode rval;
01103   
01104   std::vector<EntityHandle> facets;
01105 
01106   // if no history or history empty, use nearby facets
01107   if( !history || (history->prev_facets.size() == 0) ){
01108     rval = obbTree.closest_to_location( in_pt, root, numericalPrecision, facets );
01109     assert(MB_SUCCESS == rval);
01110     if (MB_SUCCESS != rval) return rval;
01111   }
01112   // otherwise use most recent facet in history
01113   else{
01114     facets.push_back( history->prev_facets.back() );
01115   }
01116 
01117   CartVect coords[3], normal(0.0);
01118   const EntityHandle *conn;
01119   int len;
01120   for (unsigned i = 0; i < facets.size(); ++i) {
01121     rval = mbImpl->get_connectivity( facets[i], conn, len );
01122     assert( MB_SUCCESS == rval );
01123     assert( 3 == len );
01124   
01125     rval = mbImpl->get_coords( conn, 3, coords[0].array() );
01126     assert(MB_SUCCESS == rval);
01127     
01128     coords[1] -= coords[0];
01129     coords[2] -= coords[0];
01130     normal += coords[1] * coords[2];
01131   }
01132   
01133   normal.normalize();
01134   normal.get( angle );
01135 
01136   return MB_SUCCESS;
01137 }
01138 
01139 ErrorCode DagMC::next_vol( EntityHandle surface, EntityHandle old_volume, 
01140                            EntityHandle& new_volume )
01141 {
01142   std::vector<EntityHandle> parents;
01143   ErrorCode rval = MBI->get_parent_meshsets( surface, parents );
01144 
01145   if (MB_SUCCESS == rval) {
01146     if (parents.size() != 2)
01147       rval = MB_FAILURE;
01148     else if (parents.front() == old_volume) 
01149       new_volume = parents.back();
01150     else if( parents.back() == old_volume )
01151       new_volume = parents.front();
01152     else 
01153       rval = MB_FAILURE;
01154   }
01155 
01156   if( rval != MB_SUCCESS ){
01157     std::cerr << "DAGMC: mesh error in next_vol for surf " << get_entity_id(surface) << std::endl;
01158   }
01159 
01160   return rval;
01161 
01162 }
01163 
01164 /* SECTION II (private) */
01165 
01166 ErrorCode DagMC::CAD_ray_intersect(
01167 #if defined(CGM) && defined(HAVE_CGM_FIRE_RAY)
01168     const double *point, 
01169     const double *dir, 
01170     const double huge_val,
01171     std::vector<double> &distances,
01172     std::vector<EntityHandle> &surfaces, 
01173     double &len
01174 #else
01175     const double *, 
01176     const double *, 
01177     const double ,
01178     std::vector<double> &,
01179     std::vector<EntityHandle> &, 
01180     double &
01181 #endif
01182 ) 
01183 {
01184 #ifdef CGM
01185 #ifndef HAVE_CGM_FIRE_RAY
01186   return MB_NOT_IMPLEMENTED;
01187 #else
01188   std::vector<double>::iterator dit = distances.begin();
01189   std::vector<EntityHandle>::iterator sit = surfaces.begin();
01190   static DLIList<double> ray_params;
01191   
01192   for (; dit != distances.end(); dit++, sit++) {
01193       // get the RefFace
01194     RefEntity *this_face = geomEntities[*sit - setOffset];
01195       // get the ray distance to this face
01196     ray_params.clean_out();
01197     int result = GeometryQueryTool::instance()->
01198       fire_ray(dynamic_cast<RefFace*>(this_face), CubitVector(point),
01199                CubitVector(dir), ray_params);
01200     assert(CUBIT_SUCCESS == result);
01201     if(CUBIT_SUCCESS != result) return MB_FAILURE;
01202     if (ray_params.size() != 0) {
01203       ray_params.reset();
01204       *dit = ray_params.get();
01205     }
01206     else *dit = huge_val;
01207   }
01208   
01209     // now bubble sort list
01210   bool done = false;
01211   while (!done) {
01212     dit = distances.begin();
01213     sit = surfaces.begin();
01214     done = true;
01215     for (; dit != distances.end(); dit++, sit++) {
01216       if (dit+1 != distances.end() && *dit > *(dit+1)) {
01217         double tmp_dist = *dit;
01218         *dit = *(dit+1);
01219         *(dit+1) = tmp_dist;
01220         EntityHandle tmp_hand = *sit;
01221         *sit = *(sit+1);
01222         *(sit+1) = tmp_hand;
01223         done = false;
01224       }
01225     }
01226   }
01227 
01228   if (!distances.empty()) len = distances[0];
01229   
01230   return MB_SUCCESS;
01231 #endif
01232 #else
01233   return MB_FAILURE;
01234 #endif
01235 }
01236 
01237 // If point is on boundary, then this function is called to 
01238 // discriminate cases in which the ray is entering or leaving.
01239 // result= 1 -> inside volume or entering volume
01240 // result= 0 -> outside volume or leaving volume
01241 // result=-1 -> on boundary with null or tangent uvw
01242 ErrorCode DagMC::boundary_case( EntityHandle volume, int& result, 
01243                                 double u, double v, double w,
01244                                 EntityHandle facet,
01245                                 EntityHandle surface)
01246 {
01247   ErrorCode rval;
01248 
01249   // test to see if uvx is provided
01250   if ( u <= 1.0 && v <= 1.0 && w <= 1.0 ) {
01251 
01252     const CartVect ray_vector(u, v, w);
01253     CartVect coords[3], normal(0.0);
01254     const EntityHandle *conn;
01255     int len, sense_out;
01256    
01257     rval = mbImpl->get_connectivity( facet, conn, len );
01258     assert( MB_SUCCESS == rval );
01259     if(MB_SUCCESS != rval) return rval;
01260     assert( 3 == len );
01261   
01262     rval = mbImpl->get_coords( conn, 3, coords[0].array() );
01263     assert(MB_SUCCESS == rval);
01264     if(MB_SUCCESS != rval) return rval;
01265    
01266     rval = surface_sense( volume, surface, sense_out );
01267     assert( MB_SUCCESS == rval);
01268     if(MB_SUCCESS != rval) return rval;
01269 
01270     coords[1] -= coords[0];
01271     coords[2] -= coords[0];
01272     normal = sense_out * (coords[1] * coords[2]);
01273 
01274     double sense = ray_vector % normal;
01275 
01276     if ( sense < 0.0 ) {
01277       result = 1;     // inside or entering
01278     } else  if ( sense > 0.0 ) {
01279       result = 0;     // outside or leaving
01280     } else  if ( sense == 0.0 ) {
01281       result = -1;    // tangent, therefore on boundary
01282     } else {
01283       result = -1;    // failure
01284       return MB_FAILURE;
01285     }
01286   
01287   // if uvw not provided, return on_boundary.
01288   } else {
01289     result = -1;      // on boundary
01290     return MB_SUCCESS;
01291   
01292   }
01293 
01294   return MB_SUCCESS;
01295 }
01296 
01297 // point_in_volume_slow, including poly_solid_angle helper subroutine
01298 // are adapted from "Point in Polyhedron Testing Using Spherical Polygons", Paulo Cezar 
01299 // Pinto Carvalho and Paulo Roma Cavalcanti, _Graphics Gems V_, pg. 42.  Original algorithm
01300 // was described in "An Efficient Point In Polyhedron Algortihm", Jeff Lane, Bob Magedson, 
01301 // and Mike Rarick, _Computer Visoin, Graphics, and Image Processing 26_, pg. 118-225, 1984.
01302 
01303 // helper function for point_in_volume_slow.  calculate area of a polygon 
01304 // projected into a unit-sphere space
01305    ErrorCode DagMC::poly_solid_angle( EntityHandle face, const CartVect& point, double& area )
01306 {
01307   ErrorCode rval;
01308   
01309     // Get connectivity
01310   const EntityHandle* conn;
01311   int len;
01312   rval = MBI->get_connectivity( face, conn, len, true );
01313   if (MB_SUCCESS != rval)
01314     return rval;
01315   
01316     // Allocate space to store vertices
01317   CartVect coords_static[4];
01318   std::vector<CartVect> coords_dynamic;
01319   CartVect* coords = coords_static;
01320   if ((unsigned)len > (sizeof(coords_static)/sizeof(coords_static[0]))) {
01321     coords_dynamic.resize(len);
01322     coords = &coords_dynamic[0];
01323   }
01324   
01325     // get coordinates
01326   rval = MBI->get_coords( conn, len, coords->array() );
01327   if (MB_SUCCESS != rval)
01328     return rval;
01329   
01330     // calculate normal
01331   CartVect norm(0.0), v1, v0 = coords[1] - coords[0];
01332   for (int i = 2; i < len; ++i) {
01333     v1 = coords[i] - coords[0];
01334     norm += v0 * v1;
01335     v0 = v1;
01336   }
01337   
01338     // calculate area
01339   double s, ang;
01340   area = 0.0;
01341   CartVect r, n1, n2, b, a = coords[len-1] - coords[0];
01342   for (int i = 0; i < len; ++i) {
01343     r = coords[i] - point;
01344     b = coords[(i+1)%len] - coords[i];
01345     n1 = a * r; // = norm1 (magnitude is important)
01346     n2 = r * b; // = norm2 (magnitude is important)
01347     s = (n1 % n2) / (n1.length() * n2.length()); // = cos(angle between norm1,norm2)
01348     ang = s <= -1.0 ? M_PI : s >= 1.0 ? 0.0 : acos(s); // = acos(s)
01349     s = (b * a) % norm; // =orientation of triangle wrt point
01350     area += s > 0.0 ? M_PI - ang : M_PI + ang;
01351     a = -b;
01352   }
01353   
01354   area -= M_PI * (len - 2);
01355   if ((norm % r) > 0)
01356     area = -area;
01357   return MB_SUCCESS;
01358 }
01359   
01360 /* SECTION III */
01361 
01362 EntityHandle DagMC::entity_by_id( int dimension, int id )
01363 {
01364   assert(0 <= dimension && 3 >= dimension);
01365   const Tag tags[] = { idTag, geomTag };
01366   const void* const vals[] = { &id, &dimension };
01367   ErrorCode rval;
01368   
01369   Range results;
01370   rval = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, tags, vals, 2, results );
01371 
01372   if ( MB_SUCCESS != rval ) 
01373       return 0;
01374 
01375   if ( results.empty() ){
01376     // old versions of dagmc did not set tags correctly on the implicit complement 'volume',
01377     // causing it to not be found by the call above.  This check allows this function to work
01378     // correctly, even on reloaded files from older versions.
01379     if( dimension == 3 && get_entity_id(impl_compl_handle) == id )
01380       return impl_compl_handle;
01381     else 
01382       return 0; 
01383   }
01384   
01385   return results.front();
01386 }
01387 
01388 int DagMC::id_by_index( int dimension, int index )
01389 {
01390   EntityHandle h = entity_by_index( dimension, index );
01391   if (!h)
01392     return 0;
01393   
01394   int result = 0;
01395   MBI->tag_get_data( idTag, &h, 1, &result );
01396   return result;
01397 }
01398 
01399 int DagMC::get_entity_id(EntityHandle this_ent) 
01400 {
01401   int id = 0;
01402   ErrorCode result = MBI->tag_get_data(idTag, &this_ent, 1, &id);
01403   if (MB_TAG_NOT_FOUND == result)
01404     id = MBI->id_from_handle(this_ent);
01405     
01406   return id;
01407 }
01408 
01409 ErrorCode DagMC::build_indices(Range &surfs, Range &vols)
01410 {
01411   ErrorCode rval = MB_SUCCESS;
01412 
01413     // surf/vol offsets are just first handles
01414   setOffset = std::min( *surfs.begin(), *vols.begin() );
01415 
01416     // max
01417   EntityHandle tmp_offset = std::max( surfs.back(), vols.back() );
01418 
01419     // set size
01420   rootSets.resize(tmp_offset - setOffset + 1);
01421   entIndices.resize(rootSets.size());
01422 
01423     // store surf/vol handles lists (surf/vol by index) and
01424     // index by handle lists
01425   surf_handles().resize( surfs.size() + 1 );
01426   std::vector<EntityHandle>::iterator iter = surf_handles().begin();
01427   *(iter++) = 0;
01428   std::copy( surfs.begin(), surfs.end(), iter );
01429   int idx = 1;
01430   for (Range::iterator rit = surfs.begin(); rit != surfs.end(); rit++)
01431     entIndices[*rit-setOffset] = idx++;
01432   
01433   vol_handles().resize( vols.size() + 1 );
01434   iter = vol_handles().begin();
01435   *(iter++) = 0;
01436   std::copy( vols.begin(), vols.end(), iter );
01437 
01438   idx = 1;
01439   int max_id = -1;
01440   for (Range::iterator rit = vols.begin(); rit != vols.end(); rit++)    {
01441     entIndices[*rit-setOffset] = idx++;
01442 
01443     if( *rit != impl_compl_handle ){
01444       int result=0;
01445       MBI->tag_get_data( idTag, &*rit, 1, &result );
01446       max_id = std::max( max_id, result ); 
01447     }
01448   }
01449     // assign ID to implicit complement
01450     // for consistency with earlier versions of DagMC, make sure it always has the highest ID
01451   max_id++;
01452   MBI->tag_set_data(idTag, &impl_compl_handle, 1, &max_id);
01453 
01454 #ifdef CGM
01455   if ( have_cgm_geom ) {
01456     // TODO: this block should only execute if the user has explicitly requested useCAD for ray firing.
01457     // however, this function curently executes before we know if useCAD will be specified, so do it every time.
01458 
01459     geomEntities.resize(rootSets.size());
01460       // get geometry entities by id and cache in this vector
01461     std::vector<int> ids;
01462     ids.resize(surfs.size());
01463     rval = MBI->tag_get_data(id_tag(), surfs, &ids[0]);
01464     if (MB_SUCCESS != rval) return MB_FAILURE;
01465     int i = 0;
01466     Range::iterator rit = surfs.begin();
01467     for (; rit != surfs.end(); rit++, i++) {
01468       RefEntity *this_surf = GeometryQueryTool::instance()->
01469         get_ref_face(ids[i]);
01470       assert(NULL != this_surf);
01471       geomEntities[*rit - setOffset] = this_surf;
01472     }
01473     ids.resize(vols.size());
01474     rval = MBI->tag_get_data(id_tag(), vols, &ids[0]);
01475     if (MB_SUCCESS != rval) return MB_FAILURE;
01476     i = 0;
01477     rit = vols.begin();
01478     for (; rit != vols.end(); rit++, i++) {
01479       if( is_implicit_complement( *rit ) ) continue;
01480       RefEntity *this_vol = GeometryQueryTool::instance()->
01481         get_ref_volume(ids[i]);
01482       assert(NULL != this_vol);
01483       geomEntities[*rit - setOffset] = this_vol;
01484     }
01485   }
01486 #endif  
01487 
01488     // get group handles
01489   Tag category_tag = get_tag(CATEGORY_TAG_NAME, CATEGORY_TAG_LENGTH, 
01490                                MB_TAG_SPARSE, MB_TYPE_OPAQUE);
01491   char group_category[CATEGORY_TAG_SIZE];
01492   std::fill(group_category, group_category+CATEGORY_TAG_SIZE, '\0');
01493   sprintf(group_category, "%s", "Group");
01494   const void* const group_val[] = {&group_category};
01495   Range groups;
01496   rval = MBI->get_entities_by_type_and_tag(0, MBENTITYSET, &category_tag, 
01497                                            group_val, 1, groups);
01498   if (MB_SUCCESS != rval)
01499     return rval;
01500   group_handles().resize(groups.size()+1);
01501   group_handles()[0] = 0;
01502   std::copy(groups.begin(), groups.end(), &group_handles()[1]);
01503 
01504     // populate root sets vector
01505   std::vector<EntityHandle> rsets;
01506   rsets.resize(surfs.size());
01507   rval = MBI->tag_get_data(obb_tag(), surfs, &rsets[0]);
01508   if (MB_SUCCESS != rval) return MB_FAILURE;
01509   Range::iterator rit;
01510   int i;
01511   for (i = 0, rit = surfs.begin(); rit != surfs.end(); rit++, i++)
01512     rootSets[*rit-setOffset] = rsets[i];
01513 
01514   rsets.resize(vols.size());
01515   rval = MBI->tag_get_data(obb_tag(), vols, &rsets[0]);
01516   if (MB_SUCCESS != rval) return MB_FAILURE;
01517   for (i = 0, rit = vols.begin(); rit != vols.end(); rit++, i++)
01518     rootSets[*rit-setOffset] = rsets[i];
01519 
01520   return MB_SUCCESS;
01521 }
01522 
01523 
01524 
01525 /* SECTION IV */  
01526 
01527 void DagMC::set_overlap_thickness( double new_thickness ){
01528 
01529   if (new_thickness < 0 || new_thickness > 100) {
01530     std::cerr << "Invalid overlap_thickness = " << new_thickness << std::endl;
01531   }
01532   else{
01533     overlapThickness = new_thickness;
01534   }
01535   std::cout << "Set overlap thickness = " << overlapThickness << std::endl;
01536 
01537 }
01538 
01539 void DagMC::set_numerical_precision( double new_precision ){
01540 
01541   if ( new_precision <= 0 || new_precision > 1) {
01542     std::cerr << "Invalid numerical_precision = " << numericalPrecision << std::endl;
01543   }
01544   else{
01545     numericalPrecision = new_precision;
01546   }
01547 
01548   std::cout << "Set numerical precision = " << numericalPrecision << std::endl;
01549 
01550 }
01551 
01552 void DagMC::set_use_CAD( bool use_cad ){
01553   useCAD = use_cad;
01554   if( useCAD ){
01555     if( !have_cgm_geom ){
01556       std::cerr << "Warning: CAD-based ray tracing not avaiable, because CGM has no data." << std::endl;
01557       std::cerr << "         your input file was probably not a CAD format." << std::endl;
01558       useCAD = false;
01559     }
01560 
01561 #ifndef HAVE_CGM_FIRE_RAY
01562     {
01563       std::cerr << "Warning: use_cad = 1 not supported with this build of CGM/DagMC." << std:: endl;
01564       std::cerr << "         Required ray-fire query not available. (Cubit-based CGM?)" <<  std::endl;
01565       useCAD = false;
01566     }
01567 #endif
01568   }
01569 
01570   std::cout << "Turned " << (useCAD?"ON":"OFF") << " ray firing on full CAD model." << std::endl;
01571 
01572 }
01573 
01574 ErrorCode DagMC::write_mesh(const char* ffile,
01575                             const int flen)
01576 {
01577   ErrorCode rval;
01578   
01579     // write out a mesh file if requested
01580   if (ffile && 0 < flen) {
01581     rval = MBI->write_mesh(ffile);
01582     if (MB_SUCCESS != rval) {
01583       std::cerr << "Failed to write mesh to " << ffile << "." << std::endl;
01584       return rval;
01585     }
01586   }
01587  
01588   return MB_SUCCESS;
01589 }
01590 
01591 /* SECTION V: Metadata handling */
01592 
01593 ErrorCode DagMC::get_group_name( EntityHandle group_set, std::string& name )
01594 {
01595   ErrorCode rval;
01596   const void* v = NULL;
01597   int ignored;
01598   rval = MBI->tag_get_by_ptr(name_tag(), &group_set, 1, &v, &ignored);
01599   if( MB_SUCCESS != rval ) return rval;
01600   name = static_cast<const char*>(v);
01601   return MB_SUCCESS;
01602 }
01603 
01604 ErrorCode DagMC::parse_group_name( EntityHandle group_set, prop_map& result )
01605 {
01606   ErrorCode rval;
01607   std::string group_name;
01608   rval = get_group_name( group_set, group_name );
01609   if( rval != MB_SUCCESS ) return rval;
01610 
01611   std::vector< std::string > group_tokens;
01612   tokenize( group_name, group_tokens, "_" );
01613 
01614   // iterate over all the keyword positions 
01615   // keywords are even indices, their values (optional) are odd indices
01616   for( unsigned int i = 0; i < group_tokens.size(); i += 2 ){
01617     std::string groupkey = group_tokens[i];
01618     std::string groupval;
01619     if( i < group_tokens.size() - 1 )
01620       groupval = group_tokens[i+1];
01621     result[groupkey] = groupval;
01622   }
01623   return MB_SUCCESS;
01624 }
01625 
01626 ErrorCode DagMC::detect_available_props( std::vector<std::string>& keywords_list )
01627 {
01628   ErrorCode rval;
01629   std::set< std::string > keywords;
01630   for( std::vector<EntityHandle>::const_iterator grp=group_handles().begin();
01631        grp != group_handles().end(); ++grp )
01632   {
01633     std::map< std::string, std::string > properties;
01634     rval = parse_group_name( *grp, properties );
01635     if( rval == MB_TAG_NOT_FOUND ) continue;
01636     else if( rval != MB_SUCCESS ) return rval;
01637 
01638     for( prop_map::iterator i = properties.begin();
01639          i != properties.end(); ++i )
01640     {
01641       keywords.insert( (*i).first );
01642     }
01643   }
01644   keywords_list.assign( keywords.begin(), keywords.end() );
01645   return MB_SUCCESS;
01646 }
01647 
01648 ErrorCode DagMC::append_packed_string( Tag tag, EntityHandle eh,
01649                                        std::string& new_string )
01650 {
01651     // When properties have multiple values, the values are tagged in a single character array
01652     // with the different values separated by null characters
01653   ErrorCode rval;
01654   const void* p;
01655   const char* str;
01656   int len;
01657   rval = MBI->tag_get_by_ptr( tag, &eh, 1, &p, &len );
01658   if( rval == MB_TAG_NOT_FOUND ){
01659     // This is the first entry, and can be set directly
01660     p = new_string.c_str();
01661     return MBI->tag_clear_data( tag, &eh, 1, p, new_string.length()+1);
01662   }
01663   else if( rval != MB_SUCCESS ) return rval;
01664   else{ 
01665     str = static_cast<const char*>(p);
01666   }
01667 
01668   // append a new value for the property to the existing property string
01669   unsigned int tail_len = new_string.length() + 1;
01670   char* new_packed_string = new char[ len + tail_len ];
01671   memcpy( new_packed_string, str, len );
01672   memcpy( new_packed_string + len, new_string.c_str(), tail_len );
01673 
01674   int new_len = len + tail_len;
01675   p = new_packed_string;
01676   rval = MBI->tag_set_by_ptr( tag, &eh, 1, &p, &new_len );
01677   delete[] new_packed_string;
01678   return rval;
01679 }
01680 
01681 ErrorCode DagMC::unpack_packed_string( Tag tag, EntityHandle eh, 
01682                                        std::vector< std::string >& values )
01683 {
01684   ErrorCode rval;
01685   const void* p;
01686   const char* str;
01687   int len;
01688   rval = MBI->tag_get_by_ptr( tag, &eh, 1, &p, &len );
01689   if( rval != MB_SUCCESS ) return rval;
01690   str = static_cast<const char*>(p);
01691   int idx = 0;
01692   while( idx < len ){
01693     std::string item(str + idx);
01694     values.push_back( item );
01695     idx += item.length() + 1;
01696   }
01697   return MB_SUCCESS;
01698 }
01699 
01700 ErrorCode DagMC::parse_properties( const std::vector<std::string>& keywords,
01701                                    const std::map<std::string, std::string>& keyword_synonyms )
01702 {
01703   ErrorCode rval;
01704 
01705   // master keyword map, mapping user-set words in cubit to canonical property names
01706   std::map< std::string, std::string > keyword_map( keyword_synonyms );
01707 
01708   for( std::vector<std::string>::const_iterator i = keywords.begin();
01709        i != keywords.end(); ++i )
01710   {
01711     keyword_map[*i] = *i;
01712   }
01713 
01714   // the set of all canonical property names
01715   std::set< std::string > prop_names;
01716   for( prop_map::iterator i = keyword_map.begin();
01717        i != keyword_map.end(); ++i )
01718   {
01719     prop_names.insert((*i).second);
01720   }
01721 
01722   // set up DagMC's property tags based on what's been requested
01723   for( std::set<std::string>::iterator i = prop_names.begin();
01724        i != prop_names.end(); ++i )
01725   {
01726     std::string tagname("DAGMCPROP_");
01727     tagname += (*i);
01728 
01729     Tag new_tag;
01730     rval = MBI->tag_get_handle( tagname.c_str(), 0, MB_TYPE_OPAQUE, new_tag,
01731                                 MB_TAG_SPARSE|MB_TAG_VARLEN|MB_TAG_CREAT );
01732     if( MB_SUCCESS != rval ) return rval;
01733     property_tagmap[(*i)] = new_tag;
01734   }
01735 
01736   // now that the keywords and tags are ready, iterate over all the actual geometry groups
01737   for( std::vector<EntityHandle>::iterator grp=group_handles().begin();
01738        grp != group_handles().end(); ++grp )
01739   {
01740 
01741     prop_map properties;
01742     rval = parse_group_name( *grp, properties );
01743     if( rval == MB_TAG_NOT_FOUND ) continue;
01744     else if( rval != MB_SUCCESS ) return rval;
01745 
01746     Range grp_sets;
01747     rval = MBI->get_entities_by_type( *grp, MBENTITYSET, grp_sets);
01748     if( MB_SUCCESS != rval ) return rval;
01749     if( grp_sets.size() == 0 ) continue;
01750 
01751     for( prop_map::iterator i = properties.begin(); 
01752          i != properties.end(); ++i )
01753     {
01754       std::string groupkey = (*i).first;
01755       std::string groupval = (*i).second;
01756 
01757       if( property_tagmap.find( groupkey ) != property_tagmap.end() ){
01758         Tag proptag = property_tagmap[groupkey];
01759         const unsigned int groupsize = grp_sets.size();
01760         for( unsigned int j = 0; j < groupsize; ++j){
01761             rval = append_packed_string( proptag, grp_sets[j], groupval );
01762         }
01763       }
01764     }
01765   }
01766   return MB_SUCCESS;
01767 }
01768 
01769 ErrorCode DagMC::prop_value( EntityHandle eh, const std::string& prop, std::string& value )
01770 {
01771   ErrorCode rval;
01772 
01773   std::map<std::string, Tag>::iterator it = property_tagmap.find(prop);
01774   if( it == property_tagmap.end() ){
01775       return MB_TAG_NOT_FOUND;
01776   }
01777 
01778   Tag proptag = (*it).second;
01779   const void* data; 
01780   int ignored;
01781 
01782   rval = MBI->tag_get_by_ptr( proptag, &eh, 1, &data, &ignored );
01783   if( rval != MB_SUCCESS ) return rval;
01784   value = static_cast<const char*>(data);
01785   return MB_SUCCESS;
01786 }
01787 
01788 ErrorCode DagMC::prop_values( EntityHandle eh, const std::string& prop, 
01789                               std::vector< std::string >& values )
01790 {
01791 
01792   std::map<std::string, Tag>::iterator it = property_tagmap.find(prop);
01793   if( it == property_tagmap.end() ){
01794       return MB_TAG_NOT_FOUND;
01795   }
01796   Tag proptag = (*it).second;
01797 
01798   return unpack_packed_string( proptag, eh, values );
01799 
01800 }
01801 
01802 bool DagMC::has_prop( EntityHandle eh, const std::string& prop )
01803 {
01804   ErrorCode rval;
01805 
01806   std::map<std::string, Tag>::iterator it = property_tagmap.find(prop);
01807   if( it == property_tagmap.end() ){
01808       return false;
01809   }
01810 
01811   Tag proptag = (*it).second;
01812   const void* data; 
01813   int ignored;
01814 
01815   rval = MBI->tag_get_by_ptr( proptag, &eh, 1, &data, &ignored );
01816   return ( rval == MB_SUCCESS );
01817 
01818 }
01819 
01820 
01821 ErrorCode DagMC::get_all_prop_values( const std::string& prop, std::vector<std::string>& return_list )
01822 {
01823   ErrorCode rval;
01824   std::map<std::string, Tag>::iterator it = property_tagmap.find(prop);
01825   if( it == property_tagmap.end() ){
01826     return MB_TAG_NOT_FOUND;
01827   }
01828   Tag proptag = (*it).second;
01829   Range all_ents;
01830 
01831   rval = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, &proptag, NULL, 1, all_ents );
01832   if( MB_SUCCESS != rval ) return rval;
01833 
01834   std::set<std::string> unique_values;
01835   for( Range::iterator i = all_ents.begin(); i!= all_ents.end(); ++i){
01836     std::vector<std::string> values;
01837     rval = prop_values( *i, prop, values );
01838     if( MB_SUCCESS != rval ) return rval;
01839     unique_values.insert( values.begin(), values.end() );
01840   }
01841 
01842   return_list.assign( unique_values.begin(), unique_values.end() );
01843   return MB_SUCCESS;
01844 }
01845 
01846 ErrorCode DagMC::entities_by_property( const std::string& prop, std::vector<EntityHandle>& return_list,
01847                                        int dimension, const std::string* value )
01848 {
01849   ErrorCode rval;
01850   std::map<std::string, Tag>::iterator it = property_tagmap.find(prop);
01851   if( it == property_tagmap.end() ){
01852     return MB_TAG_NOT_FOUND;
01853   }
01854   Tag proptag = (*it).second;
01855   Range all_ents;
01856 
01857   // Note that we cannot specify values for proptag here-- the passed value,
01858   // if it exists, may be only a subset of the packed string representation
01859   // of this tag.
01860   Tag tags[2] = {proptag, geomTag };
01861   void* vals[2] = {NULL, (dimension!=0) ? &dimension : NULL };
01862   rval = MBI->get_entities_by_type_and_tag( 0, MBENTITYSET, tags, vals, 2, all_ents );
01863   if( MB_SUCCESS != rval ) return rval;
01864 
01865   std::set<EntityHandle> handles;
01866   for( Range::iterator i = all_ents.begin(); i!=all_ents.end(); ++i){
01867     std::vector<std::string> values;
01868     rval = prop_values( *i, prop, values );
01869     if( MB_SUCCESS != rval ) return rval;
01870     if( value ){
01871       if( std::find(values.begin(), values.end(), *value) != values.end() ){
01872         handles.insert(*i);
01873       }
01874     }
01875     else{
01876       handles.insert(*i);
01877     }
01878   }
01879 
01880   return_list.assign( handles.begin(), handles.end() );
01881   return MB_SUCCESS;
01882 }
01883 
01884 bool DagMC::is_implicit_complement(EntityHandle volume)
01885 {
01886   return volume == impl_compl_handle;
01887 }
01888 
01889 void DagMC::tokenize( const std::string& str,
01890                       std::vector<std::string>& tokens,
01891                       const char* delimiters ) const
01892 {
01893   std::string::size_type last = str.find_first_not_of( delimiters, 0 );
01894   std::string::size_type pos  = str.find_first_of( delimiters, last );
01895   if ( std::string::npos == pos )
01896     tokens.push_back(str);
01897   else
01898     while (std::string::npos != pos && std::string::npos != last) {
01899       tokens.push_back( str.substr( last, pos - last ) );
01900       last = str.find_first_not_of( delimiters, pos );
01901       pos  = str.find_first_of( delimiters, last );
01902       if(std::string::npos == pos)
01903         pos = str.size();
01904     }
01905 }
01906 
01907 Tag DagMC::get_tag( const char* name, int size, TagType store, 
01908                     DataType type, const void* def_value,
01909                     bool create_if_missing) 
01910 {
01911   Tag retval = 0;
01912   unsigned flags = store|MB_TAG_CREAT;
01913   // NOTE: this function seens to be broken in that create_if_missing has
01914   // the opposite meaning from what its name implies.  However, changing the
01915   // behavior causes tests to fail, so I'm leaving the existing behavior
01916   // in place.  -- j.kraftcheck.
01917   if (!create_if_missing)  
01918     flags |= MB_TAG_EXCL;
01919   ErrorCode result = MBI->tag_get_handle(name, size, type, retval, flags, def_value);
01920   if (create_if_missing && MB_SUCCESS != result) 
01921     std::cerr << "Couldn't find nor create tag named " << name << std::endl;
01922   
01923   return retval;
01924 }
01925 
01926 
01927 ErrorCode DagMC::getobb(EntityHandle volume, double minPt[3],
01928                           double maxPt[3])
01929 {
01930   double center[3], axis1[3], axis2[3], axis3[3];
01931  
01932     // get center point and vectors to OBB faces
01933   ErrorCode rval = getobb(volume, center, axis1, axis2, axis3);
01934   if (MB_SUCCESS != rval)
01935     return rval;
01936      
01937     // compute min and max verticies
01938   for (int i=0; i<3; i++) 
01939   {
01940     double sum = fabs(axis1[i]) + fabs(axis2[i]) + fabs(axis3[i]);
01941     minPt[i] = center[i] - sum;
01942     maxPt[i] = center[i] + sum;
01943   }
01944   return MB_SUCCESS;
01945 }
01946 
01947 ErrorCode DagMC::getobb(EntityHandle volume, double center[3], double axis1[3],
01948                           double axis2[3], double axis3[3])
01949 {
01950     //find EntityHandle node_set for use in box
01951   EntityHandle root = rootSets[volume - setOffset];
01952   
01953     // call box to get center and vectors to faces
01954   return obbTree.box(root, center, axis1, axis2, axis3);
01955   
01956 }
01957 
01958 
01959 } // namespace moab
01960 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines