Exemplo n.º 1
0
 MBErrorCode delete_degenerate_tris( MBRange tris ) {
   MBErrorCode result;
   for(MBRange::iterator i=tris.begin(); i!=tris.end(); i++) {
     result = delete_degenerate_tris( *i );
     assert(MB_SUCCESS == result);
   }
   return MB_SUCCESS;
 }
Exemplo n.º 2
0
MBErrorCode build_obbs(moab::OrientedBoxTreeTool *obbTree, MBRange &surfs, MBRange &volumes)
{
  MBErrorCode rval = MB_SUCCESS;

  for (MBRange::iterator i = surfs.begin(); i != surfs.end(); ++i) {
    MBEntityHandle root;
    MBRange tris;
    rval = MBI()->get_entities_by_dimension( *i, 2, tris );
    if (MB_SUCCESS != rval)
      return rval;
    if (tris.empty())
      std::cerr << "WARNING: Surface " << *i << " has no facets." << std::endl;
    rval = obbTree->build( tris, root );
    if (MB_SUCCESS != rval)
      return rval;

    #pragma omp critical
    rval = MBI()->add_entities( root, &*i, 1 );
    if (MB_SUCCESS != rval)
      return rval;
  }

  return MB_SUCCESS;
}
Exemplo n.º 3
0
int main(int argc, char **argv)
{

//open moab instance
MBInterface *MBI();

//for unit testing purposes, we don't care about the output. Just PASS or FAIL. 
bool verbose=false;

// ******************************************************************
  // Load the h5m file and create tags.
  // ******************************************************************

  clock_t start_time;
  start_time = clock();
  

  // load file and get tolerance from the iter file
  MBErrorCode result;
  std::string filename = "iter_imprinted.h5m"; //set filename
  MBEntityHandle input_set;
  result = MBI()->create_meshset( MESHSET_SET, input_set ); //create handle to meshset
  if(MB_SUCCESS != result) 
    {
      return result;
    }

result = MBI()->load_file( filename.c_str(), &input_set ); //load the file into the meshset
  if(MB_SUCCESS != result) 
    {
      // failed to load the file
      std::cout << "could not load file" << std::endl;
      return result;
    }

  /// get faceting tolerance ///
  double facet_tolerance;

  MBTag faceting_tol_tag;
  //get faceting tolerance handle from file
  result = MBI()->tag_get_handle( "FACETING_TOL", 1, MB_TYPE_DOUBLE,
        faceting_tol_tag , moab::MB_TAG_SPARSE|moab::MB_TAG_CREAT );
  if(gen::error(MB_SUCCESS!=result, "could not get the faceting tag handle")) return result;
  
  //get the faceting tolerance of any entity
  MBRange file_set;
  result = MBI()->get_entities_by_type_and_tag( 0, MBENTITYSET, 
                        &faceting_tol_tag, NULL, 1, file_set );

  //get facetint tolerance value
  result = MBI()->tag_get_data( faceting_tol_tag, &file_set.front(), 1, &facet_tolerance );
  if(gen::error(MB_SUCCESS!=result, "could not get the faceting tolerance")) return result; 

  // create tags on geometry
  MBTag geom_tag, id_tag;
  result = MBI()->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, 
                            MB_TYPE_INTEGER, geom_tag, moab::MB_TAG_DENSE|moab::MB_TAG_CREAT );
  if(gen::error(MB_SUCCESS != result, "could not get GEOM_DIMENSION_TAG_NAME handle")) return result; 

  result = MBI()->tag_get_handle( GLOBAL_ID_TAG_NAME, 1, 
                            MB_TYPE_INTEGER, id_tag, moab::MB_TAG_DENSE|moab::MB_TAG_CREAT );
  if(gen::error(MB_SUCCESS != result, "could not get GLOBAL_ID_TAG_NAME handle")) return result;
  
  // get surface and volume sets
  MBRange surf_sets, vol_sets; // MBRange of set of surfaces and volumes
  // surface sets
  int dim = 2;
  void* input_dim[] = {&dim};
  result = MBI()->get_entities_by_type_and_tag( input_set, MBENTITYSET, &geom_tag, 
                                                input_dim, 1, surf_sets);
  if(MB_SUCCESS != result) 
    {
      return result;
    }

  // volume sets
  dim = 3;
  result = MBI()->get_entities_by_type_and_tag( input_set, MBENTITYSET, &geom_tag, 
                                                input_dim, 1, vol_sets);
  if(MB_SUCCESS != result)
    {
      return result;
    }
    
  //vertex sets
  dim= 0;
  MBRange verts;
  result = MBI()->get_entities_by_dimension(input_set, dim, verts, false);
  if(gen::error(MB_SUCCESS!=result, " could not get vertices from the mesh")) return result;
  
  if(gen::error(MB_SUCCESS!=result, "could not get vertex coordinates")) return result; 
  
if(verbose)
{
  std::cout<< "number of verticies= " << verts.size() << std::endl;  
  std::cout<< "number of surfaces= " << surf_sets.size() << std::endl;
  std::cout<< "number of volumes= "  << vol_sets.size() << std::endl;
}

//initialize booleans to pass to make_mesh_watertight

  bool check_topology, test, sealed;
       check_topology=false;
       test=true;
  
// initialize boolean for each set of tests
  bool test_set_result=true;


//seal mesh and make sure it is entirely sealed

// seal the model using make_watertight 
  result=mw_func::make_mesh_watertight (input_set, facet_tolerance, false);
  if(gen::error(MB_SUCCESS!=result, "could not make the mesh watertight")) return result;
  
  // Lastly Check to see if make_watertight fixed the model
  result=cw_func::check_mesh_for_watertightness( input_set, facet_tolerance, sealed, test);
  if(gen::error(MB_SUCCESS!=result, "could not check model for watertightness")) return result;
  
  if(sealed)
  {
   std::cout << "PASS" << std::endl;
  }
  else
  {
   std::cout << "FAIL" << std::endl;
   test_set_result=false;
  }

 exit(0);
}
Exemplo n.º 4
0
bool CamalPaveDriver::prepareCGMEvaluator()
{
	//
	// we will have to mesh every geo edge separately, and we have to ensure that the number of mesh edges
	// for a face is even.
	// pretty tough to do. Initially, we have to decide loops, number of edges on each face, etc
	// first build
	//int err;
	// get the triangles and the vertices from moab set

	/*iBase_EntityHandle *triangles = NULL;
	int triangles_alloc = 0;
	iBase_EntityHandle *vert_adj = NULL;
	int vert_adj_alloc = 0, vert_adj_size;
	int numTriangles;
	int * offsets = NULL, offsets_alloc = 0, indices_size;
	int * indices = NULL, indices_alloc = 0, offsets_size;
	iMesh_getAdjEntIndices(_meshIface, _set, iBase_FACE, iMesh_TRIANGLE,
			iBase_VERTEX, &triangles, &triangles_alloc, &numTriangles,
			&vert_adj, &vert_adj_alloc, &vert_adj_size, &indices,
			&indices_alloc, &indices_size, &offsets, &offsets_alloc,
			&offsets_size, &err);
	ERRORR("Couldn't get connectivity for triangles.", 1);*/

	MBRange triangles;
	MBErrorCode rval = _mb->get_entities_by_type( 0 /* root set, as above, we know */,
											   MBTRI, triangles);
	// get all the nodes
	MBRange vertices;
	rval = _mb->get_adjacencies(triangles, 0, false, vertices, MBInterface::UNION);

	// first, create CubitPointData list, from the coordinates in one array
	/* get the coordinates in one array */

	/*int vert_coords_alloc = 0, vertex_coord_size;
	double * xyz = NULL;
	iMesh_getVtxArrCoords(_meshIface, vert_adj, vert_adj_size,
			iBase_INTERLEAVED, &xyz, &vert_coords_alloc, &vertex_coord_size,
			&err);
	ERRORR("Couldn't get coordinates for vertices.", 1);*/

	// here, we use Cholla from CGM
	// we need to replace it with something equivalent, but simpler
	// the first try would be some tags in MOAB
	// create the cubit point data
	// initialize CGM
	AppUtil::instance()->startup(0, NULL);
	CGMApp::instance()->startup(0, NULL);

	// Initialize the GeometryTool
	GeometryQueryTool *gqt = GeometryQueryTool::instance();
	FacetModifyEngine *fme = FacetModifyEngine::instance();

	int vert_adj_size =  vertices.size();
	int numTriangles = triangles.size();
	DLIList<CubitFacet*> f_list(numTriangles);
	DLIList<CubitPoint*> p_list(vert_adj_size);
	double * xyz = new double [3*vert_adj_size];
	rval = _mb->  get_coords(vertices, xyz);
	//std::map<MBEntityHandle, CubitPoint *> mapPoints;
	//MBRange::iterator it = vertices.begin();
	for (int i = 0; i < vert_adj_size; i++/*, it++*/) {
		double * pCoord = &xyz[3 * i];
		CubitPointData * newPoint = new CubitPointData(pCoord[0], pCoord[1],
				pCoord[2]);
		p_list.append(newPoint);
		//mapPoints[*it] = newPoint;// or maybe we should use finding the index in MBRange??
	}

	// yes
	// define all the triangles, to see what we have
	for (MBRange::iterator it = triangles.begin(); it!=triangles.end(); it++) {
		MBEntityHandle tri = *it;
		int nnodes;
		const MBEntityHandle * conn3;//
		_mb->get_connectivity(tri, conn3, nnodes);
		assert(nnodes == 3);
		int vtri[3];// indices for triangles
		int ii = 0;
		for (ii = 0; ii < 3; ii++)
			vtri[ii] = vertices.index(conn3[ii]); // vtri[ii] = indices[offsets[j] + ii];
		CubitFacetData * triangle = new CubitFacetData(p_list[vtri[0]],
				p_list[vtri[1]], p_list[vtri[2]]);
		f_list.append(triangle);
	}

	DLIList<LoopSM*> my_loops;

	DLIList<Surface*> surf_list;
	CubitStatus result;
	//double angle = 0.01;// very small, negligible; is this radians or degrees?
	result = fme->build_facet_surface(NULL, f_list, p_list, _angle, 4, true,
			false, surf_list);

	if (surf_list.size() == 0 || result != CUBIT_SUCCESS) {
		PRINT_ERROR("Problems building mesh based surfaces.\n");
		return result;
	} else
		PRINT_INFO("Constructed %d surfaces.\n", surf_list.size());

	//Now build the shell.  If we had it set up right this would be
	//in a loop.  We need to store list of DLBlockSurfaceLists on each
	//blockvolumemesh to store the shell information.  But that will
	//be saved for later.
	ShellSM *shell_ptr;
	result = fme->make_facet_shell(surf_list, shell_ptr);

	if (shell_ptr == NULL || result != CUBIT_SUCCESS) {
		PRINT_ERROR("Problems building mesh based shell entity.\n");
		return result;
	}
#if 1
	DLIList<ShellSM*> shell_list;
	shell_list.append(shell_ptr);
	Lump *lump_ptr;
	result = fme->make_facet_lump(shell_list, lump_ptr);

	if (lump_ptr == NULL || result != CUBIT_SUCCESS) {
		PRINT_ERROR("Problems building mesh based lump entity.\n");
		return result;
	}
	DLIList<Lump*> lump_list;
	lump_list.append(lump_ptr);

	BodySM *bodysm_ptr;
	Body *body_ptr;
	result = fme->make_facet_body(lump_list, bodysm_ptr);

	body_ptr = GeometryQueryTool::instance()->make_Body(bodysm_ptr);

	if (body_ptr == NULL || result != CUBIT_SUCCESS) {
		PRINT_ERROR("Problems building mesh based body entity.\n");
		return result;
	}

	if (!body_ptr) {
		exit(1);
	}

	PRINT_INFO("Body successfully created.\n");
#endif
	PRINT_INFO("Number of vertices = %d\n", gqt->num_ref_vertices());
	PRINT_INFO("Number of edges = %d\n", gqt->num_ref_edges());
	PRINT_INFO("Number of faces = %d\n", gqt->num_ref_faces());

	// print vertex positions
	DLIList<RefVertex*> verts;
	gqt->ref_vertices(verts);

	int i;
	for (i = 0; i < verts.size(); i++) {
		RefVertex * vert = verts[i];
		CubitVector coords = vert->coordinates();
		PRINT_INFO("Vertex %d: %4.2f, %4.2f, %4.2f.\n", vert->id(), coords.x(),
				coords.y(), coords.z());
	}
	// print edges and faces

	DLIList<RefEdge*> refEdges;
	gqt->ref_edges(refEdges);

	for (i = 0; i < refEdges.size(); i++) {
		RefEdge * edg = refEdges[i];
		PRINT_INFO("Edge %d: %d %d\n", edg->id(), edg->start_vertex()->id(), edg->end_vertex ()->id() );
	}

	DLIList<RefFace*> refFaces;
	gqt->ref_faces(refFaces);

	for (i = 0; i < refFaces.size(); i++) {
		RefFace * face = refFaces[i];
		DLIList<  Loop * >  loop_list  ;
		face->ordered_loops (loop_list ) ;
		DLIList<  RefEdge  * > ordered_edge_list;
		loop_list[0]->ordered_ref_edges  (ordered_edge_list);

		//DLIList<  RefVertex* >  *listV = ref_vert_loop_list[0];
		PRINT_INFO("face %d: loop 0 size %d\n", face->id(),  ordered_edge_list.size() );
		for (int j=0; j<ordered_edge_list.size(); j++)
		{
			PRINT_INFO("  %d", ordered_edge_list[j]->id() );
		}
		PRINT_INFO("\n");
	}
	return true;
}
Exemplo n.º 5
0
    // we do not merge edges, just vert. check the verts
  MBErrorCode test_zipping(const double FACET_TOL,
                           const std::vector< std::vector<MBEntityHandle> > arcs ) {
      MBErrorCode result;

      // make sure each arc has the same number of edges
      for(unsigned int i=1; i<arcs.size(); i++) {
	if(arcs[0].size() != arcs[i].size()) {
	  std::cout << "The curve has " << arcs[0].size() << " edges but arc "
		    << i << " has " << arcs[i].size() << " edges." << std::endl;
	  gen::print_arcs( arcs );
	  return MB_FAILURE;
	}
      }
  
      // loop over every edge of the curve (first arc)
      for(unsigned int i=0; i<arcs[0].size()-1; i++) {
	// check for degenerate edge
	if(arcs[0][i] == arcs[0][i+1]) {
	  std::cout << "degenerate edge at pos " << i << " and " << i+1 << " with verts "
		    << arcs[0][i] << " and " << arcs[0][i+1] << std::endl;
	  return MB_FAILURE;
	}
      
	// check for edge of zero dist
	double d = gen::dist_between_verts( arcs[0][i], arcs[0][i+1] );
	if(FACET_TOL >= d) {
	  std::cout << "edge length=" << d << " betwee pos " << i << " and " << i+1
		    << " with verts " << arcs[0][i] << " and " << arcs[0][i+1] << std::endl;
	  return MB_FAILURE;
	}
     
	// loop over every arc
	for( unsigned int j=0; j<arcs.size(); j++) {      
	  // make sure vertices match
	  if(arcs[0][i]!=arcs[j][i] || arcs[0][i+1]!=arcs[j][i+1]) {
	    std::cout << "arc " << j << " vertices do not match curve vertices, pos= " 
		      << i << "/" << arcs[j].size() << std::endl;
	    return MB_FAILURE;
	  }
	}  	
        
	// make sure triangles have area
	MBRange tris;
	result = MBI()->get_adjacencies( &(arcs[0][i]), 2, 2, false, tris );
	assert(MB_SUCCESS == result);
	for(MBRange::iterator k=tris.begin(); k!=tris.end(); k++) {
	  // We know that there are not degenerate edges along the curve.
	  // Sometimes degenerate tris are created due to merging curve endpts.
	  // here we do not remove tri from the surf meshset, but we should
	  if( gen::triangle_degenerate(*k) ) {
	    //result = MBI()->delete_entities( &(*k), 1);
	    //assert(MB_SUCCESS == result);
	    std::cout << "  arc=" << 0 << " pos=" << i << " vert=" << arcs[0][i] 
		      << " degenerate triangle" << std::endl;
	    gen::print_triangle(*k, false);
	    //print_edge( edge );
	    //continue;
	    return MB_FAILURE;
	  }

	  double area;
          result = gen::triangle_area( *k, area );
          assert(MB_SUCCESS == result);
	  // I found a valid tri on a curve with only one edge (1e-5 long)
	  // that had an area of 1e-11.
	  if(1e-8 > area) {
	    std::cout << "    arc=" << 0 << " pos=" << i << " vert=" << arcs[0][i]
		      << " small triangle " << std::endl;
	    gen::print_triangle(*k, false);            
	    //print_edge( edge );
  	    gen::print_arcs( arcs );
	    //if(0.0 >= area) return MB_FAILURE;
	  } 
	}
      }
      return MB_SUCCESS;
    }          
Exemplo n.º 6
0
  MBErrorCode t_joint( MBTag normal_tag,
                       const MBEntityHandle vert0,
                       const MBEntityHandle vert1,
                       const MBEntityHandle vert2 ) {
    struct triangles {
      MBEntityHandle before_tri;
      const MBEntityHandle *before;
      MBCartVect     before_norm;
      MBEntityHandle after0[3];
      MBEntityHandle after1[3];
      MBCartVect     after0_norm;
      MBCartVect     after1_norm;
      MBEntityHandle surf_set;
    };   

    // Get all of the old information before changing anything. 
    // This is important because once the
    // new connectivity is set stuff becomes stale.
    // get the edge

    // get endpoints of the edge
    MBErrorCode result;
    MBEntityHandle endpts[2] = { vert0, vert2 }; 
    MBRange tris;
    result = MBI()->get_adjacencies( endpts, 2, 2, true, tris );
    assert(MB_SUCCESS == result);
    //std::cout << "t_joint: tris.size()=" << tris.size() << std::endl;
    //MBI()->list_entities( tris );

    triangles joints[tris.size()];
    for(unsigned int i=0; i<tris.size(); i++) {
      joints[i].before_tri = tris[i];

      // Find the surface set that the tri is in.
      MBRange surf_sets;
      result = MBI()->get_adjacencies( &joints[i].before_tri, 1, 4, false, surf_sets);
      assert(MB_SUCCESS == result);
      //std::cout << "t_joint: " << surf_sets.size() << " surface sets found for triangle" 
      //        << std::endl;
  
      // Check to make sure we found a set     
      if(1 != surf_sets.size()) {
	std::cout << "    t_joint: " << surf_sets.size() << " surface sets found for triangle " 
                  << joints[i].before_tri << std::endl;
        assert(1 == surf_sets.size());
	//if(1!=surf_sets.size()) return MB_FAILURE;
      }
      joints[i].surf_set = surf_sets.front();
      //std::cout << "t_joint: surf id=" << gen::geom_id_by_handle( joints[i].surf_set )
      //        << std::endl;  
      //gen::print_triangle( joints[i].before_tri, false );

      // get old  connectivity
      int n_verts;
      result = MBI()->get_connectivity( joints[i].before_tri, joints[i].before, n_verts);
      if(MB_SUCCESS != result) std::cout << "result=" << result << std::endl;
      assert(MB_SUCCESS == result);
      if(3 != n_verts) std::cout << "n_verts=" << n_verts << std::endl;
      assert(3 == n_verts);
   
      // test to make sure not degenerate
      //if(conn[0]==conn[1] || conn[1]==conn[2] || conn[2]==conn[0]) {
      if( gen::triangle_degenerate( joints[i].before_tri )) {
        std::cout << "    t_joint: degenerate input triangle" << std::endl;
        gen::print_triangle( joints[i].before_tri, false);
        return MB_FAILURE;
      }

      // make new connectivity
      for(int j=0; j<3; j++) {
	joints[i].after0[j] = (joints[i].before[j]==endpts[0]) ? vert1 : joints[i].before[j];
	joints[i].after1[j] = (joints[i].before[j]==endpts[1]) ? vert1 : joints[i].before[j]; 
      }

      // test to make sure not degenerate
      //if(conn0[0]==conn0[1] || conn0[1]==conn0[2] || conn0[2]==conn0[0]) {
      if(gen::triangle_degenerate( joints[i].after0[0], joints[i].after0[1], 
                                                        joints[i].after0[2])) {
	std::cout << "    t_joint: degenerate output triangle 1" << std::endl;	
        gen::print_triangle( joints[i].before_tri, false );
	//	return MB_FAILURE;
      }
      // test to make sure not degenerate
      //if(conn1[0]==conn1[1] || conn1[1]==conn1[2] || conn1[2]==conn1[0]) {
      if(gen::triangle_degenerate( joints[i].after1[0], joints[i].after1[1], 
                                                        joints[i].after1[2])) {
	std::cout << "    t_joint: degenerate output triangle 2" << std::endl;
        gen::print_triangle( joints[i].before_tri, false );
	//gen::print_triangle( *i, true );
	//return MB_FAILURE;
      }

      // set the new connectivity on the original triangle
      result = MBI()->set_connectivity( joints[i].before_tri, joints[i].after0, 3 );
      assert(MB_SUCCESS == result);
      // set the new connectivity on the new triangle
      MBEntityHandle new_tri;
      result = MBI()->create_element( MBTRI, joints[i].after1, 3, new_tri );
      assert(MB_SUCCESS == result);

      // copy the original normal to the new triangle
      MBCartVect normal;
      result = MBI()->tag_get_data( normal_tag, &joints[i].before_tri, 1, &normal);
      assert(MB_SUCCESS == result);
      result = MBI()->tag_set_data( normal_tag, &new_tri, 1, &normal);
      assert(MB_SUCCESS == result);
    
      // add the new triangle to the same surface set as the original
      result = MBI()->add_entities( joints[i].surf_set, &new_tri, 1);
      assert(MB_SUCCESS == result);

      // catch-all to remove degenerate tris
      result = zip::delete_degenerate_tris( joints[i].before_tri );
      if(gen::error(MB_SUCCESS!=result,"could not delete degenerate tri")) return result;
      result = zip::delete_degenerate_tris( new_tri );
      if(gen::error(MB_SUCCESS!=result,"could not delete degenerate tri")) return result;

      //gen::print_triangle( tri, false );
      //gen::print_triangle( new_tri, false );
    }
    return MB_SUCCESS;
  }
Exemplo n.º 7
0
  /* Accepts a range of inverted tris. Refacets affected surface so that no tris
     are inverted. */
  MBErrorCode remove_inverted_tris(MBTag normal_tag, MBRange tris, const bool debug ) {
      
    MBErrorCode result;
    bool failures_occur = false;
    while(!tris.empty()) {

      /* Get a group of triangles to re-facet. They must be adjacent to each other
	 and in the same surface. */
      MBRange tris_to_refacet;
      tris_to_refacet.insert( tris.front() );
      MBRange surf_set;
      result = MBI()->get_adjacencies( tris_to_refacet, 4, false, surf_set );
      assert(MB_SUCCESS == result);
      if(1 != surf_set.size()) {
	std::cout << "remove_inverted_tris: tri is in " << surf_set.size() 
                  << " surfaces" << std::endl;
        return MB_FAILURE;
      }

      // get all tris in the surface
      MBRange surf_tris;
      result = MBI()->get_entities_by_type( surf_set.front(), MBTRI, surf_tris );
      assert(MB_SUCCESS == result); 

      /* Find all of the adjacent inverted triangles of the same surface. Keep
	 searching until a search returns no new triangles. */
      bool search_again = true;
      while(search_again) {

        // Here edges are being created. Remember to delete them. Outside of this
        // function. Skinning gets bogged down if unused MBEdges (from other 
        // surfaces) accumulate.
        MBRange tri_edges;
        result = MBI()->get_adjacencies( tris_to_refacet, 1, true, tri_edges,
                                         MBInterface::UNION );
        assert(MB_SUCCESS == result);
        MBRange connected_tris;
        result = MBI()->get_adjacencies( tri_edges, 2, false, connected_tris, 
                                         MBInterface::UNION );
        assert(MB_SUCCESS == result);
        result = MBI()->delete_entities( tri_edges );
        assert(MB_SUCCESS == result);
        MBRange tris_to_refacet2 = intersect( tris_to_refacet, connected_tris );
        tris_to_refacet2 = intersect( tris_to_refacet, surf_tris );

        if(tris_to_refacet.size() == tris_to_refacet2.size()) search_again = false;
        tris_to_refacet.swap( tris_to_refacet2 );
      }

      // Remove the inverted tris that will be refaceted.
      tris = subtract( tris, tris_to_refacet );

        // do edges already exist?
	MBRange temp;
          result = MBI()->get_entities_by_type(0, MBEDGE, temp );
          assert(MB_SUCCESS == result);
          if(!temp.empty()) MBI()->list_entities( temp );
	  assert(temp.empty());


      // keep enlarging patch until we have tried to refacet the entire surface
      int counter=0;
      while(true) {
        // do edges already exist?
	temp.clear();
          result = MBI()->get_entities_by_type(0, MBEDGE, temp );
          assert(MB_SUCCESS == result);
          if(!temp.empty()) MBI()->list_entities( temp );
	  assert(temp.empty());


        counter++;
        // Only try enlarging each patch a few times
        if(48 == counter) {
          failures_occur = true;
	  if(debug) std::cout << "remove_inverted_tris: ear clipping failed, counter="
		              << counter << std::endl;
	  break;
        }
        // THIS PROVIDES A BAD EXIT. MUST FIX

        // get the edges of the patch of inverted tris
	MBRange tri_edges;
	result = MBI()->get_adjacencies( tris_to_refacet, 1, true, tri_edges,
                                         MBInterface::UNION );
	assert(MB_SUCCESS == result);

	// get all adjacent tris to the patch of inverted tris in the surface
	MBRange adj_tris;
	result = MBI()->get_adjacencies( tri_edges, 2, false, adj_tris, 
                                         MBInterface::UNION );
	assert(MB_SUCCESS == result);
        result = MBI()->delete_entities( tri_edges );
        assert(MB_SUCCESS == result);
	tris_to_refacet = intersect( surf_tris, adj_tris );
        if(tris_to_refacet.empty()) continue;
	//gen::print_triangles( tris_to_refacet );    
	
	// get an area-weighted normal of the adj_tris
	MBCartVect plane_normal(0,0,0);
	//for(unsigned int i=0; i<tris_to_refacet.size(); i++) {
	for(MBRange::iterator i=tris_to_refacet.begin(); i!=tris_to_refacet.end(); i++) {
	  MBCartVect norm;
	  result = MBI()->tag_get_data( normal_tag, &(*i), 1, &norm);
	  assert(MB_SUCCESS == result);
	  double area;
          result = gen::triangle_area( *i, area );
          assert(MB_SUCCESS == result);
	  if(debug) std::cout << "norm=" << norm << " area=" << area << std::endl;
	  //plane_normal += norm*area;
	  plane_normal += norm;
	}
	plane_normal.normalize();

        // do edges already exist?
	temp.clear();
          result = MBI()->get_entities_by_type(0, MBEDGE, temp );
          assert(MB_SUCCESS == result);
          if(!temp.empty()) MBI()->list_entities( temp );
	  assert(temp.empty());
 
	// skin the tris
	MBRange unordered_edges;
	//MBSkinner tool(MBI());
	//result = tool.find_skin( tris_to_refacet, 1, unordered_edges, false );
	result = gen::find_skin( tris_to_refacet, 1, unordered_edges, false );
	assert(MB_SUCCESS == result);
        if(unordered_edges.empty()) {
        // do edges already exist?
          MBRange temp;
          result = MBI()->get_entities_by_type(0, MBEDGE, temp );
          assert(MB_SUCCESS == result);
          if(!temp.empty()) MBI()->list_entities( temp );
	  assert(temp.empty());
          continue;
        }

	//std::cout << "remove_inverted_tris: surf_id=" 
	//  << gen::geom_id_by_handle(surf_set.front()) << std::endl;
	//result = MBI()->list_entities( tris_to_refacet );
	//assert(MB_SUCCESS == result);

	// assemble into a polygon
	std::vector<MBEntityHandle> polygon_of_verts;
	result = arc::order_verts_by_edge( unordered_edges, polygon_of_verts );
	if(debug) gen::print_loop( polygon_of_verts ); 
	//assert(MB_SUCCESS == result);
	if(MB_SUCCESS != result) {
	  if(debug) std::cout << "remove_inverted_tris: couldn't order polygon by edge" << std::endl;
	  return MB_FAILURE;
	}

        // remember to remove edges
        result = MBI()->delete_entities( unordered_edges );
        assert(MB_SUCCESS == result);

	// remove the duplicate endpt
	polygon_of_verts.pop_back();

	// the polygon should have at least 3 verts
	if(3 > polygon_of_verts.size()) {
	  if(debug) std::cout << "remove_inverted_tris: polygon has too few points" << std::endl;
	  return MB_FAILURE;
	}

	// orient the polygon with the triangles (could be backwards)
	// get the first adjacent tri
	MBEntityHandle edge[2] = { polygon_of_verts[0], polygon_of_verts[1] };
	MBRange one_tri;
	result = MBI()->get_adjacencies( edge, 2, 2, false, one_tri );
	assert(MB_SUCCESS == result);
	one_tri = intersect( tris_to_refacet, one_tri );
	assert(1 == one_tri.size());
	const MBEntityHandle *conn;
	int n_conn;
	result = MBI()->get_connectivity( one_tri.front(), conn, n_conn );
	assert(MB_SUCCESS == result);
	assert(3 == n_conn);
	if( (edge[0]==conn[1] && edge[1]==conn[0]) ||
	    (edge[0]==conn[2] && edge[1]==conn[1]) ||
	    (edge[0]==conn[0] && edge[1]==conn[2]) ) {
	  reverse( polygon_of_verts.begin(), polygon_of_verts.end() );
	  if(debug) std::cout << "remove_inverted_tris: polygon reversed" << std::endl;
	}

	/* facet the polygon. Returns MB_FAILURE if it fails to facet the polygon. */
	MBRange new_tris;
	result = gen::ear_clip_polygon( polygon_of_verts, plane_normal, new_tris );

        // break if the refaceting is successful
	if(MB_SUCCESS == result) {
          // summarize tri area
          for(MBRange::iterator i=new_tris.begin(); i!=new_tris.end(); i++) {
            double area;
            result = gen::triangle_area( *i, area );
            assert(MB_SUCCESS == result);
	    if(debug) std::cout << "  new tri area=" << area << std::endl;
          }

  	  // check the new normals
	  std::vector<MBCartVect> new_normals;
	  result = gen::triangle_normals( new_tris, new_normals );
	  if(MB_SUCCESS != result) return result;

	  // test the new triangles
	  std::vector<int> inverted_tri_indices;
	  std::vector<MBCartVect> normals ( new_normals.size(), plane_normal );
	  result = zip::test_normals( normals, new_normals, inverted_tri_indices );
	  assert(MB_SUCCESS == result);
	  if(inverted_tri_indices.empty()) {
  	    // remove the tris that were re-faceted
            tris = subtract( tris, tris_to_refacet );
  	    result = MBI()->remove_entities( surf_set.front(), tris_to_refacet );
	    assert(MB_SUCCESS == result);
	    result = MBI()->delete_entities( tris_to_refacet ); 
	    assert(MB_SUCCESS == result);

	    // add the new tris to the surf set
	    result = MBI()->add_entities( surf_set.front(), new_tris );
	    assert(MB_SUCCESS == result);

            // put the new normals on the new tris
            result = gen::save_normals( new_tris, normal_tag );
            assert(MB_SUCCESS == result);
	    if(debug) std::cout << "remove_inverted_tris: success fixing a patch" << std::endl;
            break;
          }
        }

        // remember to delete the tris that were created from the failed ear clipping
        else {
          result = MBI()->delete_entities( new_tris );
          assert(MB_SUCCESS == result);
        }

        // If the entire surface could not be ear clipped, give up
        if (tris_to_refacet.size() == surf_tris.size()) {
	  if(debug) std::cout << "remove_inverted_tris: ear clipping entire surface failed"
			    << std::endl;
	  return MB_FAILURE;
	}

      } // loop until the entire surface has attempted to be refaceted
    }   // loop over each patch of inverted tris
   
    if(failures_occur) {
      if(debug) std::cout << "remove_inverted_facets: at least one failure occured" << std::endl;
      return MB_FAILURE;
    } else {
      return MB_SUCCESS;
    }
  }