moab
|
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