Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
ExtrudePoly.cpp
Go to the documentation of this file.
1 /**
2  * @example ExtrudePoly.cpp
3  * Example demonstrating extrusion of 2D polygons to create 3D polyhedra
4  *
5  * This example shows how to:
6  * - Load a 2D mesh from a file
7  * - Extrude 2D polygons to create 3D polyhedra (prisms)
8  * - Create multiple layers with specified thickness
9  * - Generate lateral faces connecting the layers
10  * - Handle different polygon types (triangles, quads, etc.)
11  * - Write the extruded mesh to a new file
12  *
13  * The extrusion process creates layers of vertices above the base mesh,
14  * then connects them to form polyhedra with top, bottom, and lateral faces.
15  *
16  * \param[in] [meshfile] The 2D mesh file to load (default: io/poly8-10.vtk)
17  * \param[in] [outfile] The output, extruded 3D mesh file name (default: polyhedra.vtk)
18  * \param[in] [nlayers] The number of axial layers (default: 1)
19  * \param[in] [thickness_layer] The thickness of axial layers (default: 1.0)
20  *
21  * \return 0 on success, 1 on failure
22  *
23  * \par Usage:
24  * \code
25  * ./ExtrudePoly [meshfile] [outfile] [nlayers] [thickness_layer]
26  * $> ./ExtrudePoly poly2d.h5m poly3d.h5m 5 1.0
27  * \endcode
28  *
29  * @author MOAB Development Team
30  * @date Last updated: 2025
31  */
32 
33 #include "moab/Core.hpp"
34 #include "moab/ReadUtilIface.hpp"
35 #include <iostream>
36 
37 using namespace moab;
38 using namespace std;
39 
40 #ifndef MESH_DIR
41 #define MESH_DIR "."
42 #endif
43 
44 // at most 20 edges per polygon
45 #define MAXEDGES 20
46 // Note: change the file name below to test a trivial "No such file or directory" error
47 string test_file_name = string( MESH_DIR ) + string( "/io/poly8-10.vtk" );
48 string output = string( "polyhedra.vtk" );
49 int layers = 1;
50 double layer_thick = 1.0;
51 
52 int main( int argc, char** argv )
53 {
54  // Get MOAB instance
55  Interface* mb = new( std::nothrow ) Core;
56  if( NULL == mb ) return 1;
57 
58  // Need option handling here for input filename
59  if( argc > 1 )
60  {
61  // User has input a mesh file
62  test_file_name = argv[1];
63  }
64  if( argc > 2 ) output = argv[2];
65 
66  if( argc > 3 ) layers = atoi( argv[3] );
67 
68  if( argc > 4 ) layer_thick = atof( argv[4] );
69 
70  std::cout << "Run: " << argv[0] << " " << test_file_name << " " << output << " " << layers << " " << layer_thick
71  << "\n";
72  // Load the mesh from vtk file
73  MB_CHK_ERR( mb->load_mesh( test_file_name.c_str() ) );
74 
75  // Get verts entities, by type
76  Range verts;
77  MB_CHK_ERR( mb->get_entities_by_type( 0, MBVERTEX, verts ) );
78 
79  // Get faces, by dimension, so we stay generic to entity type
80  Range faces;
81  MB_CHK_ERR( mb->get_entities_by_dimension( 0, 2, faces ) );
82  cout << "Number of vertices is " << verts.size() << endl;
83  cout << "Number of faces is " << faces.size() << endl;
84 
85  Range edges;
86  // create all edges
87  MB_CHK_ERR( mb->get_adjacencies( faces, 1, true, edges, Interface::UNION ) );
88 
89  cout << "Number of edges is " << edges.size() << endl;
90 
91  std::vector< double > coords;
92  int nvPerLayer = (int)verts.size();
93  coords.resize( 3 * nvPerLayer );
94 
95  MB_CHK_ERR( mb->get_coords( verts, &coords[0] ) );
96  // create first vertices
97  Range* newVerts = new Range[layers + 1];
98  newVerts[0] = verts; // just for convenience
99  for( int ii = 0; ii < layers; ii++ )
100  {
101  for( int i = 0; i < nvPerLayer; i++ )
102  coords[3 * i + 2] += layer_thick;
103 
104  MB_CHK_ERR( mb->create_vertices( &coords[0], nvPerLayer, newVerts[ii + 1] ) );
105  }
106  // for each edge, we will create layers quads
107  int nquads = edges.size() * layers;
108  ReadUtilIface* read_iface;
109  MB_CHK_SET_ERR( mb->query_interface( read_iface ), "Error in query_interface" );
110 
111  EntityHandle start_elem, *connect;
112  // Create quads
113  MB_CHK_SET_ERR( read_iface->get_element_connect( nquads, 4, MBQUAD, 0, start_elem, connect ),
114  "Error in get_element_connect" );
115  int nedges = (int)edges.size();
116 
117  int indexConn = 0;
118  for( int j = 0; j < nedges; j++ )
119  {
120  EntityHandle edge = edges[j];
121 
122  const EntityHandle* conn2 = NULL;
123  int num_nodes;
124  MB_CHK_ERR( mb->get_connectivity( edge, conn2, num_nodes ) );
125  if( 2 != num_nodes ) MB_CHK_ERR( MB_FAILURE );
126 
127  int i0 = verts.index( conn2[0] );
128  int i1 = verts.index( conn2[1] );
129  for( int ii = 0; ii < layers; ii++ )
130  {
131  connect[indexConn++] = newVerts[ii][i0];
132  connect[indexConn++] = newVerts[ii][i1];
133  connect[indexConn++] = newVerts[ii + 1][i1];
134  connect[indexConn++] = newVerts[ii + 1][i0];
135  }
136  }
137 
138  int nfaces = (int)faces.size();
139  EntityHandle* allPolygons = new EntityHandle[nfaces * ( layers + 1 )];
140  for( int i = 0; i < nfaces; i++ )
141  allPolygons[i] = faces[i];
142 
143  // vertices are parallel to the base vertices
144  int indexVerts[MAXEDGES] = { 0 }; // polygons with at most MAXEDGES edges
145  EntityHandle newConn[MAXEDGES] = { 0 };
146  EntityHandle polyhedronConn[MAXEDGES + 2] = { 0 };
147 
148  // edges will be used to determine the lateral faces of polyhedra (prisms)
149  int indexEdges[MAXEDGES] = { 0 }; // index of edges in base polygon
150  for( int j = 0; j < nfaces; j++ )
151  {
152  EntityHandle polyg = faces[j];
153 
154  const EntityHandle* connp = NULL;
155  int num_nodes;
156  MB_CHK_ERR( mb->get_connectivity( polyg, connp, num_nodes ) );
157 
158  for( int i = 0; i < num_nodes; i++ )
159  {
160  indexVerts[i] = verts.index( connp[i] );
161  int i1 = ( i + 1 ) % num_nodes;
162  EntityHandle edgeVerts[2] = { connp[i], connp[i1] };
163  // get edge adjacent to these vertices
164  Range adjEdges;
165  MB_CHK_ERR( mb->get_adjacencies( edgeVerts, 2, 1, false, adjEdges ) );
166  if( adjEdges.size() < 1 ) MB_CHK_SET_ERR( MB_FAILURE, " did not find edge " );
167  indexEdges[i] = edges.index( adjEdges[0] );
168  if( indexEdges[i] < 0 ) MB_CHK_SET_ERR( MB_FAILURE, "did not find edge in range" );
169  }
170 
171  for( int ii = 0; ii < layers; ii++ )
172  {
173  // create a polygon on each layer
174  for( int i = 0; i < num_nodes; i++ )
175  newConn[i] = newVerts[ii + 1][indexVerts[i]]; // vertices in layer ii+1
176 
177  MB_CHK_ERR( mb->create_element( MBPOLYGON, newConn, num_nodes, allPolygons[nfaces * ( ii + 1 ) + j] ) );
178 
179  // now create a polyhedra with top, bottom and lateral swept faces
180  // first face is the bottom
181  polyhedronConn[0] = allPolygons[nfaces * ii + j];
182  // second face is the top
183  polyhedronConn[1] = allPolygons[nfaces * ( ii + 1 ) + j];
184  // next add lateral quads, in order of edges, using the start_elem
185  // first layer of quads has EntityHandle from start_elem to start_elem+nedges-1
186  // second layer of quads has EntityHandle from start_elem + nedges to
187  // start_elem+2*nedges-1 ,etc
188  for( int i = 0; i < num_nodes; i++ )
189  {
190  polyhedronConn[2 + i] = start_elem + ii + layers * indexEdges[i];
191  }
192  // Create polyhedron
193  EntityHandle polyhedron;
194  MB_CHK_ERR( mb->create_element( MBPOLYHEDRON, polyhedronConn, 2 + num_nodes, polyhedron ) );
195  }
196  }
197  MB_CHK_ERR( mb->write_file( output.c_str() ) );
198 
199  delete mb;
200 
201  return 0;
202 }