moab
DualTool.cpp
Go to the documentation of this file.
00001 
00016 #include "moab/DualTool.hpp"
00017 #include "moab/Range.hpp"
00018 // using Core for call to check_adjacencies
00019 #include "moab/Core.hpp"
00020 #include "Internals.hpp"
00021 #include "MBTagConventions.hpp"
00022 #include "moab/Skinner.hpp"
00023 #include "moab/Core.hpp"
00024 #include "moab/MeshTopoUtil.hpp"
00025 #include "AEntityFactory.hpp"
00026 #include "moab/CN.hpp"
00027 #include <string>
00028 #include <algorithm>
00029 #include <iostream>
00030 #include <sstream>
00031 #include <assert.h>
00032 
00033 #define RR if (MB_SUCCESS != result) return result
00034 #define SWAP(a,b) {EntityHandle tmp_ent = a; a = b; b = tmp_ent;}
00035 
00036 namespace moab {
00037 
00038 bool debug = false;
00039 bool debug_ap = false;
00040 
00042 const char *DualTool::DUAL_SURFACE_TAG_NAME = "DUAL_SURFACE";
00043 
00045 const char *DualTool::DUAL_CURVE_TAG_NAME = "DUAL_CURVE";
00046 
00048 const char *DualTool::IS_DUAL_CELL_TAG_NAME = "__IS_DUAL_CELL";
00049 
00051 const char *DualTool::DUAL_ENTITY_TAG_NAME = "__DUAL_ENTITY";
00052 
00054 const char *DualTool::EXTRA_DUAL_ENTITY_TAG_NAME = "__EXTRA_DUAL_ENTITY";
00055 
00057 const char *DualTool::DUAL_GRAPHICS_POINT_TAG_NAME = "__DUAL_GRAPHICS_POINT";
00058 
00059 //const int DualTool::GP_SIZE = 20;
00060 
00061 DualTool::DualTool(Interface *impl) 
00062     : mbImpl(impl)
00063 {
00064   EntityHandle dum_handle = 0;
00065   ErrorCode result;
00066   
00067   result = mbImpl->tag_get_handle( DUAL_SURFACE_TAG_NAME, 
00068                                    1, MB_TYPE_HANDLE, 
00069                                    dualSurfaceTag,
00070                                    MB_TAG_SPARSE|MB_TAG_CREAT,
00071                                    &dum_handle );
00072   assert(MB_SUCCESS == result);
00073   
00074   result = mbImpl->tag_get_handle( DUAL_CURVE_TAG_NAME, 
00075                                    1, MB_TYPE_HANDLE, 
00076                                    dualCurveTag,
00077                                    MB_TAG_SPARSE|MB_TAG_CREAT,
00078                                    &dum_handle );
00079   assert(MB_SUCCESS == result);
00080   
00081   unsigned int dummy = 0;
00082   result = mbImpl->tag_get_handle( IS_DUAL_CELL_TAG_NAME, 
00083                                    1, MB_TYPE_INTEGER,
00084                                    isDualCellTag,
00085                                    MB_TAG_SPARSE|MB_TAG_CREAT, 
00086                                    &dummy);
00087   assert(MB_SUCCESS == result);
00088 
00089   result = mbImpl->tag_get_handle( DUAL_ENTITY_TAG_NAME, 
00090                                    1, MB_TYPE_HANDLE, 
00091                                    dualEntityTag,
00092                                    MB_TAG_DENSE|MB_TAG_CREAT,
00093                                    &dum_handle );
00094   assert(MB_SUCCESS == result);
00095   
00096   result = mbImpl->tag_get_handle( EXTRA_DUAL_ENTITY_TAG_NAME, 
00097                                    1, MB_TYPE_HANDLE, 
00098                                    extraDualEntityTag,
00099                                    MB_TAG_SPARSE|MB_TAG_CREAT,
00100                                    &dum_handle );
00101   assert(MB_SUCCESS == result);
00102   
00103   static const char dum_name[CATEGORY_TAG_SIZE] = {0};
00104   result = mbImpl->tag_get_handle( CATEGORY_TAG_NAME,
00105                                    CATEGORY_TAG_SIZE, MB_TYPE_OPAQUE,
00106                                    categoryTag,
00107                                    MB_TAG_SPARSE|MB_TAG_CREAT,
00108                                    dum_name );
00109   assert(MB_SUCCESS == result);
00110   
00111   DualTool::GraphicsPoint dum_pt(0.0, 0.0, 0.0, -1);
00112   result = mbImpl->tag_get_handle(DUAL_GRAPHICS_POINT_TAG_NAME, 
00113                                   sizeof(DualTool::GraphicsPoint), MB_TYPE_DOUBLE, 
00114                                   dualGraphicsPointTag, 
00115                                   MB_TAG_DENSE|MB_TAG_CREAT|MB_TAG_BYTES,
00116                                   &dum_pt);
00117   assert(MB_SUCCESS == result);
00118 
00119   int dum_int = 0;
00120   result = mbImpl->tag_get_handle( GLOBAL_ID_TAG_NAME, 
00121                                    1, MB_TYPE_INTEGER,
00122                                    globalIdTag,
00123                                    MB_TAG_SPARSE|MB_TAG_CREAT, 
00124                                    &dum_int);
00125   assert(MB_SUCCESS == result);
00126   if (MB_SUCCESS == result) {} // empty statement to get rid of warning.
00127   
00128   maxHexId = -1;
00129 }
00130 
00131 DualTool::~DualTool() 
00132 {}
00133 
00135 ErrorCode DualTool::construct_dual(EntityHandle *entities, 
00136                                      const int num_entities) 
00137 {
00138     // allocate a dual entity for each primal entity in the mesh, starting
00139     // with highest dimension and working downward; do each dimension in a separate code
00140     // block, since they're all handled slightly differently
00141   
00142   Range regions, faces, edges, vertices;
00143   ErrorCode result;
00144 
00145   if (NULL == entities || 0 == num_entities) {
00146     
00147       // first, construct all the aentities, since they're currently needed to 
00148       // compute the dual
00149     result = mbImpl->get_entities_by_dimension(0, 0, vertices);
00150     if (MB_SUCCESS != result) return result;
00151 
00152     result = MeshTopoUtil(mbImpl).construct_aentities(vertices);
00153     if (MB_SUCCESS != result) return result;
00154 
00155       // get all edges, faces and regions now, so we don't need to filter out dual
00156       // entities later
00157   
00158     result = mbImpl->get_entities_by_dimension(0, 1, edges);
00159     if (MB_SUCCESS != result) return result;
00160     result = mbImpl->get_entities_by_dimension(0, 2, faces);
00161     if (MB_SUCCESS != result) return result;
00162     result = mbImpl->get_entities_by_dimension(0, 3, regions);
00163     if (MB_SUCCESS != result) return result;
00164 
00165       // get the max global id for hexes, we'll need for modification ops
00166     std::vector<int> gid_vec(regions.size());
00167     result = mbImpl->tag_get_data(globalId_tag(), regions, &gid_vec[0]);
00168     if (MB_SUCCESS != result) return result;
00169     maxHexId = -1;
00170     Range::iterator rit;
00171     unsigned int i;
00172     for (rit = regions.begin(), i = 0; rit != regions.end(); rit++, i++) {
00173       if (gid_vec[i] > maxHexId && mbImpl->type_from_handle(*rit) == MBHEX)
00174         maxHexId = gid_vec[i];
00175     }
00176   }
00177   else {
00178       // get entities of various dimensions adjacent to these
00179     result = mbImpl->get_adjacencies(entities, num_entities, 0, true, vertices, 
00180                                      Interface::UNION);
00181     if (MB_SUCCESS != result) return result;
00182     result = mbImpl->get_adjacencies(entities, num_entities, 1, true, edges,
00183                                      Interface::UNION);
00184     if (MB_SUCCESS != result) return result;
00185     result = mbImpl->get_adjacencies(entities, num_entities, 2, true, faces,
00186                                      Interface::UNION);
00187     if (MB_SUCCESS != result) return result;
00188     result = mbImpl->get_adjacencies(entities, num_entities, 3, true, regions,
00189                                      Interface::UNION);
00190     if (MB_SUCCESS != result) return result;
00191   
00192   }
00193   
00194   Range dual_verts;
00195   result = construct_dual_vertices(regions, dual_verts);
00196   if (MB_SUCCESS != result || dual_verts.size() != regions.size()) return result;
00197   if (debug)
00198     std::cout << "Constructed " << dual_verts.size() << " dual vertices." << std::endl;
00199 
00200     // don't really need dual edges, but construct 'em anyway
00201   Range dual_edges;
00202   result = construct_dual_edges(faces, dual_edges);
00203   if (MB_SUCCESS != result || dual_edges.size() != faces.size()) return result;
00204   if (debug)
00205     std::cout << "Constructed " << dual_edges.size() << " dual edges." << std::endl;
00206 
00207     // construct dual faces
00208   Range dual_faces;
00209   result = construct_dual_faces(edges, dual_faces);
00210   if (MB_SUCCESS != result || dual_faces.size() != edges.size()) return result;
00211   if (debug)
00212     std::cout << "Constructed " << dual_faces.size() << " dual faces." << std::endl;
00213 
00214     // construct dual cells
00215   Range dual_cells;
00216   result = construct_dual_cells(vertices, dual_cells);
00217   if (MB_SUCCESS != result || dual_cells.size() != vertices.size()) return result;
00218   if (debug)
00219     std::cout << "Constructed " << dual_cells.size() << " dual cells." << std::endl;
00220 
00221   return MB_SUCCESS;
00222 }
00223 
00224 ErrorCode DualTool::construct_dual_vertices(const Range &all_regions,
00225                                               Range &dual_ents) 
00226 {
00227   if (all_regions.empty()) return MB_SUCCESS;
00228   
00229     // make sure they're all regions
00230   assert(3 == CN::Dimension(TYPE_FROM_HANDLE(*all_regions.begin())) &&
00231          3 == CN::Dimension(TYPE_FROM_HANDLE(*all_regions.rbegin())));
00232   
00233   Range::const_iterator rit;
00234   EntityHandle dual_ent;
00235   ErrorCode tmp_result = MB_SUCCESS;
00236   ErrorCode result = MB_SUCCESS;
00237   
00238   for (rit = all_regions.begin(); rit != all_regions.end(); rit++) {
00239     if (tmp_result != MB_SUCCESS) result = tmp_result;
00240     
00241     tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &(*rit), 1, &dual_ent);
00242     if (MB_SUCCESS == tmp_result && 0 != dual_ent) {
00243       dual_ents.insert(dual_ent);
00244       continue;
00245     }
00246     else if (MB_SUCCESS != tmp_result) continue;
00247 
00248     tmp_result = construct_dual_vertex(*rit, dual_ent, false, true);
00249     if (MB_SUCCESS != tmp_result) continue;
00250 
00251       // save it in the list of new dual ents
00252     dual_ents.insert(dual_ent);
00253     
00254   }
00255 
00256   return result;
00257 }
00258 
00259 ErrorCode DualTool::construct_dual_vertex(EntityHandle entity, 
00260                                             EntityHandle &dual_ent, 
00261                                             const bool extra,
00262                                             const bool add_graphics_pt)
00263 {
00264     // no dual entity; construct one; first need the avg coordinates
00265   unsigned int is_dual = 0x1;
00266   double avg_pos[3];
00267   ErrorCode result = MeshTopoUtil(mbImpl).get_average_position(entity, avg_pos);
00268   if (MB_SUCCESS != result) return result;
00269     
00270     // now construct the new dual entity
00271   result = mbImpl->create_vertex(avg_pos, dual_ent);
00272   if (MB_SUCCESS != result) return result;
00273     
00274     // tag it indicating it's a dual entity
00275   result = mbImpl->tag_set_data(isDualCell_tag(), &dual_ent, 1, &is_dual);
00276   if (MB_SUCCESS != result) return result;
00277     
00278     // tag the primal entity with its dual entity and vica versa
00279   if (extra) 
00280     result = mbImpl->tag_set_data(extraDualEntity_tag(), &(entity), 1, &dual_ent);
00281   else
00282     result = mbImpl->tag_set_data(dualEntity_tag(), &(entity), 1, &dual_ent);
00283   if (MB_SUCCESS != result) return result;
00284     
00285   result = mbImpl->tag_set_data(dualEntity_tag(), &dual_ent, 1, &(entity));
00286   if (MB_SUCCESS != result) return result;
00287 
00288   if (add_graphics_pt)
00289         // put a graphics point on that vertex too
00290     result = add_graphics_point(dual_ent, avg_pos);
00291 
00292   return result;
00293 }
00294 
00295 ErrorCode DualTool::add_graphics_point(EntityHandle entity,
00296                                          double *avg_pos) 
00297 {
00298     // add a graphics pt, placed at the same position as the vertex
00299   double my_pos[3];
00300   ErrorCode result;
00301   
00302   if (NULL == avg_pos) {
00303     result = MeshTopoUtil(mbImpl).get_average_position(entity, my_pos);
00304     if (MB_SUCCESS != result) return result;
00305   }
00306   else
00307     for (int i = 0; i < 3; i++) my_pos[i] = avg_pos[i];
00308   
00309   DualTool::GraphicsPoint dum_pt(my_pos, -1);
00310   result = mbImpl->tag_set_data(dualGraphicsPoint_tag(), &entity, 1, 
00311                                 &dum_pt);
00312   return result;
00313 }
00314 
00315 ErrorCode DualTool::construct_dual_edges(const Range &all_faces,
00316                                            Range &dual_ents) 
00317 {
00318   if (all_faces.empty()) return MB_SUCCESS;
00319   
00320     // make sure they're all faces
00321   assert(2 == CN::Dimension(TYPE_FROM_HANDLE(*all_faces.begin())) &&
00322          2 == CN::Dimension(TYPE_FROM_HANDLE(*all_faces.rbegin())));
00323   
00324   Range::const_iterator rit;
00325   EntityHandle dual_ent;
00326   unsigned int is_dual = 0x1;
00327   ErrorCode tmp_result = MB_SUCCESS;
00328   ErrorCode result = MB_SUCCESS;
00329   
00330   for (rit = all_faces.begin(); rit != all_faces.end(); rit++) {
00331     if (tmp_result != MB_SUCCESS) result = tmp_result;
00332     
00333     tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &(*rit), 1, &dual_ent);
00334     if (MB_SUCCESS == tmp_result && 0 != dual_ent) {
00335       dual_ents.insert(dual_ent);
00336       continue;
00337     }
00338     
00339       // no dual entity; construct one; get the bounding regions
00340     std::vector<EntityHandle> in_ents, out_ents;
00341     tmp_result = mbImpl->get_adjacencies(&(*rit), 1, 3, false, out_ents);
00342     if (MB_SUCCESS != tmp_result || out_ents.empty()) continue;
00343 
00344       // get the dual vertices
00345     std::vector<EntityHandle> dual_verts(out_ents.size());
00346     tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &out_ents[0], out_ents.size(), 
00347                                       &dual_verts[0]);
00348     if (MB_SUCCESS != tmp_result) continue;
00349     assert(dual_verts.size() <= 2);
00350     
00351     double avg_pos[3];      
00352     bool bdy_face = (dual_verts.size() == 1 ? true : false);
00353     if (bdy_face) {
00354         // boundary face - make a dual vertex at the face center and put in list
00355       tmp_result = construct_dual_vertex(*rit, dual_ent, true, true);
00356       
00357         // put it on vertex list
00358       dual_verts.push_back(dual_ent);
00359     }
00360     
00361     assert(dual_verts.size() == 2);
00362     
00363       // now create the dual edge
00364     tmp_result = mbImpl->create_element(MBEDGE, &dual_verts[0], 2, dual_ent);
00365     if (MB_SUCCESS != tmp_result || 0 == dual_ent) continue;
00366     
00367       // save it in the list of new dual ents
00368     dual_ents.insert(dual_ent);
00369     
00370       // tag the primal entity with its dual entity and vica versa
00371     tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &(*rit), 1, &dual_ent);
00372     if (MB_SUCCESS != tmp_result) continue;
00373 
00374     tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &dual_ent, 1, &(*rit));
00375     if (MB_SUCCESS != tmp_result) continue;
00376 
00377       // tag the edge indicating it's a dual entity
00378     tmp_result = mbImpl->tag_set_data(isDualCell_tag(), &dual_ent, 1, &is_dual);
00379     if (MB_SUCCESS != tmp_result) continue;
00380 
00381       // add a graphics point to the edge; position depends on whether it's a
00382       // bdy face (mid-pt of dual edge) or not (mid-pt of primal face)
00383     if (bdy_face)
00384       tmp_result = add_graphics_point(dual_ent);
00385     else {
00386         // get the face's position
00387       tmp_result = MeshTopoUtil(mbImpl).get_average_position(*rit, avg_pos);
00388       if (MB_SUCCESS != tmp_result) continue;
00389       tmp_result = add_graphics_point(dual_ent, avg_pos);
00390     }
00391     if (MB_SUCCESS != tmp_result) continue;
00392   }
00393 
00394   return result;
00395 }
00396 
00397 ErrorCode DualTool::construct_dual_faces(const Range &all_edges,
00398                                            Range &dual_ents) 
00399 {
00400   if (all_edges.empty()) return MB_SUCCESS;
00401   
00402     // make sure they're all edges
00403   assert(1 == CN::Dimension(TYPE_FROM_HANDLE(*all_edges.begin())) &&
00404          1 == CN::Dimension(TYPE_FROM_HANDLE(*all_edges.rbegin())));
00405   
00406   Range::const_iterator rit;
00407   EntityHandle dual_ent;
00408   unsigned int is_dual = 0x1;
00409   ErrorCode tmp_result = MB_SUCCESS;
00410   ErrorCode result = MB_SUCCESS;
00411   Range equiv_edges;
00412 #define TRC if (MB_SUCCESS != tmp_result) {result = tmp_result; continue;}
00413   for (rit = all_edges.begin(); rit != all_edges.end(); rit++) {
00414     
00415     tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &(*rit), 1, &dual_ent);
00416     if (MB_SUCCESS == tmp_result && 0 != dual_ent) {
00417       dual_ents.insert(dual_ent);
00418       continue;
00419     }
00420     
00421       // no dual entity; construct one; get the dual vertices bounding the edge in radial order,
00422       // then construct the dual face
00423     std::vector<EntityHandle> rad_dverts;
00424     bool bdy_edge;
00425     tmp_result = get_radial_dverts(*rit, rad_dverts, bdy_edge);TRC
00426     if (rad_dverts.empty()) continue;
00427     
00428     tmp_result = mbImpl->create_element(MBPOLYGON, &rad_dverts[0], rad_dverts.size(), dual_ent);TRC
00429 
00430       // tag it indicating it's a dual entity, and tag primal/dual with dual/primal
00431     tmp_result = mbImpl->tag_set_data(isDualCell_tag(), &dual_ent, 1, &is_dual);TRC
00432     tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &(*rit), 1, &dual_ent);TRC
00433     tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &dual_ent, 1, &(*rit));TRC
00434 
00435       // save it in the list of new dual ents
00436     dual_ents.insert(dual_ent);
00437     
00438       // add a graphics point to the cell; position depends on whether it's a
00439       // bdy cell (mid-pt of cell's vertices) or not (mid-pt of primal edge)
00440     double avg_pos[3];
00441     tmp_result = MeshTopoUtil(mbImpl).get_average_position(*rit, avg_pos);TRC
00442     if (bdy_edge) {
00443       
00444         // add a new dual edge betw last 2 verts
00445       EntityHandle new_edge;
00446       tmp_result = mbImpl->create_element(MBEDGE, &rad_dverts[rad_dverts.size()-2], 
00447                                           2, new_edge);TRC
00448       tmp_result = mbImpl->tag_set_data(isDualCell_tag(), &new_edge, 1, &is_dual);TRC
00449 
00450         // tag the new dual edge with the primal edge as it's dual entity; primal
00451         // edge IS NOT likewise tagged, since it's already tagged with the 2cell
00452       tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &new_edge, 1, &(*rit)); TRC
00453       
00454         // add a graphics pt, position is center of primal edge
00455       tmp_result = add_graphics_point(dual_ent);TRC
00456       tmp_result = add_graphics_point(new_edge, avg_pos);TRC
00457     }
00458     
00459     else {
00460         // if inside, point goes on the 2cell, at primal edge mid-pt
00461       tmp_result = add_graphics_point(dual_ent, avg_pos);TRC
00462     }
00463 
00464       // check to see whether we have equiv entities; if we find any, save for later fixup
00465     Range dum_edges, dum_poly(dual_ent, dual_ent);
00466     tmp_result = mbImpl->get_adjacencies(dum_poly, 1, false, dum_edges);
00467     if (MB_MULTIPLE_ENTITIES_FOUND == tmp_result) {
00468         // we do - need to add adjacencies to disambiguate; use the primal
00469       equiv_edges.merge(dum_edges);
00470     }    
00471   }
00472 
00473   if (!equiv_edges.empty()) 
00474     result = check_dual_equiv_edges(equiv_edges);
00475 
00476   return result;
00477 }
00478 
00479 ErrorCode DualTool::check_dual_equiv_edges(Range &dual_edges)
00480 {
00481     // fix equivalent dual edges (i.e. edges whose vertices define multiple edges)
00482     // by explicitly adding adjacencies to containing polygons; adjacent polygons
00483     // found by going through primal
00484   ErrorCode tmp_result, result = MB_SUCCESS;
00485 
00486   Range all_dedges(dual_edges);
00487     // first, go through all dual edges and find equivalent edges (by looking for
00488     // up-adjacent edges on the vertices of each edge)
00489   for (Range::iterator rit = dual_edges.begin(); rit != dual_edges.end(); rit++) {
00490     Range connect, dum_range(*rit, *rit);
00491     tmp_result = mbImpl->get_adjacencies(dum_range, 0, false, connect);
00492     if (MB_SUCCESS != tmp_result) continue;
00493     tmp_result = mbImpl->get_adjacencies(connect, 1, false, all_dedges, Interface::UNION);
00494     if (MB_SUCCESS != tmp_result) continue;
00495   }
00496 
00497     // save a copy for checking later
00498   Range save_all_2cells;
00499 
00500     // go through each edge
00501   while (!all_dedges.empty()) {
00502     EntityHandle this_edge = *all_dedges.begin();
00503     all_dedges.erase(all_dedges.begin());
00504     
00505     const EntityHandle *connect;
00506     int num_connect;
00507     result = mbImpl->get_connectivity(this_edge, connect, num_connect);
00508     if (MB_SUCCESS != result) continue;
00509 
00510     Range dum_edges, verts;
00511     verts.insert(connect[0]);
00512     verts.insert(connect[1]);
00513     tmp_result = mbImpl->get_adjacencies(verts, 1, false, dum_edges);
00514     if (MB_SUCCESS != tmp_result) {
00515       result = tmp_result;
00516       continue;
00517     }
00518     if (dum_edges.size() == 1) {
00519         // not an equiv edge - already removed from list, so just continue
00520       continue;
00521     }
00522     
00523       // ok, have an equiv entity - fix by looking through primal
00524       // pre-get the primal of these
00525     EntityHandle dedge_quad;
00526     tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &this_edge, 1, &dedge_quad);
00527     if (MB_SUCCESS != tmp_result) {
00528       result = tmp_result;
00529       continue;
00530     }
00531   
00532     if (MBQUAD == mbImpl->type_from_handle(dedge_quad)) {
00533       
00534         // get the primal edges adj to quad
00535       Range dum_quad_range(dedge_quad, dedge_quad), adj_pedges;
00536       tmp_result = mbImpl->get_adjacencies(dum_quad_range, 1, false, adj_pedges);
00537       if (MB_SUCCESS != tmp_result) {
00538         result = tmp_result;
00539         continue;
00540       }
00541         // get the dual 2cells corresponding to those pedges
00542       std::vector<EntityHandle> dcells;
00543       dcells.resize(adj_pedges.size());
00544       tmp_result = mbImpl->tag_get_data(dualEntity_tag(), adj_pedges, &dcells[0]);
00545       if (MB_SUCCESS != tmp_result) {
00546         result = tmp_result;
00547         continue;
00548       }
00549         // now add explicit adjacencies from the dedge to those dcells
00550       std::vector<EntityHandle>::iterator vit;
00551       for (vit = dcells.begin(); vit != dcells.end(); vit++) {
00552         save_all_2cells.insert(*vit);
00553         
00554         assert(MBPOLYGON == mbImpl->type_from_handle(*vit));
00555         tmp_result = mbImpl->add_adjacencies(this_edge, &(*vit), 1, false);
00556         if (MB_SUCCESS != tmp_result) {
00557           result = tmp_result;
00558           continue;
00559         }
00560           // check that there are really adjacencies and *vit is in them
00561         const EntityHandle *adjs;
00562         int num_adjs;
00563         tmp_result = reinterpret_cast<Core*>(mbImpl)->a_entity_factory()->
00564           get_adjacencies(this_edge, adjs, num_adjs);
00565         if (NULL == adjs || std::find(adjs, adjs+num_adjs, *vit) == adjs+num_adjs)
00566           std::cout << "Add_adjacencies failed in construct_dual_faces." << std::endl;
00567       }
00568     }
00569     else {
00570         // else, have a dual edge representing a bdy edge - tie directly to
00571         // dual entity if its dual entity
00572       EntityHandle bdy_dcell;
00573       tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &dedge_quad, 1, &bdy_dcell); TRC
00574       assert(MBPOLYGON == mbImpl->type_from_handle(bdy_dcell));
00575       
00576       tmp_result = mbImpl->add_adjacencies(this_edge, &bdy_dcell, 1, false); 
00577       if (MB_SUCCESS != tmp_result) {
00578         result = tmp_result;
00579         continue;
00580       }
00581     }
00582   }
00583   
00584 
00585     // sanity check - look for adj edges again, and check for equiv entities
00586   for (Range::iterator vit = save_all_2cells.begin(); 
00587        vit != save_all_2cells.end(); vit++) {
00588     Range adj_edges, dum_quad_range;
00589     dum_quad_range.insert(*vit);
00590     assert(MBPOLYGON == mbImpl->type_from_handle(*vit));
00591     tmp_result = mbImpl->get_adjacencies(dum_quad_range, 1, false, adj_edges);
00592     if (MB_MULTIPLE_ENTITIES_FOUND == tmp_result) {
00593       std::cout << "Multiple entities returned for polygon " << mbImpl->id_from_handle(*vit)
00594                 << "." << std::endl;
00595       continue;
00596     }
00597   }
00598     // success!
00599   return result;
00600 }
00601 
00602 ErrorCode DualTool::construct_dual_cells(const Range &all_verts,
00603                                            Range &dual_ents) 
00604 {
00605   if (all_verts.empty()) return MB_SUCCESS;
00606   
00607     // make sure they're all edges
00608   assert(0 == CN::Dimension(TYPE_FROM_HANDLE(*all_verts.begin())) &&
00609          0 == CN::Dimension(TYPE_FROM_HANDLE(*all_verts.rbegin())));
00610   
00611   Range::const_iterator rit;
00612   EntityHandle dual_ent;
00613   unsigned int is_dual = 0x1;
00614   ErrorCode tmp_result = MB_SUCCESS;
00615   ErrorCode result = MB_SUCCESS;
00616   std::vector<EntityHandle> edges, dfaces;
00617   
00618   for (rit = all_verts.begin(); rit != all_verts.end(); rit++) {
00619     if (tmp_result != MB_SUCCESS) result = tmp_result;
00620     
00621     tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &(*rit), 1, &dual_ent);
00622     if (MB_SUCCESS == tmp_result && 0 != dual_ent) {
00623       dual_ents.insert(dual_ent);
00624       continue;
00625     }
00626     
00627       // no dual entity; construct one; get the edges bounding the vertex
00628     edges.clear();
00629     dfaces.clear();
00630     tmp_result = mbImpl->get_adjacencies(&(*rit), 1, 1, false, edges);
00631     if (MB_SUCCESS != tmp_result) continue;
00632 
00633       // get the dual faces corresponding to the edges
00634     dfaces.resize(edges.size());
00635     tmp_result = mbImpl->tag_get_data(dualEntity_tag(), &edges[0], edges.size(), &dfaces[0]);
00636     if (MB_SUCCESS != tmp_result) continue;
00637     
00638       // create the dual cell from those faces
00639     tmp_result = mbImpl->create_element(MBPOLYHEDRON, &dfaces[0], dfaces.size(), dual_ent);
00640     if (MB_SUCCESS != tmp_result || 0 == dual_ent) continue;
00641     
00642       // save it in the list of new dual ents
00643     dual_ents.insert(dual_ent);
00644     
00645       // tag it indicating it's a dual entity
00646     tmp_result = mbImpl->tag_set_data(isDualCell_tag(), &dual_ent, 1, &is_dual);
00647     if (MB_SUCCESS != tmp_result) continue;
00648 
00649       // tag the primal entity with its dual entity and vica versa
00650     tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &(*rit), 1, &dual_ent);
00651     if (MB_SUCCESS != tmp_result) continue;
00652     tmp_result = mbImpl->tag_set_data(dualEntity_tag(), &dual_ent, 1, &(*rit));
00653     if (MB_SUCCESS != tmp_result) continue;
00654   }
00655 
00656   return result;
00657 }
00658 
00661 ErrorCode DualTool::get_radial_dverts(const EntityHandle edge,
00662                                         std::vector<EntityHandle> &rad_dverts,
00663                                         bool &bdy_edge) 
00664 {
00665   rad_dverts.clear();
00666   
00667   std::vector<EntityHandle> rad_faces, rad_ents;
00668   ErrorCode result = MeshTopoUtil(mbImpl).star_entities(edge, rad_faces, bdy_edge, 0, 
00669                                                           &rad_ents);
00670   if (MB_SUCCESS != result) return result;
00671 
00672   if (bdy_edge) {
00673       // if we're a bdy edge, change the order back to what DualTool expects
00674     rad_ents.push_back(*rad_faces.rbegin());
00675     rad_ents.push_back(*rad_faces.begin());
00676   }
00677   
00678   rad_dverts.resize(rad_ents.size());
00679   for (unsigned int i = 0; i < rad_ents.size(); i++) {
00680     EntityHandle dual_ent;
00681     result = mbImpl->tag_get_data(dualEntity_tag(), &rad_ents[i], 1,
00682                                   &dual_ent);
00683     if (!bdy_edge || i < rad_ents.size()-2) rad_dverts[i] = dual_ent;
00684     else {
00685       // fix up this entry
00686       assert(mbImpl->type_from_handle(dual_ent) == MBEDGE);
00687     
00688         // get connectivity of that edge
00689       const EntityHandle *connect;
00690       int num_connect;
00691       result = mbImpl->get_connectivity(dual_ent, connect, num_connect);
00692       if (MB_SUCCESS != result) return result;
00693     
00694         // we want the one that's not already on the list; reuse last_face
00695       int last_hex = (i == rad_ents.size()-1 ? 0 : i-1);
00696       EntityHandle last_face = (connect[0] == rad_dverts[last_hex] ? connect[1] : connect[0]);
00697       rad_dverts[i] = last_face;
00698     }
00699   }
00700 
00701   return result;
00702 }
00703 
00705 ErrorCode DualTool::construct_hex_dual(Range &entities) 
00706 {
00707   std::vector<EntityHandle> evec;
00708   std::copy(entities.begin(), entities.end(), std::back_inserter(evec));
00709   return construct_hex_dual(&evec[0], evec.size());
00710 }
00711   
00713 ErrorCode DualTool::construct_hex_dual(EntityHandle *entities,
00714                                          const int num_entities) 
00715 {
00716     // really quite simple: 
00717 
00718     // construct the dual...
00719   ErrorCode result = construct_dual(entities, num_entities);
00720   if (MB_SUCCESS != result) {
00721     std::cerr << "Error constructing dual entities for primal entities." << std::endl;
00722     return result;
00723   }
00724   
00725     // now traverse to build 1d and 2d hyperplanes
00726   result = construct_dual_hyperplanes(1, entities, num_entities);
00727   if (MB_SUCCESS != result) {
00728     std::cerr << "Problem traversing 1d hyperplanes." << std::endl;
00729     return result;
00730   }
00731   if (MB_SUCCESS != result) return result;
00732 
00733   result = construct_dual_hyperplanes(2, entities, num_entities);
00734   if (MB_SUCCESS != result) {
00735     std::cerr << "Problem traversing 2d hyperplanes." << std::endl;
00736     return result;
00737   }
00738   if (MB_SUCCESS != result) return result;
00739   
00740   result = construct_hp_parent_child();
00741   if (MB_SUCCESS != result) {
00742     std::cerr << "Problem constructing parent/child relations between hyperplanes." 
00743               << std::endl;
00744     return result;
00745   }
00746   if (MB_SUCCESS != result) return result;
00747 
00748     // see?  simple, just like I said
00749   return MB_SUCCESS;
00750 }
00751 
00753 ErrorCode DualTool::get_dual_entities(const int dim, 
00754                                         EntityHandle *entities, 
00755                                         const int num_entities, 
00756                                         Range &dual_ents) 
00757 {
00758   if (0 == isDualCell_tag()) return MB_SUCCESS;
00759   if (0 > dim || 3 < dim) return MB_INDEX_OUT_OF_RANGE;
00760 
00761   unsigned int dum = 0x1;
00762   const void *dum_ptr = &dum;
00763   static EntityType dual_type[] = {MBVERTEX, MBEDGE, MBPOLYGON, MBPOLYHEDRON};
00764 
00765   Range dim_ents;
00766   
00767   ErrorCode result;
00768 
00769   if (0 == entities || 0 == num_entities) {
00770       // just get all the dual entities of this dimension
00771     result = mbImpl->get_entities_by_type_and_tag(0, dual_type[dim], 
00772                                                   &isDualCellTag, &dum_ptr, 1,
00773                                                   dual_ents);
00774   }
00775   else {
00776       // else look for specific dual entities
00777     result = mbImpl->get_adjacencies(entities, num_entities, 3-dim, false,
00778                                      dim_ents, Interface::UNION);
00779     if (MB_SUCCESS != result) return result;
00780     std::vector<EntityHandle> dual_ents_vec(dim_ents.size());
00781     result = mbImpl->tag_get_data(dualEntity_tag(), dim_ents, &dual_ents_vec[0]);
00782     if (MB_SUCCESS != result) return result;
00783     std::copy(dual_ents_vec.begin(), dual_ents_vec.end(), 
00784               range_inserter(dual_ents));
00785   }
00786   
00787   return result;
00788 }
00789 
00791 ErrorCode DualTool::get_dual_entities(const int dim, 
00792                                         EntityHandle *entities, 
00793                                         const int num_entities, 
00794                                         std::vector<EntityHandle> &dual_ents) 
00795 {
00796   Range tmp_range;
00797   ErrorCode result = get_dual_entities(dim, entities, num_entities, tmp_range);
00798   if (MB_SUCCESS != result)
00799     return result;
00800 
00801     // dual_ents.insert(dual_ents.end(), tmp_range.begin(), tmp_range.end());
00802   dual_ents.reserve(dual_ents.size() + tmp_range.size());
00803   for (Range::const_iterator it = tmp_range.begin();
00804        it != tmp_range.end();
00805        ++it)
00806   {
00807     dual_ents.push_back(*it);
00808   }
00809   return MB_SUCCESS;
00810 }
00811 
00812 ErrorCode DualTool::get_dual_hyperplanes(const Interface *impl, const int dim, 
00813                                            Range &dual_ents) 
00814 {
00815   if (dim != 1 && dim != 2) return MB_INDEX_OUT_OF_RANGE;
00816 
00817   Tag dual_tag;
00818   ErrorCode result;
00819   
00820   if (dim == 1)
00821     result = impl->tag_get_handle(DUAL_CURVE_TAG_NAME, 1, MB_TYPE_HANDLE, dual_tag );
00822   else 
00823     result = impl->tag_get_handle(DUAL_SURFACE_TAG_NAME, 1, MB_TYPE_HANDLE, dual_tag );
00824 
00825   if (MB_SUCCESS == result)
00826     result = impl->get_entities_by_type_and_tag(0, MBENTITYSET, &dual_tag, NULL, 1, dual_ents,
00827                                                 Interface::UNION);
00828       
00829   return result;
00830 }
00831 
00832 ErrorCode DualTool::construct_dual_hyperplanes(const int dim, 
00833                                                  EntityHandle *entities, 
00834                                                  const int num_entities) 
00835 {
00836     // this function traverses dual faces of input dimension, constructing
00837     // dual hyperplanes of them in sets as it goes
00838 
00839     // check various inputs
00840   int num_quads, num_hexes;
00841   if (
00842       // this function only makes sense for dim == 1 or dim == 2
00843     (dim != 1 && dim != 2) ||
00844       // should either be quads or hexes around
00845     mbImpl->get_number_entities_by_type(0, MBQUAD, num_quads) != MB_SUCCESS ||
00846     mbImpl->get_number_entities_by_type(0, MBHEX, num_hexes) != MB_SUCCESS ||
00847       // if we're asking for 1d dual ents, should be quads around
00848     (num_quads == 0 && dim == 1) ||
00849       // if we're asking for 2d dual ents, should be hexes around
00850     (num_hexes == 0 && dim == 2))
00851     return MB_FAILURE;
00852   
00853     // get tag name for this dimension hyperplane
00854   Tag gid_tag;
00855   int dum = 0;
00856   ErrorCode result = mbImpl->tag_get_handle(GLOBAL_ID_TAG_NAME, 
00857                                             1, MB_TYPE_INTEGER, 
00858                                             gid_tag,
00859                                             MB_TAG_CREAT|MB_TAG_DENSE,
00860                                             &dum);
00861   if (MB_SUCCESS != result)
00862     return result;
00863     
00864   Tag hp_tag = (1 == dim ? dualCurve_tag() : dualSurface_tag());
00865   
00866     // two stacks: one completely untreated entities, and the other untreated 
00867     // entities on the current dual hyperplane
00868   std::vector<EntityHandle> tot_untreated;
00869   
00870     // put dual entities of this dimension on the untreated list
00871   result = get_dual_entities(dim, entities, num_entities, tot_untreated);
00872   if (MB_SUCCESS != result) 
00873     return result;
00874   
00875     // main part of traversal loop
00876   EntityHandle this_ent;
00877   EntityHandle this_hp;
00878   std::vector<EntityHandle> parents;
00879 
00880   while (!tot_untreated.empty()) {
00881     if (debug && dim == 2 /*(tot_untreated.size()%report == 0)*/)
00882       std::cout << "Untreated list size " << tot_untreated.size() << "." << std::endl;
00883       
00884     this_ent = tot_untreated.back(); tot_untreated.pop_back();
00885     result = mbImpl->tag_get_data(hp_tag, &this_ent, 1, &this_hp);
00886     if (MB_SUCCESS != result && MB_TAG_NOT_FOUND != result) 
00887       return result;
00888 
00889       // d for this entity having a hyperplane assignment already
00890     else if (this_hp != 0)
00891       continue;
00892 
00893     if (1 == dim && check_1d_loop_edge(this_ent)) continue;
00894     
00895       // inner loop: traverse the hyperplane 'till we don't have any more
00896     result = traverse_hyperplane(hp_tag, this_hp, this_ent);
00897     if (MB_SUCCESS != result) {
00898       std::cout << "Failed to traverse hyperplane ";
00899       if (this_hp) std::cout << mbImpl->id_from_handle(this_hp) << "."  << std::endl;
00900       else std::cout << "0." << std::endl;
00901       return result;
00902     }
00903 
00904       // ok, now order the edges if it's a chord
00905     if (1 == dim) order_chord(this_hp);
00906   }
00907 
00908   return MB_SUCCESS;
00909 }
00910 
00911 ErrorCode DualTool::traverse_hyperplane(const Tag hp_tag, 
00912                                           EntityHandle &this_hp, 
00913                                           EntityHandle this_ent) 
00914 {
00915   Range tmp_star, star, tmp_range, new_hyperplane_ents;
00916   std::vector<EntityHandle> hp_untreated;
00917   int dim = mbImpl->dimension_from_handle(this_ent);
00918   MeshTopoUtil mtu(mbImpl);
00919   this_hp = 0;
00920   ErrorCode result;
00921   
00922   unsigned short mark_val = 0x0;
00923   Tag mark_tag;
00924   result = mbImpl->tag_get_handle("__hyperplane_mark", 1, MB_TYPE_BIT, mark_tag,
00925                                   MB_TAG_CREAT|MB_TAG_BIT);
00926   if (MB_SUCCESS != result) 
00927     return result;
00928   mark_val = 0x1;
00929   
00930   while (0 != this_ent) {
00931     EntityHandle tmp_hp = get_dual_hyperplane(this_ent);
00932     if (0 == this_hp && 0 != tmp_hp) this_hp = tmp_hp;
00933     
00934     if (0 == tmp_hp) new_hyperplane_ents.insert(this_ent);
00935     
00936     if (debug && hp_untreated.size()%10 == 0) 
00937       std::cout << "Dual surface " << this_hp << ", hp_untreated list size = " 
00938                 << hp_untreated.size() << "." << std::endl;
00939 
00940       // get the 2nd order adjacencies through lower dimension
00941     tmp_range.clear(); tmp_star.clear(); star.clear();
00942     result = mtu.get_bridge_adjacencies(this_ent, dim-1, dim, star); RR;
00943 
00944       // get the bridge adjacencies through higher dimension
00945     result = mtu.get_bridge_adjacencies(this_ent, dim+1, dim, tmp_star); RR;
00946     tmp_range = subtract( star, tmp_star);
00947     
00948     for (Range::iterator rit = tmp_range.begin(); rit != tmp_range.end(); rit++) {
00949       if (new_hyperplane_ents.find(*rit) != new_hyperplane_ents.end()) continue;
00950       
00951         // check for tag first, 'cuz it's probably faster than checking adjacencies
00952         // assign to avoid valgrind warning
00953       unsigned short tmp_mark = 0x0;
00954       result = mbImpl->tag_get_data(mark_tag, &(*rit), 1, &tmp_mark);
00955       if (MB_SUCCESS == result && mark_val == tmp_mark) 
00956         continue;
00957 
00958         // if it's on the loop, it's not eligible
00959       if (1 == dim && check_1d_loop_edge(*rit)) continue;
00960 
00961         // have one on this hp; just put it on the hp_untreated list for now,
00962         // will get tagged and put in the hp set later
00963       hp_untreated.push_back(*rit);
00964       result = mbImpl->tag_set_data(mark_tag, &(*rit), 1, &mark_val);
00965       if (MB_SUCCESS != result) 
00966         return result;
00967     }
00968 
00969       // end of inner loop; get the next this_ent, or set to zero
00970     if (hp_untreated.empty()) this_ent = 0;
00971     else {
00972       this_ent = hp_untreated.back();
00973       hp_untreated.pop_back();
00974     }
00975   }
00976 
00977   if (debug_ap) {
00978     std::string hp_name;
00979     if (2 == dim) hp_name = "sheet";
00980     else hp_name = "chord";
00981     
00982     if (0 == this_hp) std::cout << "Constructed new " << hp_name << " with ";
00983     else {
00984       int this_id;
00985       result = mbImpl->tag_get_data(globalId_tag(), &this_hp, 1, &this_id); RR;
00986       std::cout << "Added to " << hp_name << " " << this_id << " ";
00987     }
00988     if (dim == 2) std::cout << "edges:" << std::endl;
00989     else std::cout << "quads:" << std::endl;
00990     std::vector<EntityHandle> pents(new_hyperplane_ents.size());
00991     result = mbImpl->tag_get_data(dualEntity_tag(), new_hyperplane_ents,
00992                                   &pents[0]); RR;
00993     for (std::vector<EntityHandle>::iterator vit = pents.begin(); 
00994          vit != pents.end(); vit++) {
00995       if (vit != pents.begin()) std::cout << ", ";
00996       std::cout << mbImpl->id_from_handle(*vit);
00997     }
00998     std::cout << std::endl;
00999   }
01000 
01001   if (0 == this_hp) {
01002       // ok, doesn't have one; make a new hyperplane
01003     int new_id = -1;
01004     result = construct_new_hyperplane(dim, this_hp, new_id);
01005     if (MB_SUCCESS != result) return result;
01006 
01007     if (debug_ap) {
01008       std::cout << "New ";
01009       if (2 == dim) std::cout << " sheet ";
01010       else std::cout << " chord ";
01011       std::cout << new_id << " constructed." << std::endl;
01012     }
01013   }
01014 
01015     // set the hp_val for entities which didn't have one before
01016   std::vector<EntityHandle> hp_tags(new_hyperplane_ents.size());
01017   std::fill(hp_tags.begin(), hp_tags.end(), this_hp);
01018   result = mbImpl->tag_set_data(hp_tag, new_hyperplane_ents, &hp_tags[0]);
01019   if (MB_SUCCESS != result) 
01020     return result;
01021   result = mbImpl->add_entities(this_hp, new_hyperplane_ents);
01022   if (MB_SUCCESS != result) 
01023     return result;
01024 
01025     // unmark the entities by removing the tag
01026   result = mbImpl->tag_delete(mark_tag);
01027   if (MB_SUCCESS != result) 
01028     return result;
01029 
01030   return MB_SUCCESS;
01031 }
01032 
01033 ErrorCode DualTool::order_chord(EntityHandle chord_set) 
01034 {
01035     // re-order the 1cells in the set so they are in order along the chord
01036     // start by finding the vertex dual to a quad
01037   Range verts, one_cells;
01038   ErrorCode result = mbImpl->get_entities_by_dimension(chord_set, 1, one_cells); 
01039   if (MB_SUCCESS != result || one_cells.empty()) return MB_FAILURE;
01040   
01041   result = mbImpl->get_adjacencies(one_cells, 0, false, verts, Interface::UNION);
01042   if (MB_SUCCESS != result || verts.empty()) return MB_FAILURE;
01043   
01044   EntityHandle last_vert = 0;
01045   for (Range::iterator rit = verts.begin(); rit != verts.end(); rit++) {
01046     if (TYPE_FROM_HANDLE(get_dual_entity(*rit)) == MBQUAD) {
01047       last_vert = *rit;
01048       break;
01049     }
01050   }
01051     // if there's no vertex owned by a quad, just start with 1st one
01052   if (0 == last_vert) last_vert = *verts.begin();
01053   
01054     // now, skip from vertex to vertex, building a list of 1cells
01055   std::vector<EntityHandle> ordered_1cells;
01056   EntityHandle last_1cell = 0;
01057   Range dum1, dum2;
01058   const EntityHandle *connect;
01059   int num_connect;
01060   ErrorCode tmp_result = MB_SUCCESS;
01061   while(ordered_1cells.size() != one_cells.size()) {
01062     dum1 = one_cells;
01063     result = mbImpl->get_adjacencies(&last_vert, 1, 1, false, dum1);
01064     if (0 != last_1cell) dum1.erase(last_1cell);
01065       // assert(1 == dum1.size());
01066     if (0 != last_1cell && 1 != dum1.size()) {
01067       std::cerr << "unexpected size traversing chord." << std::endl;
01068       tmp_result = MB_FAILURE;
01069     }
01070       
01071     last_1cell = *dum1.begin();
01072     ordered_1cells.push_back(last_1cell);
01073     result = mbImpl->get_connectivity(last_1cell, connect, num_connect); RR;
01074     if (last_vert == connect[0]) last_vert = connect[1];
01075     else last_vert = connect[0];
01076   }
01077   
01078     // now have the 1cells in order, replace them in the set
01079   if (MB_SUCCESS == tmp_result) {
01080     result = mbImpl->remove_entities(chord_set, one_cells); RR;
01081     result = mbImpl->add_entities(chord_set, &ordered_1cells[0], ordered_1cells.size()); RR;
01082   }
01083   
01084   return MB_SUCCESS;
01085 }
01086 
01087 ErrorCode DualTool::construct_new_hyperplane(const int dim,
01088                                                EntityHandle &new_hyperplane,
01089                                                int &id) 
01090 {
01091   ErrorCode result;
01092   if (1 == dim)
01093     result = mbImpl->create_meshset((MESHSET_ORDERED | MESHSET_TRACK_OWNER), 
01094                                     new_hyperplane);
01095   else
01096     result = mbImpl->create_meshset((MESHSET_SET | MESHSET_TRACK_OWNER), 
01097                                     new_hyperplane);
01098   if (MB_SUCCESS != result) return result;
01099 
01100   if (-1 == id) {
01101     Range all_hyperplanes;
01102     result = get_dual_hyperplanes(mbImpl, dim, all_hyperplanes); RR;
01103     std::vector<int> gids(all_hyperplanes.size());
01104     result = mbImpl->tag_get_data(globalIdTag, all_hyperplanes, &gids[0]); RR;
01105     for (unsigned int i = 0; i < gids.size(); i++) 
01106       if (gids[i] > id) id = gids[i];
01107     id++;
01108     if (0 == id) id++;
01109   }
01110     
01111   result = mbImpl->tag_set_data(globalId_tag(), &new_hyperplane, 1, &id); RR;
01112   Tag hp_tag = (1 == dim ? dualCurve_tag() : dualSurface_tag());
01113   result = mbImpl->tag_set_data(hp_tag, &new_hyperplane, 1, &new_hyperplane);
01114 
01115     // assign a category name to these sets
01116   static const char dual_category_names[2][CATEGORY_TAG_SIZE] = 
01117     {"Chord\0", "Sheet\0"};
01118     
01119   result = mbImpl->tag_set_data(categoryTag, &new_hyperplane, 1, dual_category_names[dim-1]);
01120 
01121   return result;
01122 }
01123 
01124 bool DualTool::check_1d_loop_edge(EntityHandle this_ent) 
01125 {
01126     // make sure it's an edge
01127   if (MBEDGE != mbImpl->type_from_handle(this_ent)) return false;
01128 
01129     // also has to be a dual entity
01130   unsigned int dum;
01131   ErrorCode result = mbImpl->tag_get_data(isDualCell_tag(), &this_ent, 1, &dum);
01132   if (MB_SUCCESS != result || dum != 0x1) return false;
01133   
01134   const EntityHandle *verts;
01135   EntityHandle vert_tags[2];
01136   int num_verts;
01137   result = mbImpl->get_connectivity(this_ent, verts, num_verts);
01138   if (MB_SUCCESS != result) return false;
01139   
01140   result = mbImpl->tag_get_data(dualEntity_tag(), verts, 2, vert_tags);
01141   if (MB_SUCCESS != result ||
01142       mbImpl->type_from_handle(vert_tags[0]) != MBQUAD ||
01143       mbImpl->type_from_handle(vert_tags[1]) != MBQUAD) return false;
01144   
01145   else return true;
01146 }
01147 
01148 ErrorCode DualTool::construct_hp_parent_child() 
01149 {
01150   Range dual_surfs, dual_cells, dual_edges;
01151   ErrorCode result = this->get_dual_hyperplanes(mbImpl, 2, dual_surfs);
01152   if (MB_SUCCESS != result || dual_surfs.empty()) return result;
01153   std::vector<EntityHandle> dual_curve_sets;
01154   
01155   for (Range::iterator surf_it = dual_surfs.begin(); surf_it != dual_surfs.end();
01156        surf_it++) {
01157       // get all the cells, edges in those cells, and chords for those edges
01158     dual_cells.clear();
01159     result = mbImpl->get_entities_by_handle(*surf_it, dual_cells);
01160     if (MB_SUCCESS != result) return result;
01161     dual_edges.clear();
01162     result = mbImpl->get_adjacencies(dual_cells, 1, false, dual_edges, Interface::UNION);
01163     if (MB_SUCCESS != result) return result;
01164     dual_curve_sets.reserve(dual_edges.size());
01165     result = mbImpl->tag_get_data(dualCurve_tag(), dual_edges, &dual_curve_sets[0]);
01166     if (MB_SUCCESS != result) return result;
01167 
01168       // reuse dual_cells to get unique list of chord sets
01169     dual_cells.clear();
01170     for (unsigned int i = 0; i < dual_edges.size(); i++)
01171       if (dual_curve_sets[i] != 0) dual_cells.insert(dual_curve_sets[i]);
01172     
01173       // now connect up this dual surf with all the 1d ones
01174     for (Range::iterator rit = dual_cells.begin(); rit != dual_cells.end(); rit++) {
01175       result = mbImpl->add_parent_child(*surf_it, *rit);
01176       if (MB_SUCCESS != result) return result;
01177     }
01178   }
01179 
01180   return MB_SUCCESS;
01181 }
01182     
01183 ErrorCode DualTool::get_graphics_points(EntityHandle dual_ent,
01184                                           std::vector<int> &npts,
01185                                           std::vector<GraphicsPoint> &points) 
01186 {
01187     // shouldn't be a set
01188   assert(MBENTITYSET != mbImpl->type_from_handle(dual_ent));
01189   
01190     // get the graphics points comprising the given entity
01191   GraphicsPoint gp_array[DualTool::GP_SIZE];
01192 
01193   ErrorCode result = MB_SUCCESS;
01194   
01195     // switch based on topological dimension
01196   switch (mbImpl->dimension_from_handle(dual_ent)) {
01197     case 0:
01198         // just return the vertex point
01199       result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), &dual_ent, 1,
01200                                     gp_array);
01201       if (MB_SUCCESS == result)
01202         points.push_back(gp_array[0]);
01203         
01204       break;
01205 
01206     case 1:
01207         // get my graphics point then those of my vertices
01208       const EntityHandle *connect;
01209       int num_connect;
01210       result = mbImpl->get_connectivity(dual_ent, connect, num_connect);
01211       if (MB_SUCCESS != result) break;
01212       
01213       result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), connect, 2,
01214                                     gp_array);
01215       if (MB_SUCCESS == result) {
01216         points.push_back(gp_array[0]);
01217         points.push_back(gp_array[0]);
01218         points.push_back(gp_array[1]);
01219         result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), &dual_ent, 1,
01220                                       gp_array);
01221         if (MB_SUCCESS == result) points[1] = gp_array[0];
01222       }
01223 
01224       npts.push_back(3);
01225       
01226       break;
01227       
01228     case 2:
01229       result = get_cell_points(dual_ent, npts, points);
01230       break;
01231   }
01232   
01233   return result;
01234 }
01235 
01236 ErrorCode DualTool::get_cell_points(EntityHandle dual_ent,
01237                                       std::vector<int> &npts,
01238                                       std::vector<GraphicsPoint> &points) 
01239 {
01240   assert(MBPOLYGON == mbImpl->type_from_handle(dual_ent));
01241   
01242     // get the 1cells in this 2cell
01243   Range one_cells;
01244   
01245   Range tc_range; tc_range.insert(dual_ent);
01246   ErrorCode result = mbImpl->get_adjacencies(tc_range, 1, false, one_cells, 
01247                                                Interface::UNION); RR;
01248 
01249   int num_edges = one_cells.size();
01250   std::vector<GraphicsPoint> dum_gps(num_edges+1);
01251   
01252     // get graphics points for 0cells and for this cell
01253   result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), one_cells,
01254                                 &dum_gps[0]); RR;
01255   result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), &dual_ent, 1,
01256                                 &(dum_gps[num_edges])); RR;
01257 
01258   Range::iterator eit;
01259   const EntityHandle *connect;
01260   int num_connect;
01261   GraphicsPoint vert_gps[2];
01262   int i;
01263   for (i = 0, eit = one_cells.begin(); i < num_edges; i++, eit++) {
01264       // get the vertices and the graphics points for them
01265     result = mbImpl->get_connectivity(*eit, connect, num_connect); RR;
01266     result = mbImpl->tag_get_data(dualGraphicsPoint_tag(), connect, 2, 
01267                                   vert_gps); RR;
01268 
01269       // make the 2 tris corresponding to this edge; don't worry about order
01270       // for now
01271     npts.push_back(3);
01272     points.push_back(dum_gps[num_edges]);
01273     points.push_back(vert_gps[0]);
01274     points.push_back(dum_gps[i]);
01275     
01276     npts.push_back(3);
01277     points.push_back(dum_gps[num_edges]);
01278     points.push_back(dum_gps[i]);
01279     points.push_back(vert_gps[1]);
01280   }
01281 
01282   return result;
01283 }
01284 
01285 ErrorCode DualTool::get_graphics_points(const Range &in_range,
01286                                           std::vector<GraphicsPoint> &points,
01287                                           const bool assign_ids,
01288                                           const int start_id) 
01289 {
01290     // return graphics points on dual entities in in_range or in entities
01291     // in sets in in_range
01292   ErrorCode result;
01293 
01294     // for each dual hyperplane set:
01295   Range::const_iterator rit;
01296   
01297   Range two_cells, all_cells;
01298   for (rit = in_range.begin(); rit != in_range.end(); rit++) {
01299       // for each entity:
01300     two_cells.clear();
01301     EntityType this_type = mbImpl->type_from_handle(*rit);
01302     if (MBENTITYSET == this_type) {
01303       result = mbImpl->get_entities_by_handle(*rit, two_cells); RR;
01304     
01305       std::copy(two_cells.begin(), two_cells.end(), range_inserter(all_cells));
01306     }
01307     
01308     else {
01309       two_cells.insert(*rit);
01310       assert(this_type == MBVERTEX || this_type == MBEDGE ||
01311              this_type == MBPOLYGON || this_type == MBPOLYHEDRON);
01312     }
01313 
01314     result = mbImpl->get_adjacencies(two_cells, 0, false, all_cells, 
01315                                      Interface::UNION); RR;
01316     result = mbImpl->get_adjacencies(two_cells, 1, false, all_cells, 
01317                                      Interface::UNION); RR;
01318   }
01319       
01320       // get graphics points
01321   points.resize(all_cells.size());
01322   
01323   result = mbImpl->tag_get_data(dualGraphicsPointTag, all_cells,
01324                                 &points[0]); RR;
01325 
01326   if (assign_ids) {
01327     int i = start_id;
01328     
01329     for (std::vector<GraphicsPoint>::iterator vit = points.begin(); 
01330          vit != points.end(); vit++)
01331       vit->id = i++;
01332 
01333     result = mbImpl->tag_set_data(dualGraphicsPoint_tag(), all_cells, 
01334                                   &points[0]); RR;
01335   }
01336 
01337   return result;
01338 }
01339 
01340 EntityHandle DualTool::next_loop_vertex(const EntityHandle last_v,
01341                                           const EntityHandle this_v,
01342                                           const EntityHandle dual_surf)
01343 {
01344     // given two vertices, find the next one on the loop; if one is a dual
01345     // surface, then just choose either one for that surface
01346   assert((0 == last_v || mbImpl->type_from_handle(last_v) == MBVERTEX) &&
01347          mbImpl->type_from_handle(this_v) == MBVERTEX &&
01348          mbImpl->type_from_handle(dual_surf) == MBENTITYSET);
01349 
01350     // get the connected vertices
01351   MeshTopoUtil tpu(mbImpl);
01352   Range other_verts;
01353   ErrorCode result = tpu.get_bridge_adjacencies(this_v, 1, 0, other_verts);
01354   if (MB_SUCCESS != result || other_verts.empty()) return 0;
01355   
01356     //if (mbImpl->type_from_handle(last_v) == MBENTITYSET) {
01357       // dual surface, choose either; first get a 2cell on this surface
01358   Range tcells, tcells2, verts;
01359   result = mbImpl->get_entities_by_type(dual_surf, MBPOLYGON, tcells);
01360   if (MB_SUCCESS != result || tcells.empty()) return 0;
01361 
01362     // ok, pay attention here: first get 2cells common to dual surface and this_v
01363   verts.insert(this_v);
01364   result = mbImpl->get_adjacencies(verts, 2, false, tcells);
01365   if (MB_SUCCESS != result || tcells.empty()) return 0;
01366 
01367     // next get vertices common to both 2cells and subtract from other_verts; also
01368     // remove last_v if it's non-zero
01369   verts.clear();
01370   result = mbImpl->get_adjacencies(tcells, 0, false, verts);
01371   if (MB_SUCCESS != result || verts.empty()) return 0;
01372   
01373   Range tmp_verts = subtract( other_verts, verts);
01374   other_verts.swap(tmp_verts);
01375   if (0 != last_v) other_verts.erase(last_v);
01376 
01377     // now get intersection of remaining vertices and 2 2cells vertices
01378     // look at each one successively; should find one, maybe not on both
01379   tmp_verts = other_verts;
01380   Range tmp_faces(*tcells.begin(), *tcells.begin());
01381   result = mbImpl->get_adjacencies(tmp_faces, 0, false, tmp_verts);
01382   if (MB_SUCCESS == result && !tmp_verts.empty()) return *tmp_verts.begin();
01383   tmp_faces.clear();
01384   tmp_faces.insert(*tcells.rbegin());
01385   result = mbImpl->get_adjacencies(tmp_faces, 0, false, other_verts);
01386   if (MB_SUCCESS == result && !other_verts.empty()) return *other_verts.begin();
01387 
01388     // if we got here, there isn't any
01389   return 0;
01390 }
01391 
01392 EntityHandle DualTool::get_dual_hyperplane(const EntityHandle ncell) 
01393 {
01394     // get the sheet or chord it's in
01395   std::vector<EntityHandle> adj_sets;
01396   ErrorCode result = mbImpl->get_adjacencies(&ncell, 1, 4, false, adj_sets);
01397   if (MB_SUCCESS != result) return 0;
01398     
01399   EntityHandle dum_set;
01400   for (std::vector<EntityHandle>::iterator vit = adj_sets.begin(); 
01401        vit != adj_sets.end(); vit++) {
01402     if (mbImpl->tag_get_data(dualCurve_tag(), &(*vit), 1, &dum_set) != MB_TAG_NOT_FOUND ||
01403         mbImpl->tag_get_data(dualSurface_tag(), &(*vit), 1, &dum_set) != MB_TAG_NOT_FOUND)
01404       return *vit;
01405   }
01406   
01407   return 0;
01408 }
01409 
01411 ErrorCode DualTool::set_dual_surface_or_curve(EntityHandle entity, 
01412                                                 const EntityHandle dual_hyperplane,
01413                                                 const int dual_entity_dimension)
01414 {
01415   if (1 == dual_entity_dimension)
01416     mbImpl->tag_set_data(dualCurve_tag(), &entity, 1, &dual_hyperplane);
01417   else if (2 == dual_entity_dimension)
01418     mbImpl->tag_set_data(dualSurface_tag(), &entity, 1, &dual_hyperplane);
01419   else 
01420     return MB_INDEX_OUT_OF_RANGE;
01421 
01422   return MB_SUCCESS;
01423 }
01424 
01426 EntityHandle DualTool::get_dual_entity(const EntityHandle this_ent) const
01427 {
01428   EntityHandle dual_ent;
01429   ErrorCode result = mbImpl->tag_get_data(dualEntity_tag(), &this_ent, 1, &dual_ent);
01430   if (MB_SUCCESS != result || MB_TAG_NOT_FOUND == result) return 0;
01431   else return dual_ent;
01432 }
01433 
01435 EntityHandle DualTool::get_extra_dual_entity(const EntityHandle this_ent) 
01436 {
01437   EntityHandle dual_ent;
01438   ErrorCode result = mbImpl->tag_get_data(extraDualEntity_tag(), &this_ent, 1, &dual_ent);
01439   if (MB_SUCCESS != result || MB_TAG_NOT_FOUND == result) return 0;
01440   else return dual_ent;
01441 }
01442 
01443 ErrorCode DualTool::atomic_pillow(EntityHandle odedge, EntityHandle &quad1,
01444                                     EntityHandle &quad2) 
01445 {
01446   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
01447 
01448   if (debug_ap) {
01449     Range sets;
01450     Tag ms_tag;
01451     
01452     ErrorCode result = mbImpl->tag_get_handle("MATERIAL_SET", 1, MB_TYPE_INTEGER, ms_tag);
01453     if (MB_SUCCESS == result) {
01454       result = mbImpl->get_entities_by_type_and_tag(0, MBENTITYSET, &ms_tag, NULL,
01455                                                     1, sets);
01456       if (MB_SUCCESS == result)
01457         result = mbImpl->delete_entities(sets);
01458     }
01459   }
01460   
01461   std::cout << "-AP("; print_cell(odedge); std::cout << ")" << std::endl;
01462 
01463     // perform an atomic pillow operation around dedge
01464 
01465     // grab the quad before deleting the odedge
01466   quad1 = get_dual_entity(odedge);
01467   assert(0 != quad1);
01468 
01469     // 0. get star 2cells around odedge (before odedge changes) and 3cells around
01470     // those 2cells (going to delete the 2cells, therefore need to delete the 3cells
01471     // that depend on those too)
01472   MeshTopoUtil mtu(mbImpl);
01473   Range star_cells, tmp_cells;
01474   ErrorCode result = mbImpl->get_adjacencies(&odedge, 1, 2, false, star_cells); RR;
01475   result = mbImpl->get_adjacencies(star_cells, 3, false, tmp_cells,
01476                                    Interface::UNION); RR;
01477   star_cells.merge(tmp_cells);
01478   star_cells.insert(odedge);
01479   
01480     // tear down the dual entities which will be modified by the ap first
01481   result = delete_dual_entities(star_cells); RR;
01482 
01483     // now change the quad to an ap
01484   std::vector<EntityHandle> verts;
01485   result = mbImpl->get_connectivity(&quad1, 1, verts); RR;
01486   
01487     // get average position of vertices
01488   double coords[12], avg[3] = {0.0, 0.0, 0.0};
01489   result = mbImpl->get_coords(&verts[0], verts.size(), coords); RR;
01490   for (int i = 0; i < 4; i++) {
01491     avg[0] += coords[3*i]; avg[1] += coords[3*i+1]; avg[2] += coords[3*i+2];
01492   }
01493   for (int i = 0; i < 3; i++) avg[i] *= 0.25;
01494 
01495     // for each position, get a corresponding position 1/2 way to avg
01496   double new_coords[12];
01497   for (int i = 0; i < 4; i++) {
01498     new_coords[3*i] = avg[0] + .5*(coords[3*i]-avg[0]);
01499     new_coords[3*i+1] = avg[1] + .5*(coords[3*i+1]-avg[1]);
01500     new_coords[3*i+2] = avg[2] + .5*(coords[3*i+2]-avg[2]);
01501   }
01502   
01503     // make the 4 new vertices; store in vector long enough for hex connectivity
01504   for (int i = 0; i < 4; i++) {
01505     verts.push_back(0);
01506     result = mbImpl->create_vertex(&new_coords[3*i], verts[4+i]); RR;
01507   }
01508 
01509     // get the hexes connected to the quad
01510   Range hexes;
01511   result = mbImpl->get_adjacencies(&quad1, 1, 3, false, hexes); RR;
01512   assert(hexes.size() <= 2);
01513   
01514     // remove any explicit adjacency from the first hex, since that'll get connected
01515     // to the new quad; add adjacency between quad and second hex, if there is a 2nd
01516   result = mbImpl->remove_adjacencies(quad1, &(*hexes.begin()), 1); RR;
01517   if (hexes.size() == 2) {
01518     result = mbImpl->add_adjacencies(quad1, &(*hexes.rbegin()), 1, false); RR;
01519   }
01520   
01521     // create the new, inner quad, and make it explicitly adjacent to 1st hex;
01522     // make the connectivity of this quad same as the original one
01523   std::vector<EntityHandle> tmp_verts;
01524   std::copy(verts.begin(), verts.end(), std::back_inserter(tmp_verts));
01525   
01526   result = mbImpl->create_element(MBQUAD, &tmp_verts[0], 4, quad2); RR;
01527   result = mbImpl->add_adjacencies(quad2, &(*hexes.begin()), 1, false); RR;
01528 
01529     // reverse the connectivity of the 1st hex
01530   std::reverse(verts.begin(), verts.begin()+4);
01531   std::reverse(verts.begin()+4, verts.end());
01532 
01533     // now make two inner hexes; note connectivity array is flipped for the two hexes
01534   EntityHandle new_hexes[2];
01535   result = mbImpl->create_element(MBHEX, &verts[0], 8, new_hexes[0]); RR;
01536   result = mbImpl->create_element(MBHEX, &tmp_verts[0], 8, new_hexes[1]); RR;
01537 
01538     // set the global id tag on the new hexes
01539   int new_hex_ids[2] = {++maxHexId, ++maxHexId};
01540   result = mbImpl->tag_set_data(globalId_tag(), new_hexes, 2, new_hex_ids);
01541   if (MB_SUCCESS != result) return result;
01542 
01543     // by definition, quad1 is adj to new_hexes[0]
01544   result = mbImpl->add_adjacencies(quad1, &new_hexes[0], 1, false); RR;
01545   result = mbImpl->add_adjacencies(quad2, &new_hexes[1], 1, false); RR;
01546 
01547   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
01548 
01549     // now update the dual
01550   result = construct_hex_dual(&new_hexes[0], 2); RR;
01551 
01552     // get the new dual surface, by getting one of the edges between the center
01553     // and outer vertex rings
01554   Range new_edge;
01555   verts[1] = verts[4];
01556   result = mbImpl->get_adjacencies(&verts[0], 2, 1, false, new_edge);
01557   if (MB_SUCCESS != result || new_edge.size() != 1) return result;
01558   
01559   return MB_SUCCESS;
01560 }
01561 
01563 ErrorCode DualTool::rev_atomic_pillow(EntityHandle pillow, Range &chords) 
01564 {
01565     // get the dual entities associated with elements in the pillow; go through
01566     // the elements instead of the pillow sheet so you get all of them, not just
01567     // the ones on the sheet
01568   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
01569 
01570   std::cout << "-AP("; print_cell(pillow); std::cout << ")" << std::endl;
01571 
01572   Range dverts;
01573   ErrorCode result = get_dual_entities(pillow, NULL, NULL,
01574                                          &dverts, NULL, NULL);
01575   if (MB_SUCCESS != result) return result;
01576   assert(2 == dverts.size());
01577   
01578   EntityHandle hexes[2];
01579   result = mbImpl->tag_get_data(dualEntity_tag(), dverts, hexes); RR;
01580   assert(hexes[0] != 0 && hexes[1] != 0);
01581 
01582   std::vector<EntityHandle> dcells[4];
01583   Range pcells[4];
01584   std::copy(hexes, hexes+2, range_inserter(pcells[3]));
01585   std::copy(dverts.begin(), dverts.end(), std::back_inserter(dcells[0]));
01586   for (int dim = 0; dim <= 2; dim++) {
01587     result = mbImpl->get_adjacencies(hexes, 2, dim, false, pcells[dim], 
01588                                      Interface::UNION); RR;
01589     dcells[3-dim].resize(pcells[dim].size());
01590     result = mbImpl->tag_get_data(dualEntity_tag(), pcells[dim], &dcells[3-dim][0]); RR;
01591   }
01592   
01593     // delete the dual entities which are part of the original pillow
01594   result = mbImpl->delete_entities(&pillow, 1);
01595   if (MB_SUCCESS != result) return result;
01596   
01597   result = mbImpl->delete_entities(chords);
01598   if (MB_SUCCESS != result) return result;
01599 
01600   for (int i = 3; i >= 0; i--) {
01601     result = delete_dual_entities(&dcells[i][0], dcells[i].size()); RR;
01602   }
01603 
01604     // delete the primal entities inserted by the ap; be careful to get the right
01605     // faces, edges and vertices
01606   Range del_faces, del_edges, del_verts, tmp_faces, tmp_verts;
01607     // faces are the shared 5 and the 1 other one with greater handle (which
01608     // we know will be later in the range)
01609   result = mbImpl->get_adjacencies(hexes, 2, 2, false, del_faces); RR;
01610   assert(5 == del_faces.size());
01611   std::copy(pcells[2].begin(), pcells[2].end(), range_inserter(tmp_faces));
01612   tmp_faces = subtract( tmp_faces, del_faces);
01613   del_faces.insert(*tmp_faces.rbegin());
01614   result = mbImpl->get_adjacencies(tmp_faces, 0, false, tmp_verts); RR;
01615   std::copy(pcells[0].begin(), pcells[0].end(), range_inserter(del_verts));
01616   del_verts = subtract( del_verts, tmp_verts);
01617   assert(4 == del_verts.size());
01618   result = mbImpl->get_adjacencies(del_verts, 1, false, del_edges, Interface::UNION); RR;
01619   assert(8 == del_edges.size());
01620   
01621   result = mbImpl->delete_entities(hexes, 2); RR;
01622   result = mbImpl->delete_entities(del_faces); RR;
01623   result = mbImpl->delete_entities(del_edges); RR;
01624   result = mbImpl->delete_entities(del_verts); RR;
01625 
01626   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
01627 
01628     // recompute the dual for the hexes on either side of the quad affected
01629     // by the ap removal
01630   Range tmp_hexes;
01631   result = mbImpl->get_adjacencies(tmp_verts, 3, false, tmp_hexes, Interface::UNION); RR;
01632   result = construct_hex_dual(tmp_hexes); RR;
01633 
01634   return MB_SUCCESS;
01635 }
01636 
01637 ErrorCode DualTool::delete_dual_entities(EntityHandle *entities,
01638                                            int num_entities) 
01639 {
01640   Range tmp_ents;
01641   std::copy(entities, entities+num_entities, range_inserter(tmp_ents));
01642   return delete_dual_entities(tmp_ents);
01643 }
01644   
01645 ErrorCode DualTool::delete_dual_entities(Range &entities) 
01646 {
01647   if (entities.empty()) return delete_whole_dual();
01648   
01649   EntityHandle null_entity = 0;
01650   ErrorCode result;
01651   Range ents_to_delete;
01652   
01653   while (!entities.empty()) {
01654     EntityHandle this_entity = entities.pop_back();
01655     
01656       // reset the primal's dual entity
01657     EntityHandle primal = get_dual_entity(this_entity);
01658     if (get_dual_entity(primal) == this_entity) {
01659       result = mbImpl->tag_set_data(dualEntity_tag(), &primal, 1, &null_entity); RR;
01660     }
01661     EntityHandle extra = get_extra_dual_entity(primal);
01662     if (0 != extra) {
01663       result = mbImpl->tag_set_data(extraDualEntity_tag(), &primal, 1, &null_entity); RR;
01664     }
01665 
01666     ents_to_delete.insert(this_entity);
01667     
01668       // check for extra dual entities
01669     if (mbImpl->type_from_handle(this_entity) == MBPOLYGON) {
01670       // for 2cell, might be a loop edge
01671       Range loop_edges;
01672       result = mbImpl->get_adjacencies(&this_entity, 1, 1, false, loop_edges);
01673       for (Range::iterator rit = loop_edges.begin(); rit != loop_edges.end(); rit++)
01674         if (check_1d_loop_edge(*rit)) entities.insert(*rit);
01675     }
01676     else if (extra && extra != this_entity)
01677         // just put it on the list; primal for which we're extra has already been
01678         // reset to not point to extra entity
01679       ents_to_delete.insert(extra);
01680   }
01681 
01682     // now delete the entities (sheets and chords will be updated automatically)
01683   return mbImpl->delete_entities(ents_to_delete);
01684 }
01685 
01686 void DualTool::print_cell(EntityHandle cell) 
01687 {
01688   const EntityHandle *connect;
01689   int num_connect;
01690   ErrorCode result = mbImpl->get_connectivity(cell, connect, num_connect);
01691   if (MB_SUCCESS != result) return;
01692   bool first = true;
01693   EntityHandle primals[20];
01694   std::vector<int> ids;
01695   
01696   assert(num_connect < 20);
01697   result = mbImpl->tag_get_data(dualEntityTag, connect, num_connect, primals);
01698   ids.resize(num_connect);
01699   result = mbImpl->tag_get_data(globalIdTag, primals, 
01700                              num_connect, &ids[0]);
01701   for (int i = 0; i < num_connect; i++) {
01702     if (!first) std::cout << "-";
01703     EntityType this_type = mbImpl->type_from_handle(primals[i]);
01704     if (this_type == MBHEX) std::cout << "h";
01705     else if (this_type == MBQUAD) std::cout << "f";
01706     else std::cout << "u";
01707 
01708     if (ids[i] != 0) std::cout << ids[i];
01709     else std::cout << mbImpl->id_from_handle(primals[i]);
01710 
01711     first = false;
01712   }
01713 }
01714 
01715 ErrorCode DualTool::face_open_collapse(EntityHandle ocl, EntityHandle ocr) 
01716 {
01717   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
01718 
01719   MeshTopoUtil mtu(mbImpl);
01720 
01721   std::cout << "OC("; print_cell(ocl); std::cout << ")-("; print_cell(ocr);
01722   std::cout << ")" << std::endl;
01723 
01724     // get the primal entities we're dealing with
01725   EntityHandle split_quads[2] = {0}, 
01726     split_edges[3] = {0}, split_nodes[2] = {0}, other_edges[6] = {0}, other_nodes[6] = {0};
01727   Range hexes;
01728   ErrorCode result = foc_get_ents(ocl, ocr, split_quads, split_edges, split_nodes,
01729                                     hexes, other_edges, other_nodes); RR;
01730 
01731     // get star entities around edges, separated into halves
01732   std::vector<EntityHandle> star_dp1[2], star_dp2[2];
01733   result = foc_get_stars(split_quads, split_edges, star_dp1, star_dp2); RR;
01734 
01735   if (MBQUAD != mbImpl->type_from_handle(split_quads[0]) ||
01736       MBQUAD != mbImpl->type_from_handle(split_quads[1]))
01737     return MB_TYPE_OUT_OF_RANGE;
01738   
01739   result = foc_delete_dual(split_quads, split_edges, hexes);
01740   if (MB_SUCCESS != result) return result;
01741 
01742   EntityHandle new_quads[2], new_edges[3], new_nodes[2];
01743   result = split_pair_nonmanifold(split_quads, split_edges, split_nodes, 
01744                                   star_dp1, star_dp2,
01745                                   other_edges, other_nodes, 
01746                                   new_quads, new_edges, new_nodes);
01747   if (MB_SUCCESS != result) return result;
01748 
01749     // now merge entities, the C of foc
01750   EntityHandle keepit, deleteit;
01751 #define MIN(a,b) (a < b ? a : b)  
01752 #define MAX(a,b) (a > b ? a : b)  
01753 #define KEEP_DELETE(a,b,c,d) {c = MIN(a,b); d = MAX(a,b);}
01754 
01755     // find how many shared edges there were
01756   int num_shared_edges = (split_edges[2] ? 3 :
01757                           (split_edges[1] ? 2 : 1));
01758   
01759     // first the node(s)
01760   for (int i = 0; i < 3-num_shared_edges; i++) {
01761     KEEP_DELETE(other_nodes[2+2*i], other_nodes[3+2*i], keepit, deleteit);
01762     result = mbImpl->merge_entities(keepit, deleteit, false, true); RR;
01763   }
01764   
01765     // now the edges
01766   for (int i = 0; i < 4-num_shared_edges; i++) {
01767     KEEP_DELETE(other_edges[2*i], other_edges[2*i+1], keepit, deleteit);
01768     result = mbImpl->merge_entities(keepit, deleteit, false, true); RR;
01769   }
01770 
01771     // now the faces
01772   KEEP_DELETE(split_quads[0], split_quads[1], keepit, deleteit);
01773   result = mbImpl->merge_entities(keepit, deleteit, false, true); RR;
01774   
01775   result = mbImpl->merge_entities(new_quads[0], new_quads[1], false, true); RR;
01776   
01777   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
01778 
01779     // reconstruct dual
01780   result = construct_hex_dual(hexes); 
01781   if (MB_SUCCESS != result) return result;
01782 
01783   return check_dual_adjs();
01784   
01785 }
01786 
01787 ErrorCode DualTool::foc_get_ents(EntityHandle ocl, 
01788                                    EntityHandle ocr, 
01789                                    EntityHandle *split_quads, 
01790                                    EntityHandle *split_edges, 
01791                                    EntityHandle *split_nodes, 
01792                                    Range &hexes, 
01793                                    EntityHandle *other_edges, 
01794                                    EntityHandle *other_nodes)
01795 {
01796     // get the entities used for foc; ocl and ocr are dual 1-cells 
01797     // representing quads to be split; returned from this function:
01798     // quads[2] - 2 quads to be split
01799     // split_edges[2] - edge(s) to be split (2nd is 0 if only one)
01800     // split_node - node to be split, if any (otherwise 0)
01801     // hexes - connected hexes to split_edges
01802     // other_edges[0], [1] - edges in quads[0] and [1] sharing node with
01803     //        one end of split_edges[0]
01804     // other_edges[2], [3] - other end of split_edges[0] (or [1] if 2 
01805     //        split_edges)
01806     // other_edges[4], [5] - edges in quads[0], [1] opposite to split_edges[0]
01807     // other_nodes[0], [1] - nodes on other_edges[0], [1] not shared with 
01808     //        split_edges[0]
01809     // other_nodes[2], [3] - nodes on other_edges[2], [3] not shared with 
01810     //        split_edges[0] (if 2 split_edges, there's only 1 opposite node
01811     //        in each split quad)
01812     // (for diagram, see Tim's notes from 11/12/07)
01813 
01814   split_quads[0] = get_dual_entity(ocl);
01815   split_quads[1] = get_dual_entity(ocr);
01816   if (MBQUAD != mbImpl->type_from_handle(split_quads[0]) ||
01817       MBQUAD != mbImpl->type_from_handle(split_quads[1]))
01818     return MB_TYPE_OUT_OF_RANGE;
01819 
01820   Range common_edges;
01821   ErrorCode result = mbImpl->get_adjacencies(split_quads, 2, 1, false, 
01822                                                common_edges);
01823   if (MB_SUCCESS != result) return result;
01824   
01825   if (common_edges.empty()) return MB_FAILURE;
01826   for (unsigned int i = 0; i < common_edges.size(); i++) 
01827     split_edges[i] = common_edges[i];
01828 
01829   MeshTopoUtil mtu(mbImpl);
01830 
01831   if (common_edges.size() == 3) {
01832       // find other (non-shared) edges
01833     for (int i = 0; i < 2; i++) {
01834       Range tmp_edges;
01835       result = mbImpl->get_adjacencies(&split_quads[i], 1, 1, false, 
01836                                        tmp_edges);
01837       if (MB_SUCCESS != result) return result;
01838       tmp_edges = subtract( tmp_edges, common_edges);
01839       assert(tmp_edges.size() == 1);
01840       other_edges[i] = *tmp_edges.begin();
01841     }
01842     assert(other_edges[0] && other_edges[1] &&
01843            other_edges[0] != other_edges[1]);
01844     
01845       // arrange common edges so middle is in middle
01846     result = mtu.opposite_entity(split_quads[0], other_edges[0],
01847                                  split_edges[1]); RR;
01848     common_edges.erase(split_edges[1]);
01849     split_edges[0] = *common_edges.begin();
01850     split_edges[2] = *common_edges.rbegin();
01851     common_edges.insert(split_edges[1]);
01852     
01853       // get split nodes and other nodes
01854     split_nodes[0] = mtu.common_entity(split_edges[0], split_edges[1], 0);
01855     split_nodes[1] = mtu.common_entity(split_edges[2], split_edges[1], 0);
01856     other_nodes[0] = mtu.common_entity(split_edges[0], other_edges[0], 0);
01857     other_nodes[1] = mtu.common_entity(split_edges[2], other_edges[1], 0);
01858 
01859     assert(other_nodes[0] && other_nodes[1] && split_nodes[0] && split_nodes[1]);
01860     assert(split_edges[0] && split_edges[1] && split_edges[2] &&
01861            split_edges[0] != split_edges[1] && split_edges[1] != split_edges[2] &&
01862            split_edges[0] != split_edges[2]);
01863   }
01864   else if (common_edges.size() == 2) {
01865       // split node is shared by split edges
01866     split_nodes[0] = mtu.common_entity(split_edges[0], split_edges[1], 0);
01867     if (0 == split_nodes[0]) return MB_FAILURE;
01868       // first two other nodes are on split edges opposite split node
01869     result = mtu.opposite_entity(split_edges[0], split_nodes[0],
01870                                  other_nodes[0]); RR;
01871     result = mtu.opposite_entity(split_edges[1], split_nodes[0],
01872                                  other_nodes[1]); RR;
01873       // over split quads:
01874     for (int i = 0; i < 2; i++) {
01875         // 1st other edge is opposite second split edge
01876       result = mtu.opposite_entity(split_quads[i], 
01877                                    split_edges[1], other_edges[i]); RR;
01878         // 2nd other edge is opposite first split edge
01879       result = mtu.opposite_entity(split_quads[i], 
01880                                    split_edges[0], other_edges[2+i]); RR;
01881         // last other node is opposite split node on split quad
01882       result = mtu.opposite_entity(split_quads[i], split_nodes[0],
01883                                    other_nodes[2+i]); RR;
01884     }
01885   }
01886   else {
01887     const EntityHandle *connect;
01888     int num_connect;
01889     result = mbImpl->get_connectivity(split_edges[0], connect, num_connect);
01890     if (MB_SUCCESS != result) return result;
01891       // other_nodes[0], [1] are on split edge
01892     other_nodes[0] = connect[0];
01893     other_nodes[1] = connect[1];
01894       
01895       // for each of the split quads
01896     for (int i = 0; i < 2; i++) {
01897         // get the other edge on the split quad adj to node 0 on the split edge, by getting
01898         // edges adj to split quad and node and removing split edge; that's other_edge[i]
01899       Range tmp_range1, tmp_range2;
01900       tmp_range1.insert(connect[0]);
01901       tmp_range1.insert(split_quads[i]);
01902       result = mbImpl->get_adjacencies(tmp_range1, 1, false, tmp_range2);
01903       if (MB_SUCCESS != result) return result;
01904       tmp_range2.erase(split_edges[0]);
01905       assert(tmp_range2.size() == 1);
01906       other_edges[i] = *tmp_range2.begin();
01907         // get edge connected to other node on split edge & split quad; that's
01908         // opposite prev other_edges on the split quad; that's other_edges[4+i]
01909       result = mtu.opposite_entity(split_quads[i], other_edges[i],
01910                                    other_edges[4+i]); RR;
01911         // get the edge on the split quad opposite the split edge; that's other_edges[2+i]
01912       result = mtu.opposite_entity(split_quads[i], split_edges[0],
01913                                    other_edges[2+i]); RR;
01914         // get nodes on other side of split quad from split edge, by getting common
01915         // node between top/bottom edge and opposite edge
01916       other_nodes[2+i] = mtu.common_entity(other_edges[i], other_edges[2+i], 0);
01917       other_nodes[4+i] = mtu.common_entity(other_edges[4+i], other_edges[2+i], 0);
01918       if (0 == other_nodes[2+i] || 0 == other_nodes[4+i]) return MB_FAILURE;
01919     }
01920   }
01921 
01922   result = mbImpl->get_adjacencies(split_edges, common_edges.size(), 3, false, 
01923                                    hexes, Interface::UNION);
01924   if (MB_SUCCESS != result) return result;
01925 
01926   assert("split node not in other_nodes" &&
01927          other_nodes[0] != split_nodes[0] && other_nodes[0] != split_nodes[1] &&
01928          other_nodes[1] != split_nodes[0] && other_nodes[1] != split_nodes[1]);
01929   assert("each split node on an end of a split edge" &&
01930          mtu.common_entity(other_nodes[0], split_edges[0], 0) &&
01931          (((split_edges[2] && mtu.common_entity(other_nodes[1], split_edges[2], 0)) ||
01932            (split_edges[1] && mtu.common_entity(other_nodes[1], split_edges[1], 0)) ||
01933            mtu.common_entity(other_nodes[1], split_edges[0], 0))));
01934   assert("opposite other edges meet at an other node" &&
01935          (mtu.common_entity(other_edges[0], other_edges[1], 0) == other_nodes[0] ||
01936           (split_edges[2] && 
01937            mtu.common_entity(other_edges[0], other_edges[1], 0) == other_nodes[1])) &&
01938          (split_edges[2] || 
01939           (split_edges[1] && 
01940            mtu.common_entity(other_edges[2], other_edges[3], 0) == other_nodes[1]) ||
01941           mtu.common_entity(other_edges[4], other_edges[5], 0) == other_nodes[1]));
01942          
01943   return MB_SUCCESS;
01944 }
01945 
01946 ErrorCode DualTool::split_pair_nonmanifold(EntityHandle *split_quads,
01947                                              EntityHandle *split_edges,
01948                                              EntityHandle *split_nodes,
01949                                              std::vector<EntityHandle> *star_dp1,
01950                                              std::vector<EntityHandle> *star_dp2,
01951                                              EntityHandle * /*other_edges*/,
01952                                              EntityHandle * /*other_nodes*/,
01953                                              EntityHandle *new_quads,
01954                                              EntityHandle *new_edges,
01955                                              EntityHandle *new_nodes)
01956 {
01957 
01958     // if there's a bdy in the star around the shared edge(s), get the quads on that
01959     // bdy so we know which edges to merge after the split-nonmanifold
01960   MeshTopoUtil mtu(mbImpl);
01961   ErrorCode result;
01962 
01963     // get which star the split faces are in, and choose the other one
01964   int new_side = -1;
01965   if (std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[0]) !=
01966       star_dp1[0].end())
01967     new_side = 1;
01968   else if (std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[0]) !=
01969            star_dp1[1].end())
01970     new_side = 0;
01971   assert(-1 != new_side);
01972   if (-1 == new_side) return MB_FAILURE;
01973     
01974     //=============== split faces
01975 
01976   for (int i = 0; i < 2; i++) {
01977       // get a hex in star_dp2[new_side] that's adj to this split quad, to tell 
01978       // mtu which one the new quad should go with; there should be at least one,
01979       // if we have any hexes connected to the split quad
01980     EntityHandle gowith_hex = 0;
01981     for (std::vector<EntityHandle>::iterator vit = star_dp2[new_side].begin();
01982          vit != star_dp2[new_side].end(); vit++) {
01983       if (mtu.common_entity(*vit, split_quads[i], 2)) {
01984         gowith_hex = *vit;
01985         break;
01986       }
01987     }
01988     assert(0 != gowith_hex);
01989     
01990     // split manifold each of the split_quads, and put the results on the merge list
01991     result = mtu.split_entities_manifold(split_quads+i, 1, new_quads+i, NULL,
01992                                          (gowith_hex ? &gowith_hex : NULL)); RR;
01993   }
01994 
01995     // make ranges of faces which need to be explicitly adj to old, new
01996     // edge; faces come from stars and new_quads (which weren't in the stars);
01997     // new_quads go with side j, which does not have split quads
01998   Range tmp_addl_faces[2], addl_faces[2];
01999   for (int i = 0; i < 2; i++) {
02000     std::copy(star_dp1[i].begin(), star_dp1[i].end(), 
02001             range_inserter(tmp_addl_faces[i]));
02002     tmp_addl_faces[new_side].insert(new_quads[i]);
02003   }
02004 #ifndef NDEBUG
02005   bool cond1 = ("split_quads on 1, new_quads on 0" &&
02006           tmp_addl_faces[0].find(split_quads[0]) == tmp_addl_faces[0].end() &&
02007           tmp_addl_faces[0].find(split_quads[1]) == tmp_addl_faces[0].end() &&
02008           tmp_addl_faces[1].find(split_quads[0]) != tmp_addl_faces[1].end() &&
02009           tmp_addl_faces[1].find(split_quads[1]) != tmp_addl_faces[1].end() &&
02010           tmp_addl_faces[0].find(new_quads[0]) != tmp_addl_faces[0].end() &&
02011           tmp_addl_faces[0].find(new_quads[1]) != tmp_addl_faces[0].end() &&
02012           tmp_addl_faces[1].find(new_quads[0]) == tmp_addl_faces[1].end() &&
02013                 tmp_addl_faces[1].find(new_quads[1]) == tmp_addl_faces[1].end()),
02014       cond2 = ("split_quads on 0, new_quads on 1" &&
02015                tmp_addl_faces[0].find(split_quads[0]) != tmp_addl_faces[0].end() &&
02016                tmp_addl_faces[0].find(split_quads[1]) != tmp_addl_faces[0].end() &&
02017                tmp_addl_faces[1].find(split_quads[0]) == tmp_addl_faces[1].end() &&
02018                tmp_addl_faces[1].find(split_quads[1]) == tmp_addl_faces[1].end() &&
02019                tmp_addl_faces[0].find(new_quads[0]) == tmp_addl_faces[0].end() &&
02020                tmp_addl_faces[0].find(new_quads[1]) == tmp_addl_faces[0].end() &&
02021                tmp_addl_faces[1].find(new_quads[0]) != tmp_addl_faces[1].end() &&
02022                tmp_addl_faces[1].find(new_quads[1]) != tmp_addl_faces[1].end());
02023   
02024   assert(cond1 || cond2);
02025 #endif
02026 
02027     //=============== split edge(s)
02028   for (int j = 0; j < 3; j++) {
02029     if (!split_edges[j]) break;
02030     
02031       // filter add'l faces to only those adj to split_edges[j]
02032     addl_faces[0] = tmp_addl_faces[0]; addl_faces[1] = tmp_addl_faces[1];
02033     for (int i = 0; i < 2; i++) {
02034       result = mbImpl->get_adjacencies(&split_edges[j], 1, 2, false, 
02035                                        addl_faces[i]); RR;
02036     }
02037   
02038       // split edge
02039     result = mtu.split_entity_nonmanifold(split_edges[j], addl_faces[1-new_side], 
02040                                           addl_faces[new_side], new_edges[j]); RR;
02041   }
02042   
02043     //=============== split node(s)
02044 
02045   for (int j = 0; j < 2; j++) {
02046     if (!split_nodes[j]) break;
02047     
02048       // if we're splitting multiple edges, there might be other edges that have the split
02049       // node; also need to know which side they're on
02050     Range tmp_addl_edges[2];
02051     result = foc_get_addl_ents(star_dp1, star_dp2, split_edges, 
02052                                split_nodes[j], tmp_addl_edges); RR;
02053 
02054       // also, we need to know which of the split/new edges go
02055       // with the split/new node; new edges go with side 0, split with 1
02056     for (int i = 0; i < 3; i++) {
02057       if (!split_edges[i]) break;
02058       tmp_addl_edges[new_side].insert(new_edges[i]);
02059       tmp_addl_edges[1-new_side].insert(split_edges[i]);
02060     }
02061 
02062       // same for star faces and hexes
02063     for (int i = 0; i < 2; i++) {
02064       std::copy(star_dp1[i].begin(), star_dp1[i].end(), range_inserter(tmp_addl_edges[i]));
02065       std::copy(star_dp2[i].begin(), star_dp2[i].end(), range_inserter(tmp_addl_edges[i]));
02066     }
02067 
02068       // finally, new quads
02069     for (int i = 0; i < 2; i++) tmp_addl_edges[new_side].insert(new_quads[i]);
02070 
02071       // filter the entities, keeping only the ones adjacent to this node
02072     Range addl_edges[2];
02073     for (int i = 0; i < 2; i++) {
02074       for (Range::reverse_iterator rit = tmp_addl_edges[i].rbegin(); 
02075            rit != tmp_addl_edges[i].rend(); rit++) {
02076         if (mtu.common_entity(*rit, split_nodes[j], 0)) addl_edges[i].insert(*rit);
02077       }
02078     }
02079     
02080       // now split the node too
02081     result = mtu.split_entity_nonmanifold(split_nodes[j], addl_edges[1-new_side], 
02082                                           addl_edges[new_side], new_nodes[j]); RR;
02083   }
02084   
02085   return MB_SUCCESS;
02086 }
02087 
02088 ErrorCode DualTool::foc_get_addl_ents(std::vector<EntityHandle> *star_dp1, 
02089                                         std::vector<EntityHandle> * /*star_dp2*/, 
02090                                         EntityHandle *split_edges,
02091                                         EntityHandle split_node,
02092                                         Range *addl_ents) 
02093 {
02094     // if we're splitting 2 edges, there might be other edges that have the split
02095     // node; also need to know which side they're on
02096 
02097     // algorithm: for a given star_dp1 (faces) on a side:
02098     // - get all edges adj to all faces -> R1
02099     // - get all edges adj to split_node -> R2
02100     // - R3 = R1 & R2 (edges connected to split_node & adj to a star face)
02101     // - R3 -= split_edges (take split edges off addl_ents)
02102 
02103   Range R2;
02104   MeshTopoUtil mtu(mbImpl);
02105   ErrorCode result = mbImpl->get_adjacencies(&split_node, 1, 1, false, R2); RR;
02106   Range::iterator rit;
02107 
02108   for (int i = 0; i < 2; i++) {
02109     Range R1, R3;
02110     result = mbImpl->get_adjacencies(&star_dp1[i][0], star_dp1[i].size(), 1, false, 
02111                                      R1, Interface::UNION); RR;
02112     R3 = intersect( R1, R2);
02113     for (int j = 0; j < 3; j++)
02114       if (split_edges[j]) R3.erase(split_edges[j]);
02115     addl_ents[i].merge(R3);
02116   }
02117   
02118   return MB_SUCCESS;
02119 }
02120 
02121 ErrorCode DualTool::foc_get_stars(EntityHandle *split_quads,
02122                                     EntityHandle *split_edges,
02123                                     std::vector<EntityHandle> *star_dp1,
02124                                     std::vector<EntityHandle> *star_dp2) 
02125 {
02126   bool on_bdy = false, on_bdy_tmp;
02127   ErrorCode result;
02128   MeshTopoUtil mtu(mbImpl);
02129   
02130     // get the star around the split_edge
02131   std::vector<EntityHandle> qstar, hstar;
02132   unsigned int qpos = 0;
02133   
02134   for (int i = 0; i < 3; i++) {
02135     if (!split_edges[i]) break;
02136     
02137       // get the star around this split edge
02138     unsigned int qpos_tmp = 0;
02139     std::vector<EntityHandle> qstar_tmp, hstar_tmp;
02140     result = mtu.star_entities(split_edges[i], qstar_tmp, on_bdy_tmp, 0,
02141                              &hstar_tmp); RR;
02142       // if we're on the bdy, add a null to the hex star too
02143     if (on_bdy_tmp) {
02144       assert(hstar_tmp.size() == qstar_tmp.size()-1);
02145       hstar_tmp.push_back(0);
02146       on_bdy = true;
02147     }
02148     
02149       // get the position of first split quad in star
02150     while (qpos_tmp < qstar_tmp.size() && qstar_tmp[qpos_tmp] != split_quads[0])
02151       qpos_tmp++;
02152     if (qpos_tmp == qstar_tmp.size()) return MB_FAILURE;
02153   
02154     bool forward;
02155       // 1st iteration is forward by definition
02156     if (0 == i) forward = true;
02157 
02158       // need to be careful about direction on later iters
02159     else if (hstar[qpos] == hstar_tmp[qpos_tmp]) forward = true;
02160     else if (hstar[qpos] == hstar_tmp[(qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size()] &&
02161              hstar_tmp[qpos_tmp] == hstar[(qpos+qstar.size()-1)%qstar.size()])
02162       forward = false;
02163     else return MB_FAILURE;
02164     
02165     if (forward) {
02166         // 1st half of star
02167         // save hex right after split_quad[0] first
02168       star_dp2[0].push_back(hstar_tmp[qpos_tmp]);
02169       qpos_tmp = (qpos_tmp+1)%qstar_tmp.size();
02170       while (qstar_tmp[qpos_tmp] != split_quads[1]) {
02171         star_dp1[0].push_back(qstar_tmp[qpos_tmp]);
02172         star_dp2[0].push_back(hstar_tmp[qpos_tmp]);
02173         qpos_tmp = (qpos_tmp+1)%qstar_tmp.size();
02174       }
02175         // 2nd half of star
02176         // save hex right after split_quad[1] first
02177       star_dp2[1].push_back(hstar_tmp[qpos_tmp]);
02178       qpos_tmp = (qpos_tmp+1)%qstar_tmp.size();
02179       while (qstar_tmp[qpos_tmp] != split_quads[0]) {
02180         star_dp1[1].push_back(qstar_tmp[qpos_tmp]);
02181         star_dp2[1].push_back(hstar_tmp[qpos_tmp]);
02182         qpos_tmp = (qpos_tmp+1)%qstar_tmp.size();
02183       }
02184     }
02185     else {
02186         // go in reverse - take prev hex instead of current
02187         // one, and step in reverse
02188 
02189         // save hex right after split_quad[0] first
02190       qpos_tmp = (qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size();
02191       star_dp2[0].push_back(hstar_tmp[qpos_tmp]);
02192       while (qstar_tmp[qpos_tmp] != split_quads[1]) {
02193         star_dp1[0].push_back(qstar_tmp[qpos_tmp]);
02194         qpos_tmp = (qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size();
02195         star_dp2[0].push_back(hstar_tmp[qpos_tmp]);
02196       }
02197         // 2nd half of star
02198         // save hex right after split_quad[1] first
02199       qpos_tmp = (qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size();
02200       star_dp2[1].push_back(hstar_tmp[qpos_tmp]);
02201       while (qstar_tmp[qpos_tmp] != split_quads[0]) {
02202         star_dp1[1].push_back(qstar_tmp[qpos_tmp]);
02203         qpos_tmp = (qpos_tmp+qstar_tmp.size()-1)%qstar_tmp.size();
02204         star_dp2[1].push_back(hstar_tmp[qpos_tmp]);
02205       }
02206     }
02207 
02208     if (0 == i) {
02209       // if we're on the first iteration, save results and continue, other iters
02210       // get compared to this one
02211       qstar.swap(qstar_tmp);
02212       hstar.swap(hstar_tmp);
02213       on_bdy = on_bdy_tmp;
02214       qpos = qpos_tmp;
02215     }
02216   }
02217   
02218     // split quads go on list with NULLs, if any, otherwise on 2nd
02219   if (on_bdy) {
02220     if (std::find(star_dp2[0].begin(), star_dp2[0].end(), 0) != 
02221         star_dp2[0].end()) {
02222         // remove *all* the zeros
02223       star_dp2[0].erase(std::remove(star_dp2[0].begin(), star_dp2[0].end(), 0),
02224                         star_dp2[0].end());
02225         // put the split quads on this half
02226       star_dp1[0].push_back(split_quads[0]);
02227       star_dp1[0].push_back(split_quads[1]);
02228     }
02229     else {
02230       star_dp2[1].erase(std::remove(star_dp2[1].begin(), star_dp2[1].end(), 0),
02231                         star_dp2[1].end());
02232         // put the split quads on this half
02233       star_dp1[1].push_back(split_quads[0]);
02234       star_dp1[1].push_back(split_quads[1]);
02235     }
02236   }
02237   else {
02238     star_dp1[1].push_back(split_quads[0]);
02239     star_dp1[1].push_back(split_quads[1]);
02240   }
02241 
02242     // some error checking
02243   if (!(((std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[0]) == star_dp1[0].end() &&
02244           std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[1]) == star_dp1[0].end() &&
02245           std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[0]) != star_dp1[1].end() &&
02246           std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[1]) != star_dp1[1].end()) ||
02247          
02248          (std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[0]) == star_dp1[1].end() &&
02249           std::find(star_dp1[1].begin(), star_dp1[1].end(), split_quads[1]) == star_dp1[1].end() &&
02250           std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[0]) != star_dp1[0].end() &&
02251           std::find(star_dp1[0].begin(), star_dp1[0].end(), split_quads[1]) != star_dp1[0].end()))
02252         )) {
02253     std::cerr << "foc_get_stars: both split quads should be on the same star list half and not "
02254               << "on the other, failed" << std::endl;
02255     return MB_FAILURE;
02256   }
02257   
02258   if (!(std::find(star_dp2[0].begin(), star_dp2[0].end(), 0) == star_dp2[0].end() &&
02259         std::find(star_dp2[1].begin(), star_dp2[1].end(), 0) == star_dp2[1].end())) {
02260     std::cerr << "foc_get_stars: no NULLs on the hstar lists, failed";
02261     return MB_FAILURE;
02262   }
02263   
02264   return MB_SUCCESS;
02265 }
02266 
02267 ErrorCode DualTool::foc_delete_dual(EntityHandle *split_quads,
02268                                       EntityHandle *split_edges,
02269                                       Range &hexes) 
02270 {
02271     // special delete dual procedure, because in some cases we need to delete
02272     // a sheet too since it'll get merged into another
02273 
02274     // figure out whether we'll need to delete a sheet
02275   EntityHandle sheet1, sheet2 = 0;
02276   sheet1 = get_dual_hyperplane(get_dual_entity(split_edges[0]));
02277   if (split_edges[1]) sheet1 = get_dual_hyperplane(get_dual_entity(split_edges[1]));
02278   EntityHandle chordl = get_dual_hyperplane(get_dual_entity(split_quads[0]));
02279   EntityHandle chordr = get_dual_hyperplane(get_dual_entity(split_quads[1]));
02280   assert(0 != sheet1 && 0 != chordl && 0 != chordr);
02281   Range parentsl, parentsr;
02282   ErrorCode result = mbImpl->get_parent_meshsets(chordl, parentsl);
02283   if (MB_SUCCESS != result) return result;
02284   result = mbImpl->get_parent_meshsets(chordr, parentsr);
02285   if (MB_SUCCESS != result) return result;
02286   parentsl.erase(sheet1);
02287   parentsr.erase(sheet1);
02288   if (sheet2) parentsl.erase(sheet1), parentsr.erase(sheet1);
02289 
02290     // before deciding which one to delete, collect the other cells which must
02291     // be deleted, and all the chords/sheets they're on
02292   Range adj_ents, dual_ents, cells1or2;
02293   for (int i = 0; i < 3; i++) {
02294     result = mbImpl->get_adjacencies(hexes, i, false, adj_ents, Interface::UNION);
02295     if (MB_SUCCESS != result) return result;
02296   }
02297 
02298     // cache any adjacent hexes, for rebuilding the dual later
02299   result = mbImpl->get_adjacencies(adj_ents, 3, false, hexes, Interface::UNION);
02300   if (MB_SUCCESS != result) return result;
02301   
02302   for (Range::iterator rit = adj_ents.begin(); rit != adj_ents.end(); rit++) {
02303     EntityHandle this_ent = get_dual_entity(*rit);
02304     dual_ents.insert(this_ent);
02305     int dim = mbImpl->dimension_from_handle(this_ent);
02306     if (1 == dim || 2 == dim) cells1or2.insert(this_ent);
02307   }
02308 
02309   Range dual_hps;
02310   for (Range::iterator rit = cells1or2.begin(); rit != cells1or2.end(); rit++)
02311     dual_hps.insert(get_dual_hyperplane(*rit));
02312 
02313   result = delete_dual_entities(dual_ents);
02314   if (MB_SUCCESS != result) return result;
02315 
02316     // now decide which sheet to delete (to be merged into the other)
02317   EntityHandle sheet_delete = 0;
02318   if (is_blind(*parentsl.begin())) sheet_delete = *parentsl.begin();
02319   else if (is_blind(*parentsr.begin())) sheet_delete = *parentsr.begin();
02320   else {
02321       // neither is blind, take the one with fewer cells
02322     Range tmp_ents;
02323     int numl, numr;
02324     result = mbImpl->get_number_entities_by_handle(*parentsl.begin(), numl);
02325     if (MB_SUCCESS != result) return result;
02326     result = mbImpl->get_number_entities_by_handle(*parentsr.begin(), numr);
02327     if (MB_SUCCESS != result) return result;
02328     sheet_delete = (numl > numr ? *parentsr.begin() : *parentsl.begin());
02329   }
02330   assert(0 != sheet_delete);
02331   
02332     // after deleting cells, check for empty chords & sheets, and delete those too
02333   for (Range::iterator rit = dual_hps.begin(); rit != dual_hps.end(); rit++) {
02334     Range tmp_ents;
02335     result = mbImpl->get_entities_by_handle(*rit, tmp_ents);
02336     if (MB_SUCCESS != result) return result;
02337     if (tmp_ents.empty()) {
02338       result = mbImpl->delete_entities(&(*rit), 1);
02339       if (MB_SUCCESS != result) return result;
02340     }
02341     else if (*rit == sheet_delete) {
02342         // delete the sheet
02343       result = mbImpl->delete_entities(&(*rit), 1);
02344       if (MB_SUCCESS != result) return result;
02345     }
02346   }
02347 
02348     // now just to be safe, add the hexes bridge-adjacent across vertices
02349     // to the hexes we already have
02350   Range tmp_hexes;
02351   MeshTopoUtil mtu(mbImpl);
02352   for (Range::iterator rit = hexes.begin(); rit != hexes.end(); rit++) {
02353     result = mtu.get_bridge_adjacencies(*rit, 0, 3, tmp_hexes);
02354     if (MB_SUCCESS != result) return result;
02355   }
02356   hexes.merge(tmp_hexes);
02357 
02358   return MB_SUCCESS;
02359 }
02360 
02362 bool DualTool::is_blind(const EntityHandle chord_or_sheet) 
02363 {
02364     // must be an entity set
02365   if (TYPE_FROM_HANDLE(chord_or_sheet) != MBENTITYSET) return false;
02366   
02367     // get the vertices
02368   Range verts, ents;
02369   ErrorCode result = mbImpl->get_entities_by_handle(chord_or_sheet, ents); 
02370   if (MB_SUCCESS != result || ents.empty()) return false;
02371   
02372   result = mbImpl->get_adjacencies(ents, 0, false, verts, Interface::UNION);
02373   if (MB_SUCCESS != result || verts.empty()) return false;
02374   
02375   for (Range::iterator rit = verts.begin(); rit != verts.end(); rit++) {
02376       // get dual entity for this vertex
02377     EntityHandle dual_ent = get_dual_entity(*rit);
02378     if (0 == dual_ent) continue;
02379     if (TYPE_FROM_HANDLE(dual_ent) == MBQUAD) return false;
02380   }
02381 
02382     // if none of the vertices' duals were quads, chord_or_sheet must be blind
02383   return true;
02384 }
02385 
02388 ErrorCode DualTool::get_opposite_verts(const EntityHandle middle_edge, 
02389                                          const EntityHandle chord, 
02390                                          EntityHandle *verts) 
02391 {
02392     // get the edges on the chord, in order, and move to middle_edge
02393   std::vector<EntityHandle> chord_edges;
02394   const EntityHandle *connect;
02395   int num_connect;
02396   
02397   ErrorCode result = mbImpl->get_entities_by_handle(chord, chord_edges); RR;
02398   std::vector<EntityHandle>::iterator vit = std::find(chord_edges.begin(), chord_edges.end(),
02399                                                         middle_edge);
02400   result = mbImpl->get_connectivity(middle_edge, connect, num_connect); RR;
02401 
02402   if (
02403       // middle_edge isn't on this chord
02404     vit == chord_edges.end() || 
02405       // chord only has 1 edge
02406     chord_edges.size() == 1 ||
02407       // middle_edge is at beginning or end and chord isn't blind
02408       ((vit == chord_edges.begin() || vit == chord_edges.end()-1) && !is_blind(chord))) 
02409     return MB_FAILURE;
02410 
02411   else if (chord_edges.size() == 2) {
02412       // easier if it's a 2-edge blind chord, just get vertices in opposite order
02413     verts[0] = connect[1];
02414     verts[1] = connect[0];
02415     return MB_SUCCESS;
02416   }
02417   
02418     // get vertices with the prev edge & subtract vertices of 1-cell
02419   if (vit == chord_edges.begin())
02420     vit = chord_edges.end() - 1;
02421   else vit--;
02422   Range dum_connect, middle_connect;
02423   result = mbImpl->get_connectivity(&middle_edge, 1, middle_connect); RR;
02424   result = mbImpl->get_connectivity(&(*vit), 1, dum_connect); RR;
02425   dum_connect = subtract( dum_connect, middle_connect);
02426   if (dum_connect.size() != 1) {
02427     std::cerr << "Trouble traversing chord." << std::endl;
02428     return MB_FAILURE;
02429   }
02430 
02431     // put in verts[0]
02432   verts[0] = *dum_connect.begin();
02433 
02434     // same with prev edge
02435   vit++;
02436   if (vit == chord_edges.end()) vit = chord_edges.begin();
02437   vit++;
02438   dum_connect.clear();
02439   result = mbImpl->get_connectivity(&(*vit), 1, dum_connect); RR;
02440   dum_connect = subtract( dum_connect, middle_connect);
02441   if (dum_connect.size() != 1) {
02442     std::cerr << "Trouble traversing chord." << std::endl;
02443     return MB_FAILURE;
02444   }
02445 
02446     // put in verts[1]
02447   verts[1] = *dum_connect.begin();
02448 
02449     // if verts[0] and 1st vertex of 1cell don't have common edge, switch verts
02450   MeshTopoUtil mtu(mbImpl);
02451   if (0 == mtu.common_entity(verts[0], connect[0], 1)) {
02452     EntityHandle dum_h = verts[0];
02453     verts[0] = verts[1];
02454     verts[1] = dum_h;
02455   }
02456   
02457   if (0 == mtu.common_entity(verts[0], connect[0], 1)) {
02458     std::cerr << "Trouble traversing chord." << std::endl;
02459     return MB_FAILURE;
02460   }
02461   
02462   return MB_SUCCESS;
02463 }
02464 
02465 ErrorCode DualTool::get_dual_entities(const EntityHandle dual_ent,
02466                                         Range *dcells,
02467                                         Range *dedges,
02468                                         Range *dverts,
02469                                         Range *dverts_loop,
02470                                         Range *dedges_loop)
02471 {
02472   ErrorCode result = MB_SUCCESS;
02473 
02474   if (NULL != dcells) {
02475     result = mbImpl->get_entities_by_type(dual_ent, MBPOLYGON, *dcells);
02476     if (MB_SUCCESS != result) return result;
02477   }
02478   
02479   if (NULL != dedges) {
02480     if (NULL != dcells)
02481       result = mbImpl->get_adjacencies(*dcells, 1, false, *dedges, Interface::UNION);
02482     else 
02483       result = mbImpl->get_entities_by_type(dual_ent, MBEDGE, *dedges);
02484 
02485     if (MB_SUCCESS != result) return result;
02486   }
02487 
02488   if (NULL != dverts) {
02489     if (NULL != dcells)
02490       result = mbImpl->get_adjacencies(*dcells, 0, false, *dverts, Interface::UNION);
02491     else if (NULL != dedges)
02492       result = mbImpl->get_adjacencies(*dedges, 0, false, *dverts, Interface::UNION);
02493     else {
02494       Range all_ents;
02495       result = mbImpl->get_entities_by_handle(dual_ent, all_ents); RR;
02496       result = mbImpl->get_adjacencies(all_ents, 0, false, *dverts, Interface::UNION);
02497     }
02498 
02499     if (MB_SUCCESS != result) return result;
02500   }
02501 
02502   if (NULL != dverts_loop && NULL != dverts) {
02503     static std::vector<EntityHandle> dual_ents;
02504     dual_ents.reserve(dverts->size());
02505     result = mbImpl->tag_get_data(dualEntity_tag(), *dverts, &dual_ents[0]);
02506     if (MB_SUCCESS != result) return result;
02507     Range::iterator rit;
02508     unsigned int i;
02509     for (rit = dverts->begin(), i = 0; rit != dverts->end(); rit++, i++)
02510       if (0 != dual_ents[i] && mbImpl->type_from_handle(dual_ents[i]) == MBQUAD)
02511         dverts_loop->insert(*rit);
02512   }
02513   
02514   if (NULL != dedges_loop && NULL != dedges) {
02515     static std::vector<EntityHandle> dual_ents;
02516     dual_ents.reserve(dedges->size());
02517     result = mbImpl->tag_get_data(dualEntity_tag(), *dedges, &dual_ents[0]);
02518     if (MB_SUCCESS != result) return result;
02519     Range::iterator rit;
02520     unsigned int i;
02521     for (rit = dedges->begin(), i = 0; rit != dedges->end(); rit++, i++)
02522       if (0 != dual_ents[i] && mbImpl->type_from_handle(dual_ents[i]) == MBEDGE)
02523         dedges_loop->insert(*rit);
02524   }
02525 
02526   return result;
02527 }
02528 
02529 ErrorCode DualTool::list_entities(const EntityHandle *entities,
02530                                     const int num_entities) const
02531 {
02532   Range temp_range;
02533   ErrorCode result;
02534   if (NULL == entities && 0 == num_entities) 
02535     return mbImpl->list_entities(entities, num_entities);
02536   
02537   else if (NULL == entities && 0 < num_entities) {
02538 
02539       // list all entities of all types
02540     std::cout << std::endl;
02541     for (EntityType this_type = MBVERTEX; this_type < MBMAXTYPE; this_type++) {
02542       result = mbImpl->get_entities_by_type(0, this_type, temp_range);
02543       if (MB_SUCCESS != result) return result;
02544     }
02545   }
02546   
02547   else {
02548     std::copy(entities, entities+num_entities, range_inserter(temp_range));
02549   }
02550 
02551   return list_entities(temp_range);
02552 }
02553   
02554 ErrorCode DualTool::list_entities(const Range &entities) const
02555 {
02556     // now print each entity, listing the dual information first then calling Interface to do
02557     // the rest
02558   ErrorCode result = MB_SUCCESS, tmp_result;
02559   for (Range::const_iterator iter = entities.begin(); iter != entities.end(); iter++) {
02560     EntityType this_type = TYPE_FROM_HANDLE(*iter);
02561     std::cout << CN::EntityTypeName(this_type) << " " << ID_FROM_HANDLE(*iter) << ":" << std::endl;
02562 
02563     EntityHandle dual_ent = get_dual_entity(*iter);
02564     if (0 != dual_ent) {
02565       std::cout << "Dual to " 
02566                 << CN::EntityTypeName(mbImpl->type_from_handle(dual_ent)) << " "
02567                 << mbImpl->id_from_handle(dual_ent) << std::endl;
02568     }
02569 
02570     if (TYPE_FROM_HANDLE(*iter) == MBENTITYSET) {
02571       EntityHandle chord = 0, sheet = 0;
02572       int id;
02573       result = mbImpl->tag_get_data(dualCurve_tag(), &(*iter), 1, &chord);
02574       result = mbImpl->tag_get_data(dualSurface_tag(), &(*iter), 1, &sheet);
02575       result = mbImpl->tag_get_data(globalId_tag(), &(*iter), 1, &id);
02576         
02577       if (0 != chord)
02578         std::cout << "(Dual chord " << id << ")" << std::endl;
02579       if (0 != sheet)
02580         std::cout << "(Dual sheet " << id << ")" << std::endl;
02581     }
02582 
02583     tmp_result = mbImpl->list_entity(*iter);
02584     if (MB_SUCCESS != tmp_result) result = tmp_result;
02585   }
02586 
02587   return result;
02588 }
02589 
02590 ErrorCode DualTool::face_shrink(EntityHandle odedge) 
02591 {
02592     // some preliminary checking
02593   if (mbImpl->type_from_handle(odedge) != MBEDGE) return MB_TYPE_OUT_OF_RANGE;
02594 
02595   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
02596   
02597   std::cout << "FS("; print_cell(odedge); std::cout << ")" << std::endl;
02598 
02599   EntityHandle quads[4], hexes[2];
02600   std::vector<EntityHandle> connects[4], side_quads[2];
02601 
02602     // get the quads along the chord through the 2 hexes, and the vertices 
02603     // for those quads
02604   ErrorCode result = fs_get_quads(odedge, quads, hexes, connects);
02605   if (MB_SUCCESS != result) return result;
02606   
02607     // flip/rotate connect arrays so they align & are same sense
02608   result = fs_check_quad_sense(hexes[0], quads[0], connects);
02609   if (MB_SUCCESS != result) return result;
02610 
02611     // get the quad loops along the "side" surfaces
02612   result = fs_get_quad_loops(hexes, connects, side_quads);
02613   if (MB_SUCCESS != result) return result;
02614   
02615     // ok, done with setup; now delete dual entities affected by this operation,
02616     // which is all the entities adjacent to vertices of dual edge
02617   Range adj_verts, adj_edges, dual_ents, cells1or2;
02618   MeshTopoUtil mtu(mbImpl);
02619   result = mtu.get_bridge_adjacencies(odedge, 0, 1, adj_edges);
02620   if (MB_SUCCESS != result) return result;
02621   result = mbImpl->get_adjacencies(adj_edges, 0, false, adj_verts, 
02622                                    Interface::UNION);
02623   if (MB_SUCCESS != result) return result;
02624   for (int i = 1; i <= 3; i++) {
02625     result = mbImpl->get_adjacencies(adj_verts, i, false, dual_ents, 
02626                                      Interface::UNION);
02627     if (MB_SUCCESS != result) return result;
02628   }
02629 
02630     // before deleting dual, grab the 1- and 2-cells
02631   for (Range::iterator rit = dual_ents.begin(); rit != dual_ents.end(); rit++) {
02632     int dim = mbImpl->dimension_from_handle(*rit);
02633     if (1 == dim || 2 == dim) cells1or2.insert(*rit);
02634   }
02635   Range dual_hps;
02636   for (Range::iterator rit = cells1or2.begin(); rit != cells1or2.end(); rit++)
02637     dual_hps.insert(get_dual_hyperplane(*rit));
02638   
02639   dual_ents.insert(odedge);
02640   result = delete_dual_entities(dual_ents);
02641   if (MB_SUCCESS != result) return result;
02642   
02643     // after deleting cells, check for empty chords & sheets, and delete those too
02644   for (Range::iterator rit = dual_hps.begin(); rit != dual_hps.end(); rit++) {
02645     Range tmp_ents;
02646     result = mbImpl->get_entities_by_handle(*rit, tmp_ents);
02647     if (MB_SUCCESS != result) return result;
02648     if (tmp_ents.empty()) {
02649       result = mbImpl->delete_entities(&(*rit), 1);
02650       if (MB_SUCCESS != result) return result;
02651     }
02652   }
02653 
02654     // remove any explicit adjacencies between side quads and hexes; don't check
02655     // for error, since there might not be adjacencies
02656   for (int i = 0; i < 4; i++) {
02657     for (int j = 0; j < 2; j++) {
02658       result = mbImpl->remove_adjacencies(side_quads[j][i], &hexes[j], 1);
02659     }
02660   }
02661   
02662     // make inner ring of vertices
02663     // get centroid of quad2
02664   double q2coords[12], avg[3] = {0.0, 0.0, 0.0};
02665   result = mbImpl->get_coords(&connects[1][0], 4, q2coords);
02666   if (MB_SUCCESS != result) return result;
02667   for (int i = 0; i < 4; i++) {
02668     avg[0] += q2coords[3*i];
02669     avg[1] += q2coords[3*i+1];
02670     avg[2] += q2coords[3*i+2];
02671   }
02672   avg[0] *= .25; avg[1] *= .25; avg[2] *= .25;
02673     // position new vertices
02674   connects[3].resize(4);
02675   for (int i = 0; i < 4; i++) {
02676     q2coords[3*i] = avg[0] + .25*(q2coords[3*i]-avg[0]);
02677     q2coords[3*i+1] = avg[1] + .25*(q2coords[3*i+1]-avg[1]);
02678     q2coords[3*i+2] = avg[2] + .25*(q2coords[3*i+2]-avg[2]);
02679     result = mbImpl->create_vertex(&q2coords[3*i], connects[3][i]);
02680     if (MB_SUCCESS != result) return result;
02681   }
02682   
02683     // ok, now have the 4 connectivity arrays for 4 quads; construct hexes
02684   EntityHandle hconnect[8], new_hexes[4];
02685   int new_hex_ids[4];
02686   
02687   for (int i = 0; i < 4; i++) {
02688     int i1 = i, i2 = (i+1)%4;
02689     hconnect[0] = connects[0][i1];
02690     hconnect[1] = connects[0][i2];
02691     hconnect[2] = connects[3][i2];
02692     hconnect[3] = connects[3][i1];
02693 
02694     hconnect[4] = connects[1][i1];
02695     hconnect[5] = connects[1][i2];
02696     hconnect[6] = connects[2][i2];
02697     hconnect[7] = connects[2][i1];
02698     
02699     result = mbImpl->create_element(MBHEX, hconnect, 8, new_hexes[i]);
02700     if (MB_SUCCESS != result) return result;
02701 
02702       // test for equiv entities from the side quads, and make explicit adjacencies
02703       // if there are any
02704     for (int j = 0; j < 2; j++) {
02705       if (mtu.equivalent_entities(side_quads[j][i])) {
02706         result = mbImpl->add_adjacencies(side_quads[j][i], &new_hexes[i], 1, false);
02707         if (MB_SUCCESS != result) return result;
02708       }
02709     }
02710 
02711     new_hex_ids[i] = ++maxHexId;
02712   }
02713 
02714     // set the global id tag on the new hexes
02715   result = mbImpl->tag_set_data(globalId_tag(), new_hexes, 4, new_hex_ids);
02716   if (MB_SUCCESS != result) return result;
02717   
02718     // now fixup other two hexes; start by getting hex through quads 0, 1       
02719     // make this first hex switch to the other side, to make the dual look like
02720     // a hex push
02721   int tmp_ids[2];
02722   result = mbImpl->tag_get_data(globalId_tag(), hexes, 2, tmp_ids);
02723   if (MB_SUCCESS != result) return result;
02724   
02725 
02726   result = mbImpl->delete_entities(hexes, 2);
02727   if (MB_SUCCESS != result) return result;
02728   result = mbImpl->delete_entities(&quads[1], 1);
02729   if (MB_SUCCESS != result) return result;
02730   for (int i = 0; i < 4; i++) {
02731     hconnect[i] = connects[3][i];
02732     hconnect[4+i] = connects[2][i];
02733   }
02734   result = mbImpl->create_element(MBHEX, hconnect, 8, hexes[0]);
02735   if (MB_SUCCESS != result) return result;
02736 
02737   for (int i = 0; i < 4; i++) {
02738     hconnect[i] = connects[0][i];
02739     hconnect[4+i] = connects[3][i];
02740   }
02741   result = mbImpl->create_element(MBHEX, hconnect, 8, hexes[1]);
02742   if (MB_SUCCESS != result) return result;
02743 
02744     // check for and fix any explicit adjacencies on either end quad
02745   if (mtu.equivalent_entities(quads[0]))
02746       mbImpl->add_adjacencies(quads[0], &hexes[1], 1, false);
02747   if (mtu.equivalent_entities(quads[2]))
02748       mbImpl->add_adjacencies(quads[2], &hexes[0], 1, false);
02749 
02750     // re-set the global ids for the hexes to what they were
02751   result = mbImpl->tag_set_data(globalId_tag(), hexes, 2, tmp_ids);
02752   if (MB_SUCCESS != result) return result;
02753   
02754   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
02755 
02756     // now update the dual
02757   Range tmph;
02758   result = mtu.get_bridge_adjacencies(hexes[0], 0, 3, tmph);
02759   if (MB_SUCCESS != result) return result;
02760   result = mtu.get_bridge_adjacencies(hexes[1], 0, 3, tmph);
02761   if (MB_SUCCESS != result) return result;
02762   tmph.insert(hexes[1]);
02763   result = construct_hex_dual(tmph);
02764   if (MB_SUCCESS != result) return result;
02765   
02766   return result;
02767 }
02768 
02769 ErrorCode DualTool:: fs_get_quad_loops(EntityHandle *hexes, 
02770                                          std::vector<EntityHandle> *connects, 
02771                                          std::vector<EntityHandle> *side_quads) 
02772 {
02773   for (int i = 0; i < 4; i++) {
02774     for (int j = 0; j < 2; j++) {
02775       Range adj_ents, dum_quads;
02776       adj_ents.insert(hexes[j]);
02777       adj_ents.insert(connects[j][i]);
02778       adj_ents.insert(connects[j][(i+1)%4]);
02779       adj_ents.insert(connects[j+1][i]);
02780       adj_ents.insert(connects[j+1][(i+1)%4]);
02781     
02782       ErrorCode result = mbImpl->get_adjacencies(adj_ents, 2, false, dum_quads);
02783       if (MB_SUCCESS != result) return result;
02784       assert(1 == dum_quads.size());
02785       side_quads[j].push_back(*dum_quads.begin());
02786     }
02787   }
02788   
02789   return MB_SUCCESS;
02790 }
02791   
02792 ErrorCode DualTool::fs_check_quad_sense(EntityHandle hex0,
02793                                           EntityHandle quad0,
02794                                           std::vector<EntityHandle> *connects) 
02795 {
02796     // check sense of 0th quad wrt hex; since sense is out of element,
02797     // switch if quad is NOT reversed wrt hex
02798   int dum1, dum2, sense = 0;
02799   ErrorCode result = mbImpl->side_number(hex0, quad0, dum1, sense, dum2);
02800   if (MB_SUCCESS != result) return result;
02801   assert(0 != sense);
02802   if (1 == sense) {
02803       // just switch sense of this one; others will get switched next
02804     EntityHandle dum = connects[0][0];
02805     connects[0][0] = connects[0][2];
02806     connects[0][2] = dum;
02807   }
02808   
02809     // check sense of 1st, 2nd quads, rotate if necessary to align connect arrays
02810   int index0 = -1, index2 = -1, sense0 = 0, sense2 = 0;
02811   MeshTopoUtil mtu(mbImpl);
02812   for (int i = 0; i < 4; i++) {
02813     if (0 != mtu.common_entity(connects[0][0], connects[1][i], 1)) {
02814       index0 = i;
02815       if (0 != mtu.common_entity(connects[0][1], connects[1][(i+1)%4], 1))
02816         sense0 = 1;
02817       else if (0 != mtu.common_entity(connects[0][1], connects[1][(i+4-1)%4], 1))
02818         sense0 = -1;
02819       break;
02820     }
02821   }
02822 
02823   assert(index0 != -1 && sense0 != 0);
02824   
02825   if (sense0 == -1) {
02826     EntityHandle dumh = connects[1][0];
02827     connects[1][0] = connects[1][2];
02828     connects[1][2] = dumh;
02829     if (index0%2 == 0)
02830       index0 = (index0+2)%4;
02831   }
02832 
02833   if (index0 != 0) {
02834     std::vector<EntityHandle> tmpc;
02835     for (int i = 0; i < 4; i++)
02836       tmpc.push_back(connects[1][(index0+i)%4]);
02837     connects[1].swap(tmpc);
02838   }
02839     
02840   for (int i = 0; i < 4; i++) {
02841     if (0 != mtu.common_entity(connects[1][0], connects[2][i], 1)) {
02842       index2 = i;
02843       if (0 != mtu.common_entity(connects[1][1], connects[2][(i+1)%4], 1))
02844         sense2 = 1;
02845       else if (0 != mtu.common_entity(connects[1][1], connects[2][(i+4-1)%4], 1))
02846         sense2 = -1;
02847       break;
02848     }
02849   }
02850 
02851   assert(index2 != -1 && sense2 != 0);
02852 
02853   if (sense2 == -1) {
02854     EntityHandle dumh = connects[2][0];
02855     connects[2][0] = connects[2][2];
02856     connects[2][2] = dumh;
02857     if (index2%2 == 0)
02858       index2 = (index2+2)%4;
02859   }
02860 
02861   if (index2 != 0) {
02862     std::vector<EntityHandle> tmpc;
02863     for (int i = 0; i < 4; i++)
02864       tmpc.push_back(connects[2][(index2+i)%4]);
02865     connects[2].swap(tmpc);
02866   }
02867     
02868   return MB_SUCCESS;
02869 }
02870 
02872 ErrorCode DualTool::rev_face_shrink(EntityHandle odedge) 
02873 {
02874   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
02875 
02876     // some preliminary checking
02877   if (mbImpl->type_from_handle(odedge) != MBEDGE) return MB_TYPE_OUT_OF_RANGE;
02878   
02879   std::cout << "-FS("; print_cell(odedge); std::cout << ")" << std::endl;
02880 
02881   EntityHandle quads[4], hexes[2];
02882   std::vector<EntityHandle> connects[4], side_quads[2];
02883 
02884     // get three quads (shared quad & 2 end quads), hexes, and quad
02885     // connects
02886   ErrorCode result = fs_get_quads(odedge, quads, hexes, connects);
02887   if (MB_SUCCESS != result) return result;
02888   
02889     // adjust sense & rotation so they're aligned, together & wrt first
02890     // hex
02891   result = fs_check_quad_sense(hexes[0], quads[0], connects);
02892   if (MB_SUCCESS != result) return result;
02893 
02894   result = fsr_get_fourth_quad(connects, side_quads);
02895   if (MB_SUCCESS != result) {
02896     std::cout << "Can't do -FS here, two hexes must be adjacent to ring of 4 hexes." 
02897               << std::endl;
02898     return result;
02899   }
02900 
02901   Range adj_ents, outer_hexes, all_adjs;
02902 
02903     // first get the entities connected to interior 4 verts
02904   for (int i = 1; i <= 3; i++) {
02905     result = mbImpl->get_adjacencies(&connects[1][0], 4, i, false, adj_ents,
02906                                      Interface::UNION);
02907     if (MB_SUCCESS != result) return result;
02908   }
02909   
02910     // next get all entities adjacent to those; these will have their dual
02911     // entities deleted
02912   for (int i = 0; i < 3; i++) {
02913     result = mbImpl->get_adjacencies(adj_ents, i, false, all_adjs,
02914                                      Interface::UNION);
02915     if (MB_SUCCESS != result) return result;
02916   }
02917 
02918     // get the dual entities and delete them
02919   Range dual_ents, dual_hps;
02920   for (Range::iterator rit = all_adjs.begin(); rit != all_adjs.end(); rit++) {
02921     EntityHandle this_ent = get_dual_entity(*rit);
02922     dual_ents.insert(this_ent);
02923   }
02924     
02925     // before deleting dual, grab the 1- and 2-cells
02926   for (Range::iterator rit = dual_ents.begin(); rit != dual_ents.end(); rit++) {
02927     int dim = mbImpl->dimension_from_handle(*rit);
02928     if (1 == dim || 2 == dim) dual_hps.insert(get_dual_hyperplane(*rit));
02929   }
02930   
02931   result = delete_dual_entities(dual_ents);
02932   if (MB_SUCCESS != result) return result;
02933   
02934     // after deleting cells, check for empty chords & sheets, and delete those too
02935   for (Range::iterator rit = dual_hps.begin(); rit != dual_hps.end(); rit++) {
02936     Range tmp_ents;
02937     result = mbImpl->get_entities_by_handle(*rit, tmp_ents);
02938     if (MB_SUCCESS != result) return result;
02939     if (tmp_ents.empty()) {
02940       result = mbImpl->delete_entities(&(*rit), 1);
02941       if (MB_SUCCESS != result) return result;
02942     }
02943   }
02944     
02945     // before re-connecting two hexes, check for existing quad on 4th quad vertices; 
02946     // if there is a quad there, need to add explicit adjs to any adj hexes, since
02947     // by definition there'll be another quad on those vertices
02948   bool need_explicit = false;
02949   Range adj_quads;
02950   result = mbImpl->get_adjacencies(&connects[3][0], 4, 2, false, adj_quads);
02951   if (MB_MULTIPLE_ENTITIES_FOUND == result || !adj_quads.empty()) {
02952       // there's already a quad for these 4 vertices; by definition,
02953       // we'll be creating equivalent entities, so that original quad
02954       // needs explicit adj's to its bounding elements
02955     need_explicit = true;
02956     for (Range::iterator rit = adj_quads.begin(); rit != adj_quads.end(); 
02957          rit++) {
02958       Range adj_hexes;
02959       result = mbImpl->get_adjacencies(&(*rit), 1, 3, false, adj_hexes); RR;
02960       result = mbImpl->add_adjacencies(*rit, adj_hexes, false); RR;
02961     }
02962   }
02963     
02964     // re-connect the two hexes
02965   std::vector<EntityHandle> new_connect;
02966   std::copy(connects[3].begin(), connects[3].end(), std::back_inserter(new_connect));
02967   std::copy(connects[2].begin(), connects[2].end(), std::back_inserter(new_connect));
02968   result = mbImpl->set_connectivity(hexes[0], &new_connect[0], 8);
02969   if (MB_SUCCESS != result) return result;
02970 
02971   new_connect.clear();
02972   std::copy(connects[0].begin(), connects[0].end(), std::back_inserter(new_connect));
02973   std::copy(connects[3].begin(), connects[3].end(), std::back_inserter(new_connect));
02974   result = mbImpl->set_connectivity(hexes[1], &new_connect[0], 8);
02975   if (MB_SUCCESS != result) return result;
02976 
02977     // test for equiv entities from the side quads, and make explicit 
02978     // adjacencies if there are any
02979   MeshTopoUtil mtu(mbImpl);
02980   for (int j = 0; j < 2; j++) {
02981     for (int i = 0; i < 4; i++) {
02982       if (mtu.equivalent_entities(side_quads[j][i])) {
02983         result = mbImpl->add_adjacencies(side_quads[j][i], &hexes[j], 1, false);
02984         if (MB_SUCCESS != result) return result;
02985       }
02986     }
02987   }
02988   
02989     // remove hexes we want to keep
02990   adj_ents.erase(hexes[0]);
02991   adj_ents.erase(hexes[1]);
02992   
02993     // delete the other interior entities
02994   result = mbImpl->delete_entities(adj_ents);
02995   if (MB_SUCCESS != result) return result;
02996 
02997   EntityHandle new_quad;
02998   result = mbImpl->create_element(MBQUAD, &connects[3][0], 4, new_quad); RR;
02999   if (need_explicit) {
03000     result = mbImpl->add_adjacencies(new_quad, hexes, 2, false); RR;
03001   }
03002   
03003   if (debug_ap) ((Core*)mbImpl)->check_adjacencies();
03004 
03005     // now update the dual
03006   result = construct_hex_dual(hexes, 2);
03007   if (MB_SUCCESS != result) return result;
03008 
03009   return MB_SUCCESS;
03010 }
03011 
03012 ErrorCode DualTool::fsr_get_fourth_quad(std::vector<EntityHandle> *connects,
03013                                           std::vector<EntityHandle> *side_quads) 
03014 {
03015     // given the first three quad connectivities in ordered vectors, get the fourth,
03016     // where the fourth is really the 4 vertices originally shared by the 2 hexes
03017     // before the face shrink on them
03018 
03019     // vertex on 4th quad is in quad adj to other 3 verts
03020   for (int i = 0; i < 4; i++) {
03021     Range start_verts, tmp_verts, quads;
03022     for (int j = 0; j < 3; j++) start_verts.insert(connects[j][i]);
03023     ErrorCode result = mbImpl->get_adjacencies(start_verts, 2, false, quads);
03024     if (MB_SUCCESS != result) return result;
03025     assert(quads.size() == 1);
03026     result = mbImpl->get_adjacencies(&(*quads.begin()), 1, 0, false, tmp_verts); RR;
03027     tmp_verts = subtract( tmp_verts, start_verts);
03028     assert(1 == tmp_verts.size());
03029     connects[3].push_back(*tmp_verts.begin());
03030   }
03031     
03032     // now get the side quads
03033   for (int i = 0; i < 4; i++) {
03034     Range dum_ents, hexes;
03035     dum_ents.insert(connects[1][i]);
03036     dum_ents.insert(connects[1][(i+1)%4]);
03037     dum_ents.insert(connects[3][i]);
03038     ErrorCode result = mbImpl->get_adjacencies(dum_ents, 3, false, hexes);
03039     if (MB_SUCCESS != result) return result;
03040     assert(1 == hexes.size());
03041     
03042     hexes.insert(connects[0][i]);
03043     hexes.insert(connects[0][(i+1)%4]);
03044     hexes.insert(connects[3][i]);
03045     hexes.insert(connects[3][(i+1)%4]);
03046     dum_ents.clear();
03047     result = mbImpl->get_adjacencies(hexes, 2, false, dum_ents);
03048     if (MB_SUCCESS != result) return result;
03049     assert(dum_ents.size() == 1);
03050     side_quads[0].push_back(*dum_ents.begin());
03051 
03052     hexes.erase(connects[0][i]);
03053     hexes.erase(connects[0][(i+1)%4]);
03054     hexes.insert(connects[2][i]);
03055     hexes.insert(connects[2][(i+1)%4]);
03056     dum_ents.clear();
03057     result = mbImpl->get_adjacencies(hexes, 2, false, dum_ents);
03058     if (MB_SUCCESS != result) return result;
03059     side_quads[1].push_back(*dum_ents.begin());
03060   }
03061 
03062   return MB_SUCCESS;
03063 }
03064 
03065 ErrorCode DualTool::fs_get_quads(EntityHandle odedge, 
03066                                    EntityHandle *quads,
03067                                    EntityHandle *hexes,
03068                                    std::vector<EntityHandle> *connects) 
03069 {
03070     // need to get the three quads along the chord
03071   EntityHandle chord = get_dual_hyperplane(odedge);
03072   if (0 == chord) return MB_FAILURE;
03073   
03074   std::vector<EntityHandle> edges;
03075   ErrorCode result = mbImpl->get_entities_by_handle(chord, edges);
03076   if (MB_FAILURE == result) return result;
03077   
03078   std::vector<EntityHandle>::iterator vit = std::find(edges.begin(), edges.end(), odedge);
03079     // shouldn't be first or last edge on chord
03080   if (vit == edges.end() || *edges.begin() == *vit || *edges.rbegin() == *vit)
03081     return MB_FAILURE;
03082   
03083     // get quads/connectivity for first 3 quads
03084   quads[0] = get_dual_entity(*(vit-1));
03085   quads[1] = get_dual_entity(*vit);
03086   quads[2] = get_dual_entity(*(vit+1));
03087   for (int i = 0; i < 3; i++) {
03088     result = mbImpl->get_connectivity(&quads[i], 1, connects[i], true);
03089     if (MB_SUCCESS != result) return result;
03090   }
03091   
03092   Range tmph;
03093   result = mbImpl->get_adjacencies(quads, 2, 3, false, tmph);
03094   if (MB_SUCCESS != result) return result;
03095   assert(tmph.size() == 1);
03096   hexes[0] = *tmph.begin();
03097   
03098   tmph.clear();
03099   result = mbImpl->get_adjacencies(&quads[1], 2, 3, false, tmph);
03100   if (MB_SUCCESS != result) return result;
03101   assert(tmph.size() == 1);
03102   hexes[1] = *tmph.begin();
03103   
03104   return MB_SUCCESS;
03105 }
03106 
03107 ErrorCode DualTool::delete_whole_dual() 
03108 {
03109     // delete dual hyperplanes
03110   Range dual_surfs, dual_curves;
03111   ErrorCode result = this->get_dual_hyperplanes(mbImpl, 2, dual_surfs); RR;
03112   result = mbImpl->delete_entities(dual_surfs); RR;
03113   result = this->get_dual_hyperplanes(mbImpl, 1, dual_curves); RR;
03114   result = mbImpl->delete_entities(dual_curves); RR;
03115   
03116     // gather up all dual entities
03117   Range dual_ents;
03118   result = mbImpl->get_entities_by_type_and_tag(0, MBVERTEX, &isDualCellTag, NULL, 1, dual_ents,
03119                                                 Interface::UNION); RR;
03120   result = mbImpl->get_entities_by_type_and_tag(0, MBEDGE, &isDualCellTag, NULL, 1, dual_ents,
03121                                                 Interface::UNION); RR;
03122   result = mbImpl->get_entities_by_type_and_tag(0, MBPOLYGON, &isDualCellTag, NULL, 1, dual_ents,
03123                                                 Interface::UNION); RR;
03124   result = mbImpl->get_entities_by_type_and_tag(0, MBPOLYHEDRON, &isDualCellTag, NULL, 1, dual_ents,
03125                                                 Interface::UNION); RR;
03126 
03127     // delete them, in reverse order of dimension
03128   ErrorCode tmp_result;
03129   for (Range::reverse_iterator rit = dual_ents.rbegin(); rit != dual_ents.rend(); rit++) {
03130     tmp_result = mbImpl->delete_entities(&(*rit), 1);
03131     if (MB_SUCCESS != tmp_result) result = tmp_result;
03132   }
03133   RR;
03134   
03135     // delete dual-related tags
03136   if (0 != dualSurfaceTag) {
03137     tmp_result = mbImpl->tag_delete(dualSurfaceTag); 
03138     if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result;
03139   }
03140   if (0 != dualCurveTag) {
03141     tmp_result = mbImpl->tag_delete(dualCurveTag); 
03142     if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result;
03143   }
03144   if (0 != dualEntityTag) {
03145     tmp_result = mbImpl->tag_delete(dualEntityTag); 
03146     if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result;
03147   }
03148   if (0 != extraDualEntityTag) {
03149     tmp_result = mbImpl->tag_delete(extraDualEntityTag); 
03150     if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result;
03151   }
03152   if (0 != dualGraphicsPointTag) {
03153     tmp_result = mbImpl->tag_delete(dualGraphicsPointTag); 
03154     if (MB_SUCCESS != tmp_result && MB_TAG_NOT_FOUND != tmp_result) result = tmp_result;
03155   }
03156 
03157   return MB_SUCCESS;
03158 }
03159 
03160 ErrorCode DualTool::check_dual_adjs() 
03161 {
03162     // check primal-dual correspondence
03163 
03164     // get the primal entities
03165   Range pents[4];
03166   ErrorCode result = mbImpl->get_entities_by_type(0, MBHEX, pents[3]); RR;
03167   for (int i = 2; i >= 0; i--) {
03168     result = mbImpl->get_adjacencies(pents[3], 2, false, pents[2], 
03169                                      Interface::UNION); RR;
03170   }
03171   
03172     // for each primal entity of dimension pd
03173 #define PRENT(ent) CN::EntityTypeName(TYPE_FROM_HANDLE(ent)) << " " \
03174         << ID_FROM_HANDLE(ent) 
03175   ErrorCode overall_result = MB_SUCCESS;
03176   for (int pd = 1; pd <= 3; pd++) {
03177     for (Range::iterator prit = pents[pd].begin(); prit != pents[pd].end(); prit++) {
03178         // get corresponding dual entity of dimension dd = 3-pd
03179       EntityHandle dual_ent = get_dual_entity(*prit);
03180       if (0 == dual_ent) 
03181         std::cerr << "Problem getting dual entity for " << PRENT(*prit) << std::endl;
03182       
03183         // for each sub dimension sd = 0..pd-1
03184       for (int sd = 0; sd < pd; sd++) {
03185         Range R1, R2, R3;
03186           //   R1 = entities bounding primal entity of dim sd
03187         result = mbImpl->get_adjacencies(&(*prit), 1, sd, false, R1); RR;
03188         
03189           //   R2 = entities bounded by dual entity, of dim 3-sd
03190         result = mbImpl->get_adjacencies(&dual_ent, 1, 3-sd, false, R2); RR;
03191 
03192 
03193         if (R1.size() != R2.size()) {
03194           std::cerr << PRENT(*prit) << ": number of adj ents in "
03195                     << "primal/dual don't agree for dimension " << sd << "." << std::endl;
03196           overall_result = MB_FAILURE;
03197         }
03198         
03199           // for each entity in R1, get its dual and look for it in R2
03200         for (Range::iterator r1it = R1.begin(); r1it != R1.end(); r1it++) {
03201           EntityHandle tmp_dual = get_dual_entity(*r1it);
03202           if (R2.find(tmp_dual) == R2.end()) {
03203             std::cerr << PRENT(*prit) << ": adj entity " << PRENT(*r1it)
03204                       << " isn't adjacent in dual." << std::endl;
03205             overall_result = MB_FAILURE;
03206           }
03207         }
03208           // ditto for R2
03209         for (Range::iterator r2it = R2.begin(); r2it != R2.end(); r2it++) {
03210           EntityHandle tmp_prim = get_dual_entity(*r2it);
03211           if (R1.find(tmp_prim) == R1.end()) {
03212             std::cerr << PRENT(*prit) << ": adj entity " << PRENT(*r2it)
03213                       << " isn't adjacent in primal." << std::endl;
03214             overall_result = MB_FAILURE;
03215           }
03216         }
03217       }
03218     }
03219   }
03220 
03221   return overall_result;
03222 }
03223   
03224 } // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines