Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
SkinMesh.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <cstdlib>
3 #include "MBCore.hpp"
4 #include "MBRange.hpp"
5 #include "MBTagConventions.hpp"
6 
7 // Hold edges in an array of vertex handles.
8 struct edge
9 {
10  MBEntityHandle v0;
11  MBEntityHandle v1;
12 };
13 
14 // edge structure comparision function for qsort
15 // If the first vertex handle is the same, compare the second.
16 int compare_edge( const void* a, const void* b )
17 {
18  struct edge* ia = (struct edge*)a;
19  struct edge* ib = (struct edge*)b;
20  if( ia->v0 == ib->v0 )
21  {
22  return (int)( 100.f * ia->v1 - 100.f * ib->v1 );
23  }
24  else
25  {
26  return (int)( 100.f * ia->v0 - 100.f * ib->v0 );
27  }
28 }
29 
30 // This skinner is fast partly because it assumes that no edges exist in the MOAB
31 // instance. Checking to see if an edge exists before creating a new one is slow.
32 MBErrorCode skin_tris( MBInterface* mb, MBRange tris, MBRange& skin_edges )
33 {
34 
35  // Empty the output range and make sure that the input range is only tris
36  skin_edges.clear();
37  if( tris.empty() ) return MB_ENTITY_NOT_FOUND;
38  if( !tris.all_of_type( MBTRI ) ) return MB_FAILURE;
39 
40  // Remove edges from the instance.
41  int n_edges;
42  MBErrorCode rval = mb->get_number_entities_by_type( 0, MBEDGE, n_edges );
43  if( MB_SUCCESS != rval ) return rval;
44  if( 0 != n_edges )
45  {
46  std::cerr << "skin_tris: failed because " << n_edges << " edges exist in the MOAB instance" << std::endl;
47  return MB_FAILURE;
48  }
49 
50  // Get connectivity. Do not create MBEdges.
51  edge* edges = new edge[3 * tris.size()];
52  int n_verts;
53  int ii = 0;
54  for( MBRange::iterator i = tris.begin(); i != tris.end(); ++i )
55  {
56  const MBEntityHandle* conn;
57  rval = mb->get_connectivity( *i, conn, n_verts );
58  if( MB_SUCCESS != rval ) return rval;
59  if( 3 != n_verts ) return MB_FAILURE;
60  // points should not be degenerate
61  if( conn[0] == conn[1] || conn[1] == conn[2] || conn[2] == conn[0] )
62  {
63  std::cerr << "skin_tris: degenerate triangle" << std::endl;
64  return MB_FAILURE;
65  }
66 
67  // make edges
68  edges[3 * ii + 0].v0 = conn[0];
69  edges[3 * ii + 0].v1 = conn[1];
70  edges[3 * ii + 1].v0 = conn[1];
71  edges[3 * ii + 1].v1 = conn[2];
72  edges[3 * ii + 2].v0 = conn[2];
73  edges[3 * ii + 2].v1 = conn[0];
74  ii++;
75  }
76 
77  // Ensure that the first vertex handle is the lowest
78  for( unsigned int i = 0; i < 3 * tris.size(); ++i )
79  {
80  if( edges[i].v0 > edges[i].v1 )
81  {
82  MBEntityHandle temp = edges[i].v0;
83  edges[i].v0 = edges[i].v1;
84  edges[i].v1 = temp;
85  }
86  }
87 
88  // Sort by first handle, then second handle.
89  qsort( edges, 3 * tris.size(), sizeof( struct edge ), compare_edge );
90 
91  // Go through array, saving edges that are not paired.
92  for( unsigned int i = 0; i < 3 * tris.size(); i++ )
93  {
94  // If the last edge has not been paired, create it. This avoids overrunning
95  // the edges array with i+1.
96  if( 3 * tris.size() - 1 == i )
97  {
98  const MBEntityHandle conn[2] = { edges[i].v0, edges[i].v1 };
99  MBEntityHandle edge;
100  rval = mb->create_element( MBEDGE, conn, 2, edge );
101  if( MB_SUCCESS != rval ) return rval;
102  skin_edges.insert( edge );
103 
104  // If a match exists, skip ahead
105  }
106  else if( edges[i].v0 == edges[i + 1].v0 && edges[i].v1 == edges[i + 1].v1 )
107  {
108  i++;
109  // test to make sure surface is manifold
110  while( edges[i].v0 == edges[i + 1].v0 && edges[i].v1 == edges[i + 1].v1 )
111  {
112  std::cout << "find_skin WARNING: non-manifold edge" << std::endl;
113  mb->list_entity( edges[i].v0 );
114  mb->list_entity( edges[i].v1 );
115  ++i;
116  }
117  // otherwise a skin edge has been found
118  }
119  else
120  {
121  const MBEntityHandle conn[2] = { edges[i].v0, edges[i].v1 };
122  MBEntityHandle edge;
123  rval = mb->create_element( MBEDGE, conn, 2, edge );
124  if( MB_SUCCESS != rval ) return rval;
125  skin_edges.insert( edge );
126  }
127  }
128  delete[] edges;
129  return MB_SUCCESS;
130 }
131 
132 // Skin triangles to recover edges.
133 // Triangles are contained in surface sets.
134 int main( int argc, char** argv )
135 {
136  if( 1 == argc )
137  {
138  std::cout << "Usage: " << argv[0] << " <filename>" << std::endl;
139  return 0;
140  }
141 
142  // get MOAB instance and read the file
143  MBCore* mb = new MBCore();
144  MBErrorCode rval = mb->load_file( argv[1] );
145  if( MB_SUCCESS != rval ) return 0;
146 
147  // this optimized skinner requires removing all MBEdges from the MOAB instance
148  MBRange edges;
149  rval = mb->get_entities_by_type( 0, MBEDGE, edges );
150  if( MB_SUCCESS != rval ) return 0;
151  if( !edges.empty() ) std::cout << "Warning: deleting all MBEdges" << std::endl;
152  rval = mb->delete_entities( edges );
153  if( MB_SUCCESS != rval ) return 0;
154 
155  // get surface sets
156  MBTag geom_tag;
157  rval = mb->tag_get_handle( GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER, geom_tag );
158  if( MB_SUCCESS != rval ) return 0;
159  MBRange surf_sets;
160  int two = 2;
161  void* dim[] = { &two };
162  rval = mb->get_entities_by_type_and_tag( 0, MBENTITYSET, &geom_tag, dim, 1, surf_sets );
163  if( MB_SUCCESS != rval ) return 0;
164 
165  // skin each surface
166  for( MBRange::iterator i = surf_sets.begin(); i != surf_sets.end(); ++i )
167  {
168 
169  // get triangles in the surface set
170  MBRange tris;
171  rval = mb->get_entities_by_type( *i, MBTRI, tris );
172  if( MB_SUCCESS != rval ) return 0;
173 
174  // call the skinning function
175  MBRange skin_edges;
176  rval = skin_tris( mb, tris, skin_edges );
177  if( MB_SUCCESS != rval ) return 0;
178 
179  // do something with the result
180  std::cout << "surface has " << skin_edges.size() << " skin edges" << std::endl;
181 
182  // remove the edges for the optimized skinner
183  rval = mb->delete_entities( skin_edges );
184  if( MB_SUCCESS != rval ) return 0;
185  }
186 }