[MOAB-dev] r1400 - in MOAB/trunk: . tools/qvdual

tautges at mcs.anl.gov tautges at mcs.anl.gov
Fri Nov 16 09:29:37 CST 2007


Author: tautges
Date: 2007-11-16 09:29:36 -0600 (Fri, 16 Nov 2007)
New Revision: 1400

Modified:
   MOAB/trunk/DualTool.cpp
   MOAB/trunk/DualTool.hpp
   MOAB/trunk/MBCN.cpp
   MOAB/trunk/MBCN.hpp
   MOAB/trunk/MeshTopoUtil.cpp
   MOAB/trunk/MeshTopoUtil.hpp
   MOAB/trunk/tools/qvdual/DrawDual.hpp
   MOAB/trunk/tools/qvdual/uiQVDual.h
   MOAB/trunk/tools/qvdual/uiQVDual.ui
   MOAB/trunk/tools/qvdual/uiQVDual.ui.h
Log:
QVDual, DrawDual: adding ability to manually add picked 1- and 2-cells, by
filling in the string boxes in the gui

MeshTopoUtil:
- fixes to star_entities for non-manifold case
- added function opposite_entity, which for some specific parent and
child entities returns an opposite entity; functionality is obvious
for faces on hexes, nodes/edges on quads; for tris/tets, return
different-dimensional entities in some cases
- new implementation for split_entity_nonmanifold

DualTool:
- fixing bug in atomic pillow
- new implementation for face_open_collapse

MBCN: adding OppositeSide function, similar to MeshTopoUtil function
but in terms of entity types and indices




Modified: MOAB/trunk/DualTool.cpp
===================================================================
--- MOAB/trunk/DualTool.cpp	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/DualTool.cpp	2007-11-16 15:29:36 UTC (rev 1400)
@@ -1461,16 +1461,16 @@
     // get the hexes connected to the quad
   MBRange hexes;
   result = mbImpl->get_adjacencies(&quad1, 1, 3, false, hexes); RR;
+  assert(hexes.size() <= 2);
   
-    // remove any explicit adjacency from the first hex, since that'll get connected
-    // to the new outer quad; add adjacency between quad and other hex
-  result = mbImpl->remove_adjacencies(quad1, &(*hexes.begin()), 1); RR;
+    // remove any explicit adjacency from the second hex, since that'll get connected
+    // to the new quad; add adjacency between quad and first hex
   if (hexes.size() == 2) {
-    result = mbImpl->add_adjacencies(quad1, &(*hexes.rbegin()), 1, false);
-    RR;
+    result = mbImpl->remove_adjacencies(quad1, &(*hexes.rbegin()), 1); RR;
   }
+  result = mbImpl->add_adjacencies(quad1, &(*hexes.begin()), 1, false); RR;
   
-    // create the new, outer quad, and make it explicitly adjacent to 1st hex;
+    // create the new, outer quad, and make it explicitly adjacent to 2nd hex;
     // make the connectivity of this quad reversed from the original one
   std::vector<MBEntityHandle> tmp_verts;
   std::copy(verts.begin(), verts.end(), std::back_inserter(tmp_verts));
@@ -1478,6 +1478,9 @@
   std::reverse(tmp_verts.begin()+4, tmp_verts.end());
   
   result = mbImpl->create_element(MBQUAD, &tmp_verts[0], 4, quad2); RR;
+  if (hexes.size() == 2) {
+    result = mbImpl->add_adjacencies(quad2, &(*hexes.rbegin()), 1, false); RR;
+  }
   
     // now make two inner hexes; note connectivity array is flipped for the two hexes
   MBEntityHandle new_hexes[2];
@@ -1488,16 +1491,6 @@
   result = mbImpl->add_adjacencies(quad1, &new_hexes[0], 1, false); RR;
   result = mbImpl->add_adjacencies(quad2, &new_hexes[1], 1, false); RR;
 
-    // not sure for this one, should be opposite sense with quad
-  int side_no, sense, offset;
-  result = mbImpl->side_number(*hexes.begin(), quad1, side_no, sense, offset); RR;
-  if (sense == 1) {
-    result = mbImpl->add_adjacencies(quad1, &(*hexes.begin()), 1, false); RR;
-  }
-  else {
-    result = mbImpl->add_adjacencies(quad2, &(*hexes.begin()), 1, false); RR;
-  }
-
   if (debug_ap) ((MBCore*)mbImpl)->check_adjacencies();
 
     // now update the dual
@@ -1648,28 +1641,33 @@
   MeshTopoUtil mtu(mbImpl);
 
     // get the primal entities we're dealing with
-  MBEntityHandle quads[2], edge;
-  quads[0] = get_dual_entity(ocl);
-  quads[1] = get_dual_entity(ocr);
-  if (MBQUAD != mbImpl->type_from_handle(quads[0]) ||
-      MBQUAD != mbImpl->type_from_handle(quads[1]))
+  MBEntityHandle split_quads[2], split_edges[2], split_node,
+    other_edges[6], other_nodes[6];
+  MBRange hexes;
+  MBErrorCode result = foc_get_ents(ocl, ocr, split_quads, split_edges, split_node,
+                                    hexes, other_edges, other_nodes); RR;
+
+  if (MBQUAD != mbImpl->type_from_handle(split_quads[0]) ||
+      MBQUAD != mbImpl->type_from_handle(split_quads[1]))
     return MB_TYPE_OUT_OF_RANGE;
   
-  edge = mtu.common_entity(quads[0], quads[1], 1);
-  if (0 == edge) return MB_FAILURE;
-
-  MBRange hexes;
-  MBErrorCode result = mbImpl->get_adjacencies(quads, 2, 3, false, hexes, MBInterface::UNION);
+  result = foc_delete_dual(split_quads, split_edges, hexes);
   if (MB_SUCCESS != result) return result;
-  assert(4 >= hexes.size());
 
-  result = foc_delete_dual(edge, ocl, ocr, hexes);
-  if (MB_SUCCESS != result) return result;
-
   std::vector<MBEntityHandle> merge_ents;
-  result = split_pair_nonmanifold(quads, 2, merge_ents);
+  result = split_pair_nonmanifold(split_quads, split_edges, split_node, hexes,
+                                  other_edges, other_nodes, merge_ents);
   if (MB_SUCCESS != result) return result;
+
+    // put the other entities to be merged on the list
+  for (int i = 0; i < 4; i++) merge_ents.push_back(other_edges[i]);
+  if (!split_node)   
+    for (int i = 4; i < 6; i++) merge_ents.push_back(other_edges[i]);
+  for (int i = 2; i < 4; i++) merge_ents.push_back(other_nodes[i]);
+  if (!split_node)   
+    for (int i = 4; i < 6; i++) merge_ents.push_back(other_nodes[i]);
   
+  
     // now merge them
   for (std::vector<MBEntityHandle>::reverse_iterator vit = merge_ents.rbegin();
        vit != merge_ents.rend(); vit+=2) {
@@ -1689,230 +1687,298 @@
   return MB_SUCCESS;
 }
 
-MBErrorCode DualTool::split_pair_nonmanifold(MBEntityHandle *ents,
-                                             const int ents_size,
-                                             std::vector<MBEntityHandle> &merge_ents) 
+MBErrorCode DualTool::foc_get_ents(MBEntityHandle ocl, 
+                                   MBEntityHandle ocr, 
+                                   MBEntityHandle *split_quads, 
+                                   MBEntityHandle *split_edges, 
+                                   MBEntityHandle &split_node, 
+                                   MBRange &hexes, 
+                                   MBEntityHandle *other_edges, 
+                                   MBEntityHandle *other_nodes)
 {
+    // get the entities used for foc; ocl and ocr are dual 1-cells 
+    // representing quads to be split; returned from this function:
+    // quads[2] - 2 quads to be split
+    // split_edges[2] - edge(s) to be split (2nd is 0 if only one)
+    // split_node - node to be split, if any (otherwise 0)
+    // hexes - connected hexes to split_edges
+    // other_edges[0], [1] - edges in quads[0] and [1] sharing node with
+    //        one end of split_edges[0]
+    // other_edges[2], [3] - other end of split_edges[0] (or [1] if 2 
+    //        split_edges)
+    // other_edges[4], [5] - edges in quads[0], [1] opposite to split_edges[0]
+    // other_nodes[0], [1] - nodes on other_edges[0], [1] not shared with 
+    //        split_edges[0]
+    // other_nodes[2], [3] - nodes on other_edges[2], [3] not shared with 
+    //        split_edges[0] (if 2 split_edges, there's only 1 opposite node
+    //        in each split quad)
+    // (for diagram, see Tim's notes from 11/12/07)
 
-    // if there's a bdy in the star around the shared edge(s), get the quads on that
-    // bdy so we know which edges to merge after the split-nonmanifold
-  MeshTopoUtil mtu(mbImpl);
-  MBRange shared_ents;
+  split_quads[0] = get_dual_entity(ocl);
+  split_quads[1] = get_dual_entity(ocr);
+  if (MBQUAD != mbImpl->type_from_handle(split_quads[0]) ||
+      MBQUAD != mbImpl->type_from_handle(split_quads[1]))
+    return MB_TYPE_OUT_OF_RANGE;
 
-  int star_dim = mbImpl->dimension_from_handle(ents[0])-1;
-  MBErrorCode result = mbImpl->get_adjacencies(ents, ents_size,
-                                               star_dim, false, shared_ents);
+  MBRange common_edges;
+  MBErrorCode result = mbImpl->get_adjacencies(split_quads, 2, 1, false, 
+                                               common_edges);
   if (MB_SUCCESS != result) return result;
-  else if (shared_ents.empty()) return MB_FAILURE;
   
-  MBRange bdy_ents[3];
-  int i;
-  MBRange::iterator rit;
-  for (rit = shared_ents.begin(), i = 0; i < 3; i++, rit++) {
-    std::vector<MBEntityHandle> star_ents;
-    bool on_bdy;
-    result = mtu.star_entities(*rit, star_ents, on_bdy);
-    if (MB_SUCCESS != result) return result;
-    if (on_bdy) {
-      bdy_ents[i].insert(*star_ents.begin());
-      bdy_ents[i].insert(*star_ents.rbegin());
+  if (common_edges.empty()) return MB_FAILURE;
+  for (unsigned int i = 0; i < common_edges.size(); i++) 
+    split_edges[i] = common_edges[i];
+
+  MeshTopoUtil mtu(mbImpl);
+
+  if (common_edges.size() > 1) {
+    split_node = mtu.common_entity(split_edges[0], split_edges[1], 0);
+    if (0 == split_node) return MB_FAILURE;
+    for (int i = 0; i < 2; i++) {
+      result = mtu.opposite_entity(split_quads[i], 
+                                   split_edges[1-i], other_edges[i]); RR;
+      result = mtu.opposite_entity(split_quads[i], 
+                                   split_edges[i], other_edges[2+i]); RR;
+      result = mtu.opposite_entity(split_quads[i], split_node,
+                                   other_nodes[i]); RR;
     }
   }
-  
-    // split manifold each of the entities
-  std::vector<MBEntityHandle> new_ents(ents_size);
-  result = mtu.split_entities_manifold(ents, ents_size, &new_ents[0], NULL);
-  if (MB_SUCCESS != result) return result;
-  
-    // split non-manifold the shared entities between them
-  MBRange new_shared_ents;
-  for (rit = shared_ents.begin(), i = 0; rit != shared_ents.end(); rit++, i++) {
-    new_shared_ents.clear();
-    result = mtu.split_entity_nonmanifold(*rit, new_shared_ents);
+  else {
+    split_edges[1] = 0;
+    split_node = 0;
+    const MBEntityHandle *connect;
+    int num_connect;
+    result = mbImpl->get_connectivity(split_edges[0], connect, num_connect);
     if (MB_SUCCESS != result) return result;
-
-    if (new_shared_ents.size() > 2) {
-      std::cerr << "Can't do split_pair_nonmanifold, too many new d-1 entities." << std::endl;
-      return MB_FAILURE;
-    }
-    else if (new_shared_ents.size() == 2) {
-        // need to merge 2 of the entities together, don't know which ones yet but they're adjacent
-        // to bdy_ents and are either in new_shared_ents or are the original *rit
-      assert(!bdy_ents[i].empty());
-      MBRange dum_ents;
-      result = mbImpl->get_adjacencies(bdy_ents[i], star_dim, false, dum_ents, MBInterface::UNION);
+    
+    for (int i = 0; i < 2; i++) {
+      MBRange tmp_range1, tmp_range2;
+      tmp_range1.insert(connect[i]);
+      tmp_range1.insert(split_quads[i]);
+      result = mbImpl->get_adjacencies(tmp_range1, 1, false, tmp_range2);
       if (MB_SUCCESS != result) return result;
-      new_shared_ents.insert(*rit);
-      dum_ents = dum_ents.intersect(new_shared_ents);
-      assert(2 == dum_ents.size());
-
-        // merge them together; will keep lower handle 'cuz they're in a range
-      result = mbImpl->merge_entities(*dum_ents.begin(), *dum_ents.rbegin(), false, true);
-      if (MB_SUCCESS != result) return result;
+      tmp_range2.erase(split_edges[0]);
+      assert(tmp_range2.size() == 1);
+      other_edges[i] = *tmp_range2.begin();
+      result = mtu.opposite_entity(other_edges[i], connect[i],
+                                   other_nodes[i]); RR;
+      result = mtu.opposite_entity(split_quads[i], split_edges[0],
+                                   other_edges[4+i]); RR;
     }
-    else {
-      assert(1 == new_shared_ents.size());
-    }
   }
 
-  if (shared_ents.size() != 1 && star_dim > 0) {
-  
-      // need to split-nonmanifold vertices too
-      // get which vertices they are
-    MBRange shared_verts;
-    rit = shared_ents.begin();
-    MBRange::iterator rit2 = rit; rit2++;
-    for (; rit != shared_ents.end(); rit++, rit2++) {
-      if (rit2 == shared_ents.end()) rit2 = shared_ents.begin();
-      MBEntityHandle shared_vert = mtu.common_entity(*rit, *rit2, 0);
-      if (0 != shared_vert) shared_verts.insert(shared_vert);
-    }
-      // now split them
-    assert(shared_verts.size() == shared_ents.size()-1);
-    for (rit = shared_verts.begin(); rit != shared_verts.end(); rit++) {
-      MBRange dum_ents;
-      result = mtu.split_entity_nonmanifold(*rit, dum_ents);
-      if (MB_SUCCESS != result) return result;
-        //assert(1 == dum_ents.size());
+  result = mbImpl->get_adjacencies(split_quads, 2, 3, false, hexes, MBInterface::UNION);
+  if (MB_SUCCESS != result) return result;
+  assert(4 >= hexes.size());
 
-        // let's put new vertex in a sane position, too; get the bridge-adjacent vertices
-        // across edges
-      MBEntityHandle this_vert = *dum_ents.begin();
-      dum_ents.clear();
-      result = mtu.get_bridge_adjacencies(this_vert, 1, 0, dum_ents);
-      if (MB_SUCCESS != result) return result;
-        // add the original of the split vertex too
-      dum_ents.insert(*rit);
-      double avg_pos[3];
-      result = mtu.get_average_position(dum_ents, avg_pos);
-      if (MB_SUCCESS != result) return result;
-      result = mbImpl->set_coords(&this_vert, 1, avg_pos);
-      if (MB_SUCCESS != result) return result;
-    }
-  }
+  return MB_SUCCESS;
+}
+
+MBErrorCode DualTool::split_pair_nonmanifold(MBEntityHandle *split_quads,
+                                             MBEntityHandle *split_edges,
+                                             MBEntityHandle split_node,
+                                             MBRange hexes,
+                                             MBEntityHandle *other_edges,
+                                             MBEntityHandle *other_nodes,
+                                             std::vector<MBEntityHandle> &merge_ents) 
+{
+
+    // if there's a bdy in the star around the shared edge(s), get the quads on that
+    // bdy so we know which edges to merge after the split-nonmanifold
+  MeshTopoUtil mtu(mbImpl);
+  MBErrorCode result;
+
+    // get star entities around edges, separated into halves
+  std::vector<MBEntityHandle> star_dp1[2], star_dp2[2];
+  result = foc_get_stars(split_quads, split_edges, star_dp1, star_dp2); RR;
   
-    // now need to build vector of entity pairs to merge; this is computed by finding
-    // the two ents from ents, new_ents which have common (d-1)-dimensional entities which
-    // are in shared_ents, and similarly for those adjacent to entities in new_shared_ents
+    // split manifold each of the split_quads, and put the results on the merge list
+  MBEntityHandle new_quads[2];
+  result = mtu.split_entities_manifold(split_quads, 2, new_quads, NULL); RR;
+  for (int i = 0; i < 2; i++) merge_ents.push_back(split_quads[i]);
+  for (int i = 0; i < 2; i++) merge_ents.push_back(new_quads[i]);
   
-    // group all ents, new_ents into a range, then intersect that with d-dimensional
-    // entities adjacent to one of the original (d-1)-dimensional shared_ents; those will be 
-    // the first two mergeable d-dimensional entities
-  MBRange dum_ents;
-  dum_ents.insert(ents[0]); dum_ents.insert(ents[1]); 
-  dum_ents.insert(new_ents[0]); dum_ents.insert(new_ents[1]); 
-  MBRange other_dum_ents = dum_ents;
-  result = mbImpl->get_adjacencies(&(*shared_ents.begin()), 1, star_dim+1, false, dum_ents);
-  if (MB_SUCCESS != result) return result;
-  assert(2 == dum_ents.size());
-  other_dum_ents = other_dum_ents.subtract(dum_ents);
-  assert(2 == other_dum_ents.size());
-  merge_ents.push_back(*dum_ents.begin());
-  merge_ents.push_back(*dum_ents.rbegin());
-  if (0 != mtu.common_entity(merge_ents[0], *other_dum_ents.begin(), star_dim)) {
-    merge_ents.push_back(*other_dum_ents.begin());
-    merge_ents.push_back(*other_dum_ents.rbegin());
-  }
-  else {
-    merge_ents.push_back(*other_dum_ents.rbegin());
-    merge_ents.push_back(*other_dum_ents.begin());
-  }
-    
-    // order shared_ents_vec and new_shared_ents_vec such that they're ready for merging
-    // get all the non-shared edges 
-  MBRange unshared_edges;
-  result = mbImpl->get_adjacencies(&merge_ents[0], 2, 1, false, unshared_edges, 
-                                   MBInterface::UNION);
-  if (MB_SUCCESS != result) return result;
-  shared_ents.clear();
-  result = mbImpl->get_adjacencies(&merge_ents[0], 2, 1, false, shared_ents);
-  if (MB_SUCCESS != result) return result;
-  unshared_edges = unshared_edges.subtract(shared_ents);
-  shared_ents.clear();
-  result = mbImpl->get_adjacencies(&merge_ents[2], 2, 1, false, shared_ents);
-  if (MB_SUCCESS != result) return result;
-  unshared_edges = unshared_edges.subtract(shared_ents);
-  assert(2 <= unshared_edges.size());
+
+    // if we're splitting 2 edges, there might be other edges that have the split
+    // node; also need to know which side they're on
+  MBRange addl_ents[2];
+  result = foc_get_addl_ents(star_dp1, star_dp2, split_node, addl_ents); RR;
+
+    // now split the edges; just add the star ents to addl_ents to pass into
+    // split_nonmanifold
+  for (int i = 0; i < 2; i++) 
+    std::copy(star_dp1[i].begin(), star_dp1[i].end(), mb_range_inserter(addl_ents[i]));
   
-  if (2 == unshared_edges.size()) {
-      // only 2, they must be the ones to merge, and no vertices
-    merge_ents.push_back(*unshared_edges.begin());
-    merge_ents.push_back(*unshared_edges.rbegin());
-    return MB_SUCCESS;
-  }
+  MBEntityHandle new_entity;
+  result = mtu.split_entity_nonmanifold(split_edges[0], addl_ents[0], addl_ents[1],
+                                        new_entity); RR;
+  addl_ents[0].insert(split_edges[0]); addl_ents[1].insert(new_entity);
 
-    // otherwise, first ones are adjacent to either shared vertex
-  int unshared_size = unshared_edges.size();
-  dum_ents.clear();
-  MBRange end_verts, all_edges;
-  dum_ents.insert(merge_ents[0]);
-  dum_ents.insert(merge_ents[3]);
-  result = mbImpl->get_adjacencies(dum_ents, 0, false, end_verts);
-  if (MB_SUCCESS != result) return result;
-  assert(2 == end_verts.size());
+  if (split_edges[1]) {
+    result = mtu.split_entity_nonmanifold(split_edges[1], addl_ents[0], addl_ents[1],
+                                          new_entity); RR;
+    addl_ents[0].insert(split_edges[0]); addl_ents[1].insert(new_entity);
   
-  for (rit = end_verts.begin(); rit != end_verts.end(); rit++) {
-      // intersect the unshared edges with the edges adjacent to this vertex
-    dum_ents = unshared_edges;
-    result = mbImpl->get_adjacencies(&(*rit), 1, 1, false, dum_ents);
-    if (MB_SUCCESS != result) return result;
-      // by definition, there should only be 2, and they're to be merged
-    assert(2 == dum_ents.size());
-    merge_ents.push_back(*dum_ents.begin());
-    merge_ents.push_back(*dum_ents.rbegin());
-      // remove these from unshared_edges, since they don't need to be 
-      // considered any more
-    unshared_edges = unshared_edges.subtract(dum_ents);
+      // now split the node too
+    result = mtu.split_entity_nonmanifold(split_node, addl_ents[0], addl_ents[1],
+                                          new_entity); RR;
   }
   
-    // if we have any unshared edges left, they should be merged too
-  if (!unshared_edges.empty()) {
-    assert(2 == unshared_edges.size());
-    merge_ents.push_back(*unshared_edges.begin());
-    merge_ents.push_back(*unshared_edges.rbegin());
+  return MB_SUCCESS;
+}
+
+MBErrorCode DualTool::foc_get_addl_ents(std::vector<MBEntityHandle> *star_dp1, 
+                                        std::vector<MBEntityHandle> *star_dp2, 
+                                        MBEntityHandle split_node,
+                                        MBRange *addl_ents) 
+{
+    // if we're splitting 2 edges, there might be other edges that have the split
+    // node; also need to know which side they're on
+
+    // algorithm:
+    // - start with star entities on search list
+    // - while (search list not empty):
+    // . take face off search list, put on result list
+    // . get all edge-adj faces also adj to split node
+    // . for each of these, if face is not on result list, put on search list
+    // - for each entity on result list:
+    // . get all entities also adj to split node & put on result list
+
+  MBRange node_faces;
+  MeshTopoUtil mtu(mbImpl);
+  MBErrorCode result = mbImpl->get_adjacencies(&split_node, 1, 2, false, node_faces); RR;
+  MBRange::iterator rit;
+
+  for (int i = 0; i < 2; i++) {
+    MBRange slist, rlist, tmp_list;
+    std::copy(star_dp1[i].begin(), star_dp1[i].end(), mb_range_inserter(slist));
+    while (!slist.empty()) {
+      MBEntityHandle this_ent = slist.pop_front();
+      rlist.insert(this_ent);
+      tmp_list.clear();
+      result = mtu.get_bridge_adjacencies(this_ent, 1, 2, tmp_list); RR;
+      tmp_list = tmp_list.intersect(node_faces);
+      for (rit = tmp_list.begin(); rit != tmp_list.end(); rit++)
+        if (rlist.find(*rit) == rlist.end()) slist.insert(*rit);
+    }
+    MBEntityHandle tmp_ents[2];
+    tmp_ents[0] = split_node;
+    MBRange rlist2;
+    for (rit = rlist.begin(); rit != rlist.end(); rit++) {
+      tmp_list.clear();
+      tmp_ents[1] = *rit;
+      result = mbImpl->get_adjacencies(tmp_ents, 2, 1, false, tmp_list); RR;
+      rlist2.merge(tmp_list);
+      tmp_list.clear();
+      result = mbImpl->get_adjacencies(tmp_ents, 2, 3, false, tmp_list); RR;
+      rlist2.merge(tmp_list);
+    }
+
+    for (rit = rlist.begin(); rit != rlist.end(); rit++) 
+      if (std::find(star_dp1[i].begin(), star_dp1[i].end(), *rit) ==
+          star_dp1[i].end()) addl_ents[i].insert(*rit);
+    addl_ents[i].merge(rlist2);
   }
   
-    // now get the vertex or vertices which must also be merged
-  MBEntityHandle ent1 = *merge_ents.rbegin(),
-    ent2 = *(merge_ents.rbegin()+1);
-  
-  for (int i = 0; i < (unshared_size/2)-1; i++) {
-    MBEntityHandle shared_ent = mtu.common_entity(merge_ents[4+2*i], ent1, 0);
-    if (0 == shared_ent) shared_ent = mtu.common_entity(merge_ents[4+2*i], ent2, 0);
-    assert(0 != shared_ent);
-    merge_ents.push_back(shared_ent);
+  return MB_SUCCESS;
+}
 
-    shared_ent = mtu.common_entity(merge_ents[4+2*i+1], ent1, 0);
-    if (0 == shared_ent || shared_ent == *merge_ents.rbegin()) 
-      shared_ent = mtu.common_entity(merge_ents[4+2*i+1], ent2, 0);
-    assert(0 != shared_ent);
-    merge_ents.push_back(shared_ent);
+MBErrorCode DualTool::foc_get_stars(MBEntityHandle *split_quads,
+                                    MBEntityHandle *split_edges,
+                                    std::vector<MBEntityHandle> *star_dp1,
+                                    std::vector<MBEntityHandle> *star_dp2) 
+{
+
+  bool on_bdy;
+  MBErrorCode result;
+  MeshTopoUtil mtu(mbImpl);
+  for (int i = 0; i < 2; i++) {
+      // only do 2nd iteration if we have a 2nd edge
+    if (1 == i && !split_edges[1]) continue;
+
+      // get the star around the split_edge
+    std::vector<MBEntityHandle> star_tmp[2], split_qstar[2], split_hstar[2];
+    result = mtu.star_entities(split_edges[i], star_tmp[0], on_bdy, 0,
+                               &star_tmp[1]); RR;
+    std::vector<MBEntityHandle>::iterator fit, hit;
+    bool inside = false;
+
+      // separate the star into halves; store faces in split_qstar[0],[1], and
+      // the hexes in split_hstar[0],[1]
+    for (fit = star_tmp[0].begin(), hit = star_tmp[1].begin(); fit != star_tmp[0].end();
+         fit++, hit++) {
+      if (!inside && (*fit == split_quads[0] || *fit == split_quads[1]))
+        inside = true;
+      if (inside) split_qstar[0].push_back(*fit);
+      else split_qstar[1].push_back(*fit);
+        // only save hex if we're not on the end with a bdy
+      if (!on_bdy || fit != star_tmp[0].end()) {
+        if (inside) split_hstar[0].push_back(*hit);
+        else split_hstar[1].push_back(*hit);
+      }
+      if (inside && *fit != *split_qstar[0].begin() &&
+          (*fit == split_quads[0] || *fit == split_quads[1]))
+        inside = false;
+    }
+
+      // if we're on edge 1, just put the halves into the result vectors
+    if (0 == i) {
+      star_dp1[0].swap(split_qstar[0]); star_dp1[1].swap(split_qstar[1]);
+      star_dp2[0].swap(split_hstar[0]); star_dp2[1].swap(split_hstar[1]);
+    }
+      // else, align the star halves then add them to the star_dpx lists
+    else {
+        // if the lists are aligned, the hex next to the first face on star_dp1[0]
+        // should also be next to that face on split_qstar, either the front or
+        // the back depending whether that face is 1st or last on split_qstar[0]
+      MBEntityHandle hex1 = *star_dp2[0].begin();
+      MBEntityHandle hex2 = 0;
+      if (*split_qstar[0].begin() == *star_dp1[0].begin())
+        hex2 = *split_hstar[0].begin();
+      else if (*split_qstar[0].rbegin() == *star_dp1[0].begin())
+        hex2 = *split_hstar[0].rbegin();
+      if (hex1 == hex2) {
+        for (int i = 0; i < 2; i++)
+          std::copy(split_qstar[i].begin(), split_qstar[i].end(), 
+                    std::back_inserter(star_dp1[i])),
+            std::copy(split_hstar[i].begin(), split_hstar[i].end(), 
+                      std::back_inserter(star_dp2[i]));
+      }
+      else {
+        for (int i = 0; i < 2; i++)
+          std::copy(split_qstar[(i+1)%2].begin(), split_qstar[(i+1)%2].end(), 
+                    std::back_inserter(star_dp1[i])),
+            std::copy(split_hstar[(i+1)%2].begin(), split_hstar[(i+1)%2].end(), 
+                      std::back_inserter(star_dp2[i]));
+      }
+    }
   }
-  
-  
+
   return MB_SUCCESS;
 }
 
-MBErrorCode DualTool::foc_delete_dual(MBEntityHandle edge,
-                                      MBEntityHandle ocl,
-                                      MBEntityHandle ocr,
+MBErrorCode DualTool::foc_delete_dual(MBEntityHandle *split_quads,
+                                      MBEntityHandle *split_edges,
                                       MBRange &hexes) 
 {
     // special delete dual procedure, because in some cases we need to delete
     // a sheet too since it'll get merged into another
 
     // figure out whether we'll need to delete a sheet
-  MBEntityHandle sheet = get_dual_hyperplane(get_dual_entity(edge));
-  MBEntityHandle chordl = get_dual_hyperplane(ocl);
-  MBEntityHandle chordr = get_dual_hyperplane(ocr);
-  assert(0 != sheet && 0 != chordl && 0 != chordr);
+  MBEntityHandle sheet1, sheet2 = 0;
+  sheet1 = get_dual_hyperplane(get_dual_entity(split_edges[0]));
+  if (split_edges[1]) sheet1 = get_dual_hyperplane(get_dual_entity(split_edges[1]));
+  MBEntityHandle chordl = get_dual_hyperplane(get_dual_entity(split_quads[0]));
+  MBEntityHandle chordr = get_dual_hyperplane(get_dual_entity(split_quads[1]));
+  assert(0 != sheet1 && 0 != chordl && 0 != chordr);
   MBRange parentsl, parentsr;
   MBErrorCode result = mbImpl->get_parent_meshsets(chordl, parentsl);
   if (MB_SUCCESS != result) return result;
   result = mbImpl->get_parent_meshsets(chordr, parentsr);
   if (MB_SUCCESS != result) return result;
-  parentsl.erase(sheet);
-  parentsr.erase(sheet);
+  parentsl.erase(sheet1);
+  parentsr.erase(sheet1);
+  if (sheet2) parentsl.erase(sheet1), parentsr.erase(sheet1);
 
     // before deciding which one to delete, collect the other cells which must
     // be deleted, and all the chords/sheets they're on
@@ -1991,80 +2057,6 @@
   return MB_SUCCESS;
 }
 
-/*
-MBErrorCode DualTool::foc_get_merge_ents(MBEntityHandle *quads, MBEntityHandle *new_quads, 
-                                         MBRange &shared_edges, MBRange &new_shared_edges,
-                                         std::vector<MBEntityHandle> &merge_ents)
-{
-  MeshTopoUtil mtu(mbImpl);
-
-    // get the two common vertices
-  MBRange common_verts;
-  MBErrorCode result = mbImpl->get_adjacencies(quads, 2, 0, false, common_verts);
-  if (MB_SUCCESS != result) return result;
-  result = mbImpl->get_adjacencies(new_quads, 2, 0, false, common_verts);
-  if (MB_SUCCESS != result) return result;
-  assert(2 == common_verts.size());
-
-    // get the vertices to merge; each vertex pair is bridge-adjacent (across edges)
-    // to one of the vertices of our edge, and is not the other vertex of our edge
-  const MBEntityHandle *connect;
-  int num_connect;
-  result = mbImpl->get_connectivity(*shared_edges.begin(), connect, num_connect);
-  if (MB_SUCCESS != result) return result;
-  
-  for (int i = 0; i < 2; i++) {
-    MBRange tmp_verts;
-    result = mtu.get_bridge_adjacencies(connect[i], 1, 0, tmp_verts);
-    if (MB_SUCCESS != result) return result;    
-    tmp_verts = tmp_verts.intersect(all_verts);
-
-      // bridge adjacencies don't include connect[i], but will include the other
-    tmp_verts.erase(connect[(i+1)%2]);
-    assert(2 == tmp_verts.size());
-    
-    merge_ents.push_back(*tmp_verts.begin());
-    merge_ents.push_back(*tmp_verts.rbegin());
-  }
-
-    // now edges
-  MBRange all_edges, saved_edges;
-  result = mbImpl->get_adjacencies(quads, 2, 1, false, all_edges, MBInterface::UNION);
-  if (MB_SUCCESS != result) return result;
-  result = mbImpl->get_adjacencies(new_quads, 2, 1, false, all_edges, MBInterface::UNION);
-  if (MB_SUCCESS != result) return result;
-  all_edges.erase(*shared_edges.begin());
-  all_edges.erase(new_edge);
-  assert(6 == all_edges.size());
-
-    // first the ones connected to each vertex of our edge but not edge or new_edge
-  for (int i = 0; i < 2; i++) {
-    MBRange tmp_edges;
-    result = mbImpl->get_adjacencies(&connect[i], 1, 1, false, tmp_edges);
-    if (MB_SUCCESS != result) return result;
-    tmp_edges = tmp_edges.intersect(all_edges);
-    assert(2 == tmp_edges.size());
-    merge_ents.push_back(*tmp_edges.begin());
-    merge_ents.push_back(*tmp_edges.rbegin());
-    saved_edges.merge(tmp_edges);
-  }
-    // last two are the ones left over, not counting edge and new_edge
-  all_edges = all_edges.subtract(saved_edges);
-  assert(2 == all_edges.size());
-  merge_ents.push_back(*all_edges.begin());
-  merge_ents.push_back(*all_edges.rbegin());
-  
-    // now faces; already know which ones, because of code we used before to
-    // store quads and new_quads
-  merge_ents.push_back(quads[0]);
-  merge_ents.push_back(new_quads[0]);
-  merge_ents.push_back(quads[1]);
-  merge_ents.push_back(new_quads[1]);
-  
-  return MB_SUCCESS;
-}
-*/
-
 //! returns true if all vertices are dual to hexes (not faces)
 bool DualTool::is_blind(const MBEntityHandle chord_or_sheet) 
 {

Modified: MOAB/trunk/DualTool.hpp
===================================================================
--- MOAB/trunk/DualTool.hpp	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/DualTool.hpp	2007-11-16 15:29:36 UTC (rev 1400)
@@ -182,6 +182,17 @@
   
     //! effect a face open-collapse operation
   MBErrorCode face_open_collapse(MBEntityHandle ocl, MBEntityHandle ocr);
+
+    //! given the two 1-cells involved in the foc, get entities associated with
+    //! the quads being opened/collapsed; see implementation for more details
+  MBErrorCode foc_get_ents(MBEntityHandle ocl, 
+                           MBEntityHandle ocr, 
+                           MBEntityHandle *quads, 
+                           MBEntityHandle *split_edges, 
+                           MBEntityHandle &split_node, 
+                           MBRange &hexes, 
+                           MBEntityHandle *other_edges, 
+                           MBEntityHandle *other_nodes);
   
     //! given a 1-cell and a chord, return the neighboring vertices on the
     //! chord, in the same order as the 1-cell's vertices
@@ -315,17 +326,34 @@
 
     //! function for deleting dual prior to foc operation; special because in
     //! many cases need to delete a sheet in preparation for merging onto another
-  MBErrorCode foc_delete_dual(MBEntityHandle edge,
-                              MBEntityHandle ocl,
-                              MBEntityHandle ocr,
+  MBErrorCode foc_delete_dual(MBEntityHandle *split_quads,
+                              MBEntityHandle *split_edges,
                               MBRange &hexes);
 
-    //! split a pair of entities such that the new pair shares as many (d-1)-
-    //! and (d-2)-dimensional entities as the original pair did
-  MBErrorCode split_pair_nonmanifold(MBEntityHandle *ents,
-                                     const int ents_size,
+    //! split a pair of quads and the edge(s) shared by them
+  MBErrorCode split_pair_nonmanifold(MBEntityHandle *split_quads,
+                                     MBEntityHandle *split_edges,
+                                     MBEntityHandle split_node,
+                                     MBRange hexes,
+                                     MBEntityHandle *other_edges,
+                                     MBEntityHandle *other_nodes,
                                      std::vector<MBEntityHandle> &merge_ents);
   
+    //! for foc's splitting two shared edges, there might be additional entities
+    //! connected to the split node that also have to be updated
+  MBErrorCode foc_get_addl_ents(std::vector<MBEntityHandle> *star_dp1, 
+                                std::vector<MBEntityHandle> *star_dp2, 
+                                MBEntityHandle split_node,
+                                MBRange *addl_ents);
+  
+    //! given the split quads and edges, get the face and hex stars around the
+    //! edge(s), separated into halves, each of which goes with the new or old entities
+    //! after the split
+  MBErrorCode foc_get_stars(MBEntityHandle *split_quads,
+                            MBEntityHandle *split_edges,
+                            std::vector<MBEntityHandle> *star_dp1,
+                            std::vector<MBEntityHandle> *star_dp2);
+  
     //! private copy of interface *
   MBInterface *mbImpl;
 

Modified: MOAB/trunk/MBCN.cpp
===================================================================
--- MOAB/trunk/MBCN.cpp	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/MBCN.cpp	2007-11-16 15:29:36 UTC (rev 1400)
@@ -286,6 +286,80 @@
   return 0;
 }
 
+  //! return the dimension and index of the opposite side, given parent entity type and child 
+  //! dimension and index.  This function is only defined for certain types of parent/child types:
+  //! (Parent, Child dim->Opposite dim): 
+  //!  (Tri, 1->0), (Tri, 0->1), (Quad, 1->1), (Quad, 0->0), 
+  //!  (Tet, 2->0), (Tet, 1->1), (Tet, 0->2),
+  //!  (Hex, 2->2), (Hex, 1->1)(diagonally across element), (Hex, 0->0) (diagonally across element)
+  //! All other parent types and child dimensions return an error.
+  //!
+  //! \param parent_type The type of parent element
+  //! \param child_type The type of child element
+  //! \param child_index The index of the child element
+  //! \param opposite_index The index of the opposite element
+  //! \return status Returns 0 if successful, -1 if not
+int MBCN::OppositeSide(const MBEntityType parent_type,
+                       const int child_index,
+                       const int child_dim,
+                       int &opposite_index,
+                       int &opposite_dim) 
+{
+  switch (parent_type) {
+    case MBTRI:
+      switch (child_dim) {
+        case 0:
+          opposite_dim = 1;
+          opposite_index = (child_index+1)%3;
+          break;
+        case 1:
+          opposite_dim = 0;
+          opposite_index = (child_index+2)%3;
+          break;
+        default:
+          return -1;
+      }
+      break;
+
+    case MBQUAD:
+      switch (child_dim) {
+        case 0:
+        case 1:
+          opposite_dim = child_dim;
+          opposite_index = (child_index+2)%4;
+          break;
+        default:
+          return -1;
+      }
+      break;
+      
+    case MBTET:
+      switch (child_dim) {
+        case 0:
+          opposite_dim = 2;
+          opposite_index = (child_index+2)%3 + 2*(child_index/3);
+          break;
+        case 1:
+          opposite_dim = 1;
+          opposite_index = 3 + (child_index + 5)%3;
+          break;
+        case 2:
+          opposite_dim = 0;
+          opposite_index = (child_index+2)%3 + child_index/3;
+          break;
+        default:
+          return -1;
+      }
+      break;
+    case MBHEX:
+      
+    default:
+      return -1;
+  }
+  
+  return 0;
+}
+
 template <typename T> 
 static inline bool connectivity_match( const T* conn1_i,
                                        const T* conn2_i,

Modified: MOAB/trunk/MBCN.hpp
===================================================================
--- MOAB/trunk/MBCN.hpp	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/MBCN.hpp	2007-11-16 15:29:36 UTC (rev 1400)
@@ -222,6 +222,25 @@
                         const int child_dim,
                         int &side_number, int &sense, int &offset);
 
+  //! return the dimension and index of the opposite side, given parent entity type and child 
+  //! dimension and index.  This function is only defined for certain types of parent/child types:
+  //! (Parent, Child dim->Opposite dim): 
+  //!  (Tri, 1->0), (Tri, 0->1), (Quad, 1->1), (Quad, 0->0), 
+  //!  (Tet, 2->0), (Tet, 1->1), (Tet, 0->2),
+  //!  (Hex, 2->2), (Hex, 1->1)(diagonally across element), (Hex, 0->0) (diagonally across element)
+  //! All other parent types and child dimensions return an error.
+  //!
+  //! \param parent_type The type of parent element
+  //! \param child_type The type of child element
+  //! \param child_index The index of the child element
+  //! \param opposite_index The index of the opposite element
+  //! \return status Returns 0 if successful, -1 if not
+  static int OppositeSide(const MBEntityType parent_type,
+                          const int child_index,
+                          const int child_dim,
+                          int &opposite_index,
+                          int &opposite_dim);
+
   //! given two connectivity arrays, determine whether or not they represent the same entity.
   //! \param conn1 Connectivity array of first entity
   //! \param conn2 Connectivity array of second entity

Modified: MOAB/trunk/MeshTopoUtil.cpp
===================================================================
--- MOAB/trunk/MeshTopoUtil.cpp	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/MeshTopoUtil.cpp	2007-11-16 15:29:36 UTC (rev 1400)
@@ -25,6 +25,8 @@
 
 #include <assert.h>
 
+#define RR {if (MB_SUCCESS != result) return result;}
+
     //! generate all the AEntities bounding the vertices
 MBErrorCode MeshTopoUtil::construct_aentities(const MBRange &vertices) 
 {
@@ -96,32 +98,41 @@
 
   // given an entity, find the entities of next higher dimension around
   // that entity, ordered by connection through next higher dimension entities; 
-  // if any of the star entities is in only entity of next higher dimension, 
+  // if any of the star entities is in only one entity of next higher dimension, 
   // on_boundary is returned true
 MBErrorCode MeshTopoUtil::star_entities(const MBEntityHandle star_center,
                                         std::vector<MBEntityHandle> &star_entities,
                                         bool &bdy_entity,
                                         const MBEntityHandle starting_star_entity,
-                                        std::vector<MBEntityHandle> *star_entities_dp1,
-                                        MBRange *star_candidates_dp1)
+                                        std::vector<MBEntityHandle> *star_entities_dp2,
+                                        MBRange *star_candidates_dp2)
 {
     // now start the traversal
   bdy_entity = false;
-  MBEntityHandle last_entity = starting_star_entity, last_dp1 = 0, next_entity, next_dp1;
-  std::vector<MBEntityHandle> star_dp1;
+  MBEntityHandle last_entity = starting_star_entity, last_dp2 = 0, next_entity, next_dp2;
+  std::vector<MBEntityHandle> star_dp2;
+  MBErrorCode result;
+  int center_dim = mbImpl->dimension_from_handle(star_center);
+  
+  MBRange tmp_candidates_dp2;
+  if (NULL != star_candidates_dp2) tmp_candidates_dp2 = *star_candidates_dp2;
+  else {
+    result = mbImpl->get_adjacencies(&star_center, 1, 
+                                     center_dim+2,
+                                     false, tmp_candidates_dp2);
+    if (MB_SUCCESS != result) return result;
+  }
 
   do {
       // get the next star entity
-    MBErrorCode result = star_next_entity(star_center, last_entity, last_dp1,
-                                          star_candidates_dp1,
-                                          next_entity, next_dp1);
+    result = star_next_entity(star_center, last_entity, last_dp2,
+                              &tmp_candidates_dp2,
+                              next_entity, next_dp2);
     if (MB_SUCCESS != result) return result;
-    
+
       // special case: if starting_star_entity isn't connected to any entities of next
       // higher dimension, it's the only entity in the star; put it on the list and return
-    if (star_entities.empty() && next_entity == 0 && next_dp1 == 0 &&
-        (star_candidates_dp1 == NULL || 
-         star_candidates_dp1->find(last_entity) != star_candidates_dp1->end())) {
+    if (star_entities.empty() && next_entity == 0 && next_dp2 == 0) {
       star_entities.push_back(last_entity);
       bdy_entity = true;
       return MB_SUCCESS;
@@ -130,41 +141,48 @@
       // if we're at a bdy and bdy_entity hasn't been set yet, we're at the
       // first bdy; reverse the lists and start traversing in the other direction; but,
       // pop the last star entity off the list and find it again, so that we properly
-      // check for next_dp1
-    if (0 == next_dp1 && !bdy_entity) {
+      // check for next_dp2
+    if (0 == next_dp2 && !bdy_entity) {
       star_entities.push_back(next_entity);
       bdy_entity = true;
       std::reverse(star_entities.begin(), star_entities.end());
       star_entities.pop_back();
       last_entity = star_entities.back();
-      if (!star_dp1.empty()) {
-        std::reverse(star_dp1.begin(), star_dp1.end());
-        last_dp1 = star_dp1.back();
+      if (!star_dp2.empty()) {
+        std::reverse(star_dp2.begin(), star_dp2.end());
+        last_dp2 = star_dp2.back();
       }
     }
       // else if we're not on the bdy and next_entity is already in star, that means
       // we've come all the way around; don't put next_entity on list again, and
-      // zero out last_dp1 to terminate while loop
+      // zero out last_dp2 to terminate while loop
     else if (!bdy_entity && 
              std::find(star_entities.begin(), star_entities.end(), next_entity) != 
-             star_entities.end())
+             star_entities.end() &&
+             (std::find(star_dp2.begin(), star_dp2.end(), next_dp2) != 
+             star_dp2.end() || !next_dp2))
     {
-      last_dp1 = 0;
+      last_dp2 = 0;
     }
 
       // else, just assign last entities seen and go on to next iteration
     else {
-      star_entities.push_back(next_entity);
-      if (0 != next_dp1) star_dp1.push_back(next_dp1);
+      if (std::find(star_entities.begin(), star_entities.end(), next_entity) == 
+          star_entities.end())
+        star_entities.push_back(next_entity);
+      if (0 != next_dp2) {
+        star_dp2.push_back(next_dp2);
+        tmp_candidates_dp2.erase(next_dp2);
+      }
       last_entity = next_entity;
-      last_dp1 = next_dp1;
+      last_dp2 = next_dp2;
     }
   }
-  while (0 != last_dp1);
+  while (0 != last_dp2);
   
-    // copy over the star_dp1 list, if requested
-  if (NULL != star_entities_dp1) 
-    (*star_entities_dp1).swap(star_dp1);
+    // copy over the star_dp2 list, if requested
+  if (NULL != star_entities_dp2) 
+    (*star_entities_dp2).swap(star_dp2);
   
   return MB_SUCCESS;
 }
@@ -183,6 +201,7 @@
   MBRange from_ents, to_ents;
   from_ents.insert(star_center);
   if (0 != last_dp1) from_ents.insert(last_dp1);
+    
   int dim = mbImpl->dimension_from_handle(star_center);
   
   MBErrorCode result = mbImpl->get_adjacencies(from_ents, dim+1, false, to_ents);
@@ -200,6 +219,16 @@
     }
     to_ents = tmp_to_ents;
   }
+
+  if (0 == last_dp1 && to_ents.size() > 1 && NULL != star_candidates_dp1 && 
+      !star_candidates_dp1->empty()) {
+      // if we have a choice of to_ents and no previous dp1 and dp1 candidates, 
+      // the one we choose needs to be adjacent to one of the candidates
+    result = mbImpl->get_adjacencies(*star_candidates_dp1, dim+1, false,
+                                     from_ents, MBInterface::UNION);
+    if (MB_SUCCESS != result) return result;
+    to_ents = to_ents.intersect(from_ents);
+  }
   
   if (!to_ents.empty()) next_entity = *to_ents.begin();
   else {
@@ -239,8 +268,8 @@
     // Algorithm:
     // get the (d+2)-manifold entities; for d=1 / d+2=3, just assume all connected elements, since
     //   we don't do 4d yet
-    // get intersection of (d+1)-entities adjacent to star and union of (d+1)-entities 
-    //   adjacent to (d+2)-manifold entities
+    // get intersection of (d+1)-entities adjacent to star entity and union of (d+1)-entities 
+    //   adjacent to (d+2)-manifold entities; these will be the entities in the star
     // while (d+1)-entities
     //   remove (d+1)-entity from (d+1)-entities
     //   get the (d+1)-star and (d+2)-star around that (d+1)-entity (using star_entities)
@@ -319,6 +348,13 @@
       // (end while)
   }
 
+    // check for leftover dp2 manifold entities, these should be in one of the 
+    // stars
+  if (!dp2_manifold.empty()) {
+    for (MBRange::iterator rit = dp2_manifold.begin(); rit != dp2_manifold.end(); rit++) {
+    }
+  }
+    
   return MB_SUCCESS;
 }
 
@@ -439,6 +475,38 @@
   else return *tmp_range2.begin();
 }
 
+  //! return the opposite side entity given a parent and bounding entity.
+  //! This function is only defined for certain types of parent/child types;
+  //! See MBCN.hpp::OppositeSide for details.
+  //!
+  //! \param parent The parent element
+  //! \param child The child element
+  //! \param opposite_element The index of the opposite element
+MBErrorCode MeshTopoUtil::opposite_entity(const MBEntityHandle parent,
+                                          const MBEntityHandle child,
+                                          MBEntityHandle &opposite_element) 
+{
+    // get the side no.
+  int side_no, offset, sense;
+  MBErrorCode result = mbImpl->side_number(parent, child, side_no, 
+                                           offset, sense);
+  if (MB_SUCCESS != result) return result;
+  
+    // get the child index from MBCN
+  int opposite_index, opposite_dim;
+  int status = MBCN::OppositeSide(mbImpl->type_from_handle(parent),
+                                  side_no, mbImpl->dimension_from_handle(child),
+                                  opposite_index, opposite_dim);
+  if (0 != status) return MB_FAILURE;
+  
+    // now get the side element from MOAB
+  result = mbImpl->side_element(parent, opposite_dim, opposite_index, 
+                                opposite_element);
+  if (MB_SUCCESS != result) return result;
+  
+  return MB_SUCCESS;
+}
+
 MBErrorCode MeshTopoUtil::split_entities_manifold(MBRange &entities,
                                                   MBRange &new_entities,
                                                   MBRange *fill_entities) 
@@ -575,93 +643,50 @@
 }
 
 MBErrorCode MeshTopoUtil::split_entity_nonmanifold(MBEntityHandle split_ent,
-                                                   MBRange &new_ents) 
+                                                   MBRange &old_adjs,
+                                                   MBRange &new_adjs,
+                                                   MBEntityHandle &new_entity) 
 {
+    // split an entity into two entities; new entity gets explicit adj to new_adjs,
+    // old to old_adjs
 
-    // split an entity into multiple entities, one per (d+2)-connected region
-    // in the (d+1)-star around the entity
-  std::vector<std::vector<MBEntityHandle> > star_regions;
-  std::vector<bool> bdy_flags;
-  MBErrorCode result = star_entities_nonmanifold(split_ent, star_regions);
-  if (MB_SUCCESS != result) return result;
-
-    // should be at least 2 regions
-  if (star_regions.size() < 2) return MB_FAILURE;
+    // make new entities and add adjacencies
+    // create the new entity
+  MBEntityType split_type = mbImpl->type_from_handle(split_ent);
   
-    // ok, have the regions; make new entities and add adjacencies to regions
-  std::vector<std::vector<MBEntityHandle> >::iterator vvit = star_regions.begin();
-  const MBEntityHandle *connect;
-  int num_connect;
-  MBEntityType split_type = mbImpl->type_from_handle(split_ent);
-  if (split_type != MBVERTEX) {
-    result = mbImpl->get_connectivity(split_ent, connect, num_connect);
-    if (MB_SUCCESS != result) return result;
+  MBErrorCode result;
+  if (MBVERTEX == split_type) {
+    double coords[3];
+    result = mbImpl->get_coords(&split_ent, 1, coords); RR;
+    result = mbImpl->create_vertex(coords, new_entity); RR;
   }
-  
-  for (; vvit != star_regions.end(); vvit++) {
-      // create the new entity
-    MBEntityHandle new_entity;
-    if (vvit != star_regions.begin()) {
-      if (MBVERTEX == split_type) {
-        double coords[3];
-        result = mbImpl->get_coords(&split_ent, 1, coords);
-        if (MB_SUCCESS != result) return result;
-        result = mbImpl->create_vertex(coords, new_entity);
-        if (MB_SUCCESS != result) return result;
-      }
-      else {
-        result = mbImpl->create_element(split_type, connect, num_connect, new_entity);
-        if (MB_SUCCESS != result) return result;
+  else {
+    const MBEntityHandle *connect;
+    int num_connect;
+    result = mbImpl->get_connectivity(split_ent, connect, num_connect); RR;
+    result = mbImpl->create_element(split_type, connect, num_connect, new_entity); RR;
 
-          // remove any explicit adjacencies with split entity
-        result = mbImpl->remove_adjacencies(split_ent, &(*vvit)[0], vvit->size());
-        if (MB_SUCCESS != result) return result;
-      }
+      // remove any explicit adjacencies between new_adjs and split entity
+    for (MBRange::iterator rit = new_adjs.begin(); rit != new_adjs.end(); rit++)
+      mbImpl->remove_adjacencies(split_ent, &(*rit), 1);
+  }
       
-      new_ents.insert(new_entity);
+  if (MBVERTEX != split_type) {
+        //  add adj's between new_adjs & new entity, old_adjs & split_entity
+    for (MBRange::iterator rit = new_adjs.begin(); rit != new_adjs.end(); rit++)
+      mbImpl->add_adjacencies(new_entity, &(*rit), 1, true);
+    for (MBRange::iterator rit = old_adjs.begin(); rit != old_adjs.end(); rit++)
+      mbImpl->add_adjacencies(split_ent, &(*rit), 1, true);
+  }
+  else if (split_ent != new_entity) {
+      // instead of adjs replace in connectivity
+    std::vector<MBEntityHandle> connect;
+    for (MBRange::iterator rit = new_adjs.begin(); rit != new_adjs.end(); rit++) {
+      connect.clear();
+      result = mbImpl->get_connectivity(&(*rit), 1, connect); RR;
+      std::replace(connect.begin(), connect.end(), split_ent, new_entity);
+      result = mbImpl->set_connectivity(*rit, &connect[0], connect.size()); RR;
     }
-    else {
-      new_entity = split_ent;
-    }
-
-    if (MBVERTEX != split_type) {
-        //  add adjacency with new entity
-      result = mbImpl->add_adjacencies(new_entity, &(*vvit)[0], vvit->size(), false);
-      if (MB_SUCCESS != result) return result;
-    }
-    else if (split_ent != new_entity) {
-        // need to get all entities adjacent to edges in this star, and replace one
-        // vertex with another
-      MBRange star_ents;
-      result = mbImpl->get_adjacencies(&(*vvit)[0], vvit->size(), 2, false, star_ents,
-                                       MBInterface::UNION);
-      if (MB_SUCCESS != result) return result;
-
-        // add edges adjacent to these faces which are also adjacent to split_ent
-      MBRange dum_range, dum_range_2;
-      result = mbImpl->get_adjacencies(&split_ent, 1, 1, false, dum_range);
-      if (MB_SUCCESS != result) return result;
-      result = mbImpl->get_adjacencies(star_ents, 1, false, dum_range_2, MBInterface::UNION);
-      if (MB_SUCCESS != result) return result;
-      dum_range = dum_range.intersect(dum_range_2);
-      star_ents.merge(dum_range);
-      
-      result = mbImpl->get_adjacencies(&(*vvit)[0], vvit->size(), 3, false, star_ents,
-                                       MBInterface::UNION);
-      if (MB_SUCCESS != result) return result;
-      std::copy(vvit->begin(), vvit->end(), mb_range_inserter(star_ents));
-      
-        // shouldn't matter which order we do this...
-      std::vector<MBEntityHandle> connect;
-      for (MBRange::iterator rit = star_ents.begin(); rit != star_ents.end(); rit++) {
-        connect.clear();
-        result = mbImpl->get_connectivity(&(*rit), 1, connect);
-        if (MB_SUCCESS != result) return result;
-        std::replace(connect.begin(), connect.end(), split_ent, new_entity);
-        
-        result = mbImpl->set_connectivity(*rit, &connect[0], connect.size());
-      }
-    }
   }
   
   return result;

Modified: MOAB/trunk/MeshTopoUtil.hpp
===================================================================
--- MOAB/trunk/MeshTopoUtil.hpp	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/MeshTopoUtil.hpp	2007-11-16 15:29:36 UTC (rev 1400)
@@ -99,12 +99,25 @@
                                const MBEntityHandle ent2,
                                const int dim);
   
+  //! return the opposite side entity given a parent and bounding entity.
+  //! This function is only defined for certain types of parent/child types;
+  //! See MBCN.hpp::OppositeSide for details.
+  //!
+  //! \param parent The parent element
+  //! \param child The child element
+  //! \param opposite_element The index of the opposite element
+  MBErrorCode opposite_entity(const MBEntityHandle parent,
+                              const MBEntityHandle child,
+                              MBEntityHandle &opposite_element);
+
     //! split entity which is non-manifold, that is, which has > 2 connected entities
     //! of next higher dimension; assumes that there are >= 2 connected regions of
     //! (d+2)-dimensional entities; a new d-entity is created for each region after the
     //! first, and it's made explicitly-adjacent to the region to which it corresponds
   MBErrorCode split_entity_nonmanifold(MBEntityHandle split_ent,
-                                       MBRange &new_ents);
+                                       MBRange &old_adjs,
+                                       MBRange &new_adjs,
+                                       MBEntityHandle &new_entity);
   
     //! split entities that are manifold (shared by two or less entities of each higher dimension),
     //! optionally creating an entity of next higher dimension to fill the gap

Modified: MOAB/trunk/tools/qvdual/DrawDual.hpp
===================================================================
--- MOAB/trunk/tools/qvdual/DrawDual.hpp	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/tools/qvdual/DrawDual.hpp	2007-11-16 15:29:36 UTC (rev 1400)
@@ -46,6 +46,8 @@
 
   MBErrorCode reset_drawn_sheets(MBRange *drawn_sheets = NULL);
   
+  void print_picked_ents(MBRange &picked_ents);
+
 private:
 
   static DrawDual *gDrawDual;
@@ -230,8 +232,6 @@
   
   MBErrorCode fixup_degen_bchords(MBEntityHandle dual_surf);
 
-  void print_picked_ents(MBRange &picked_ents);
-
     //! given some entities, get the corresponding gviz points on the sheet
   void get_points(const MBEntityHandle *ents, const int num_ents, 
                   const bool extra,

Modified: MOAB/trunk/tools/qvdual/uiQVDual.h
===================================================================
--- MOAB/trunk/tools/qvdual/uiQVDual.h	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/tools/qvdual/uiQVDual.h	2007-11-16 15:29:36 UTC (rev 1400)
@@ -1,7 +1,7 @@
 /****************************************************************************
 ** Form interface generated from reading ui file 'uiQVDual.ui'
 **
-** Created: Mon Sep 10 16:49:13 2007
+** Created: Mon Nov 5 08:55:16 2007
 **      by: The User Interface Compiler ($Id: qt/main.cpp   3.3.7   edited Aug 31 2005 $)
 **
 ** WARNING! All changes made in this file will be lost!
@@ -124,6 +124,7 @@
     virtual void fileSaveAs();
     virtual void resetDisplay();
     virtual void redrawDisplay();
+    virtual void pickline1_returnPressed();
 
 signals:
     void toggled();

Modified: MOAB/trunk/tools/qvdual/uiQVDual.ui
===================================================================
--- MOAB/trunk/tools/qvdual/uiQVDual.ui	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/tools/qvdual/uiQVDual.ui	2007-11-16 15:29:36 UTC (rev 1400)
@@ -922,6 +922,12 @@
         <receiver>uiQVDual</receiver>
         <slot>negFCbutton_clicked()</slot>
     </connection>
+    <connection>
+        <sender>pickline1</sender>
+        <signal>returnPressed()</signal>
+        <receiver>uiQVDual</receiver>
+        <slot>pickline1_returnPressed()</slot>
+    </connection>
 </connections>
 <includes>
     <include location="local" impldecl="in declaration">MBInterface.hpp</include>
@@ -1000,6 +1006,7 @@
     <slot>fileSaveAs()</slot>
     <slot>resetDisplay()</slot>
     <slot>redrawDisplay()</slot>
+    <slot>pickline1_returnPressed()</slot>
 </slots>
 <functions>
     <function access="private" specifier="non virtual">init()</function>

Modified: MOAB/trunk/tools/qvdual/uiQVDual.ui.h
===================================================================
--- MOAB/trunk/tools/qvdual/uiQVDual.ui.h	2007-11-16 15:18:33 UTC (rev 1399)
+++ MOAB/trunk/tools/qvdual/uiQVDual.ui.h	2007-11-16 15:29:36 UTC (rev 1400)
@@ -1055,3 +1055,52 @@
 
   this->updateMesh();
 }
+
+
+void uiQVDual::pickline1_returnPressed()
+{
+    // get the currently picked entity
+  QString line = pickline1->text();
+
+  MBRange cell_ents, picked_ents;
+  int last_match = 0, next_match = 0;
+  MBHandleUtils hu(vtkMOABUtils::mbImpl->proc_rank(), 
+                   vtkMOABUtils::mbImpl->proc_size());
+  while (true) {
+    last_match = next_match;
+    if (-1 == last_match) break;
+    if (0 != last_match) last_match++;
+    next_match = line.find("-", last_match);
+    int ent_no = -1;
+    MBEntityType etype = MBMAXTYPE;
+    if (line.ascii()[last_match] == 'h') etype = MBHEX;
+    else if (line.ascii()[last_match] == 'f') etype = MBQUAD;
+    sscanf(line.ascii()+last_match+1, "%d", &ent_no);
+    if (-1 != ent_no && MBMAXTYPE != etype)
+      cell_ents.insert(hu.create_handle(etype, ent_no, 0));
+  }
+#define PR(a) {pickline1->setText(QString(a));return;}
+
+  if (cell_ents.size() < 2) PR("(not a dual entity!)");
+
+  MBErrorCode result;
+  DualTool dt(vtkMOABUtils::mbImpl);
+  if (cell_ents.size() > 2) {
+      // assume it's a dual 2-cell
+    result = vtkMOABUtils::mbImpl->get_adjacencies(cell_ents, 1, false, 
+                                                   picked_ents);
+    if (picked_ents.empty()) PR("(not a dual 2-cell!)");
+  }
+  else {
+    result = vtkMOABUtils::mbImpl->get_adjacencies(cell_ents, 2, false, 
+                                                   picked_ents);
+    if (picked_ents.empty()) PR("(not a dual 1-cell!)");
+  }
+  
+  MBEntityHandle dual_ent = dt.get_dual_entity(*picked_ents.begin());
+  if (0 ==  dual_ent) PR("(no dual entity!)");
+  picked_ents.clear();
+  picked_ents.insert(dual_ent);
+    
+  vtkMOABUtils::drawDual->print_picked_ents(picked_ents);
+}




More information about the moab-dev mailing list