TexGen
TetgenMesh.cpp
Go to the documentation of this file.
1/*=============================================================================
2TexGen: Geometric textile modeller.
3Copyright (C) 2010 Louise Brown
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18=============================================================================*/
19
20#include "PrecompiledHeaders.h"
21#include "TexGen.h"
22
23extern "C"
24{
25#include "../Triangle/triangle.h"
26#include "../Triangle/triangle_api.h"
27}
28
29using namespace TexGen;
30using namespace std;
31
32CTetgenMesh::CTetgenMesh(double Seed) : CMeshDomainPlane(Seed)
33{
34
35}
36
38{
39}
40
41void CTetgenMesh::SaveTetgenMesh( CTextile &Textile, string OutputFilename, string Parameters, bool bPeriodic, int FileType )
42{
43 tetgenio::facet *f;
44 tetgenio::polygon *p;
45
46 pair<XYZ, XYZ> DomainAABB;
47 XYZ P;
48
49 if ( !Textile.AddSurfaceToMesh( m_Mesh, m_DomainMeshes, true ) )
50 {
51 TGERROR("Error creating surface mesh. Cannot generate tetgen mesh");
52 return;
53 }
55
56 MeshDomainPlanes( bPeriodic );
57
58 m_in.numberoffacets = (int)m_Mesh.GetNumElements() + (int)m_DomainMeshes.size();
59 m_in.facetlist = new tetgenio::facet[m_in.numberoffacets];
60
61 // Add facets for yarn elements
62 list<int>::const_iterator itIter;
63
64 int i = 0;
65 for ( int j = 0; j < CMesh::NUM_ELEMENT_TYPES; ++j)
66 {
67 const list<int> &Indices = m_Mesh.GetIndices((CMesh::ELEMENT_TYPE)j);
68 int iNumNodes = CMesh::GetNumNodes((CMesh::ELEMENT_TYPE)j);
69 for (itIter = Indices.begin(); itIter != Indices.end(); )
70 {
71 if ( j == CMesh::QUAD || j == CMesh::TRI ) // For the moment assume that all surface elements are quad or tri
72 {
73 f = &m_in.facetlist[i];
74 f->numberofpolygons = 1;
75 f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
76 f->numberofholes = 0;
77 f->holelist = NULL;
78 p = &f->polygonlist[0];
79 p->numberofvertices = iNumNodes;
80 p->vertexlist = new int[p->numberofvertices];
81 for ( int iNode = 0; iNode < iNumNodes; ++iNode )
82 {
83 p->vertexlist[iNode] = *(itIter++) + 1;
84 }
85 ++i;
86 }
87 else
88 {
89 break;
90 }
91 }
92 }
93
94 // Add facets for domain planes
95 if ( bPeriodic )
96 {
97 vector<CMesh>::iterator itTriangulatedMeshes;
98 for ( itTriangulatedMeshes = m_TriangulatedMeshes.begin(); itTriangulatedMeshes != m_TriangulatedMeshes.end(); ++itTriangulatedMeshes )
99 {
100 const list<int> &TriIndices = itTriangulatedMeshes->GetIndices(CMesh::TRI);
101 list<int>::const_iterator itTriIndices;
102
103 int iNodeOffset = m_Mesh.GetNumNodes(); // Adding domain plane points to m_Mesh so need to continue from current max index
104 int iNumNodes = 3;
105
106 f = &m_in.facetlist[i];
107 f->numberofpolygons = (int)TriIndices.size()/iNumNodes;
108 f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
109 f->numberofholes = 0;
110 f->holelist = NULL;
111
112 int iList = 0;
113
114 int PolyInd = 0;
115 for (itTriIndices = TriIndices.begin(); itTriIndices != TriIndices.end(); )
116 {
117 p = &f->polygonlist[PolyInd++];
118 p->numberofvertices = iNumNodes;
119 p->vertexlist = new int[p->numberofvertices];
120
121 for ( int iNode = 0; iNode < p->numberofvertices; ++iNode )
122 {
123 XYZ Point = itTriangulatedMeshes->GetNode( *(itTriIndices++) );
124 int ind = m_Mesh.GetClosestNodeDistance( Point, 0.000001);
125 if ( ind == -1 ) // Add node if not in mesh yet
126 {
127 m_Mesh.AddNode( Point );
128 p->vertexlist[iNode] = m_Mesh.GetNumNodes();
129 }
130 else // Add existing node index to vertex list
131 p->vertexlist[iNode] = ind + 1;
132 }
133 }
134 ++i;
135 }
136 }
137 else // if not periodic need to add quad for domain edge and point for any polygons intersecting domain plane
138 { // currently assuming prism domains are not periodic
139 int iFace = 0;
140 vector<CMesh>::iterator itDomainMeshes;
141 for ( itDomainMeshes = m_DomainMeshes.begin(); itDomainMeshes != m_DomainMeshes.end(); ++itDomainMeshes )
142 {
143 const list<int> &QuadIndices = itDomainMeshes->GetIndices(CMesh::QUAD);
144 const list<int> &PolygonIndices = itDomainMeshes->GetIndices(CMesh::POLYGON);
145 list<int>::const_iterator itQuadIndices;
146 list<int>::const_iterator itPolygonIndices;
147
148
149 int iNodeOffset = m_Mesh.GetNumNodes();
150
151 f = &m_in.facetlist[i];
152 if ( PolygonIndices.empty() ) // Just a quad with no yarns crossing
153 f->numberofpolygons = 1;
154 else // either a quad with yarns crossing or a prism domain polygon with/without yarns crossing
155 {
156 if (QuadIndices.empty()) // Prism domain
157 f->numberofpolygons = (int)m_PolygonNumVertices[iFace].size(); // Number of polygons (1 prism outline + any yarns crossing)
158 else
159 f->numberofpolygons = (int)m_PolygonNumVertices[iFace].size() + 1; // Number of polygons + the quad
160 }
161 f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
162 f->numberofholes = 0;
163 f->holelist = NULL;
164
165 int iList = 0;
166
167 int PolyInd = 0;
168 // Add quad points
169 for (itQuadIndices = QuadIndices.begin(); itQuadIndices != QuadIndices.end(); )
170 {
171 p = &f->polygonlist[PolyInd++];
172 p->numberofvertices = 4;
173 p->vertexlist = new int[p->numberofvertices];
174
175 for ( int iNode = 0; iNode < p->numberofvertices; ++iNode )
176 {
177 XYZ Point = itDomainMeshes->GetNode( *(itQuadIndices++) );
178 int ind = m_Mesh.GetClosestNodeDistance( Point, 0.000001);
179 if ( ind == -1 ) // Add node if not in mesh yet
180 {
181 m_Mesh.AddNode( Point );
182 p->vertexlist[iNode] = m_Mesh.GetNumNodes();
183 }
184 else // Add existing node index to vertex list
185 p->vertexlist[iNode] = ind + 1;
186 }
187 }
188
189 // Add polygon points
190 if ( !PolygonIndices.empty() )
191 {
192 vector<int>::iterator itNumVertices = m_PolygonNumVertices[iFace].begin();
193 for (itPolygonIndices = PolygonIndices.begin(); itPolygonIndices != PolygonIndices.end(); )
194 {
195 p = &f->polygonlist[PolyInd++];
196 p->numberofvertices = *(itNumVertices++);
197 p->vertexlist = new int[p->numberofvertices];
198
199 for ( int iNode = 0; iNode < p->numberofvertices; ++iNode )
200 {
201 XYZ Point = itDomainMeshes->GetNode( *(itPolygonIndices++) );
202 int ind = m_Mesh.GetClosestNodeDistance( Point, 0.000001);
203 if ( ind == -1 ) // Add node if not in mesh yet
204 {
205 m_Mesh.AddNode( Point );
206 p->vertexlist[iNode] = m_Mesh.GetNumNodes();
207 }
208 else // Add existing node index to vertex list
209 p->vertexlist[iNode] = ind + 1;
210 }
211 }
212 ++iFace;
213 }
214 ++i;
215
216 }
217 }
218
219 // Add the mesh nodes to the tetgen point list
220 // All indices start from 1.
221 m_in.firstnumber = 1;
222 m_in.numberofpoints = m_Mesh.GetNumNodes();
223
224 m_in.pointlist = new REAL[m_in.numberofpoints * 3];
225
226 vector<XYZ>::iterator itNode;
227 int iNodeInd = 0;
228 for ( itNode = m_Mesh.NodesBegin(); itNode != m_Mesh.NodesEnd(); ++itNode )
229 {
230 m_in.pointlist[iNodeInd++] = (*itNode).x;
231 m_in.pointlist[iNodeInd++] = (*itNode).y;
232 m_in.pointlist[iNodeInd++] = (*itNode).z;
233 }
234
235 string strOutput;
236 string strInput;
237 int size = (int)OutputFilename.length();
238
239 char* TetgenOutput = new char[size];
240 char* TetgenInput = new char[size+5];
241 if (FileType == INP_EXPORT)
242 strOutput = RemoveExtension( OutputFilename, ".inp" );
243 else
244 strOutput = RemoveExtension(OutputFilename, ".vtu");
245 strInput = strOutput + "Input";
246 strcpy(TetgenOutput, strOutput.c_str());
247 strcpy( TetgenInput, strInput.c_str());
248
249 m_in.save_nodes(TetgenInput);
250 m_in.save_poly(TetgenInput);
251 delete [] TetgenInput;
252
253 // Check the input mesh first
254 try
255 {
256 tetrahedralize((char *)"d", &m_in, &m_out);
257 }
258 catch(...)
259 {
260 TGERROR("Tetrahedralize failed. Intersections in PLC");
261 return;
262 }
263 // Then create the mesh
264 try
265 {
266 tetrahedralize((char*)Parameters.c_str(), &m_in, &m_out);
267 }
268 catch(...)
269 {
270 TGERROR("Tetrahedralize failed. No mesh generated");
271 TGERROR(Parameters);
272 return;
273 }
274
275 // Output mesh to files 'barout.node', 'barout.ele' and 'barout.face'.
276 m_out.save_nodes(TetgenOutput);
277 m_out.save_elements(TetgenOutput);
278 m_out.save_faces(TetgenOutput);
279 delete [] TetgenOutput;
280
281 SaveMesh( Textile );
282 if (FileType == INP_EXPORT)
283 SaveToAbaqus(OutputFilename, Textile);
284 else
285 SaveToVTK(OutputFilename);
286}
287
289{
291
292 // Store output mesh in CMesh
293 for (int i = 0; i < m_out.numberofpoints * 3; ) // Three REALs in pointlist for each point
294 {
295 XYZ Point;
296 Point.x = m_out.pointlist[i++];
297 Point.y = m_out.pointlist[i++];
298 Point.z = m_out.pointlist[i++];
299 m_OutputMesh.AddNode(Point);
300 }
301
302 CMesh::ELEMENT_TYPE ElementType = m_out.numberofcorners == 4 ? CMesh::TET : CMesh::QUADRATIC_TET;
303 int quad_tet_ind[10] = {0, 1, 2, 3, 6, 7, 9, 5, 8, 4};
304
305 for (int i = 0; i < m_out.numberoftetrahedra; i++)
306 {
307 vector<int> Indices;
308 for ( int j = 0; j < m_out.numberofcorners; j++ )
309 {
310 if (ElementType == CMesh::TET)
311 {
312 Indices.push_back( m_out.tetrahedronlist[i*m_out.numberofcorners + j]-1 ); // Tetgen indices start from 1
313 }
314 else
315 {
316 Indices.push_back( m_out.tetrahedronlist[i*m_out.numberofcorners + quad_tet_ind[j]] -1);
317 }
318 }
319 m_OutputMesh.AddElement(ElementType, Indices);
320 }
321
323}
324
325void CTetgenMesh::SaveToAbaqus( string Filename, CTextile &Textile )
326{
327 m_OutputMesh.SaveToABAQUS( Filename, &m_ElementsInfo, false, false );
328
329}
330
331void CTetgenMesh::SaveToVTK(string Filename)
332{
333 CMeshData<char> YarnIndex("YarnIndex", CMeshDataBase::ELEMENT);
334 CMeshData<XYZ> YarnTangent("YarnTangent", CMeshDataBase::ELEMENT);
335 CMeshData<XY> Location("Location", CMeshDataBase::ELEMENT);
336 CMeshData<double> VolumeFraction("VolumeFraction", CMeshDataBase::ELEMENT);
337 CMeshData<double> SurfaceDistance("SurfaceDistance", CMeshDataBase::ELEMENT);
338 CMeshData<XYZ> Orientation("Orientation", CMeshDataBase::ELEMENT);
339
340 vector<POINT_INFO>::const_iterator itPointInfo;
341 for (itPointInfo = m_ElementsInfo.begin(); itPointInfo != m_ElementsInfo.end(); ++itPointInfo)
342 {
343 YarnIndex.m_Data.push_back(itPointInfo->iYarnIndex);
344 YarnTangent.m_Data.push_back(itPointInfo->YarnTangent);
345 Location.m_Data.push_back(itPointInfo->Location);
346 VolumeFraction.m_Data.push_back(itPointInfo->dVolumeFraction);
347 SurfaceDistance.m_Data.push_back(itPointInfo->dSurfaceDistance);
348 Orientation.m_Data.push_back(itPointInfo->Orientation);
349 }
350
351 vector<CMeshDataBase*> MeshData;
352
353 MeshData.push_back(&YarnIndex);
354 MeshData.push_back(&YarnTangent);
355 MeshData.push_back(&Location);
356 MeshData.push_back(&VolumeFraction);
357 MeshData.push_back(&SurfaceDistance);
358 MeshData.push_back(&Orientation);
359
360 m_OutputMesh.SaveToVTK( Filename, &MeshData );
361}
#define TGERROR(MESSAGE)
Macros used to report the file name and line number to the TexGenError and TexGenLog functions.
Definition: Logger.h:29
#define NULL
Definition: ShinyConfig.h:50
vector< T > m_Data
Definition: MeshData.h:87
void MeshDomainPlanes(bool bPeriodic)
vector< vector< int > > m_PolygonNumVertices
Number of polygon vertices on each face. Number of outer vector members = number of faces.
vector< CMesh > m_DomainMeshes
Vector of meshes used to store domain plane meshes.
vector< CMesh > m_TriangulatedMeshes
Vector of triangulated domain plane meshes.
bool AddElement(ELEMENT_TYPE Type, const vector< int > &Indices)
Add an element to the mesh of given type with node number checking.
Definition: Mesh.cpp:2565
int GetNumNodes() const
Return the number of nodes.
Definition: Mesh.cpp:2646
void ConvertQuadstoTriangles(bool bQuality=true)
Convert the quad elements to triangles.
Definition: Mesh.cpp:1088
bool SaveToABAQUS(string Filename, const vector< POINT_INFO > *pElementInfo=NULL, bool bCreateStep=true, bool bCreateMaterial=true, int iElementType=0)
Save the mesh to ABAQUS input file format with information such as yarn tangents.
Definition: Mesh.cpp:2089
const int AddNode(XYZ Node)
Append a node to the list of nodes, the integer returns the index of the node
Definition: Mesh.cpp:2624
vector< XYZ > GetElementCenters() const
Get a vector of element centers, one entry for each element.
Definition: Mesh.cpp:1549
bool SaveToVTK(string Filename, const vector< CMeshDataBase * > *pMeshData=NULL) const
Save the mesh to VTK unstructured grid file format (.vtu)
Definition: Mesh.cpp:2348
static int GetNumNodes(ELEMENT_TYPE Type)
Get the number of nodes a particular element type contains.
Definition: Mesh.h:81
const list< int > & GetIndices(ELEMENT_TYPE ElemType) const
Get the element indices of a given element type.
Definition: Mesh.cpp:2671
ELEMENT_TYPE
Each element type is represented by a unique integer value.
Definition: Mesh.h:66
@ NUM_ELEMENT_TYPES
Definition: Mesh.h:77
@ QUADRATIC_TET
Definition: Mesh.h:75
@ POLYGON
Definition: Mesh.h:76
int GetNumElements(ELEMENT_TYPE Type) const
Get the number of elements of a given type.
Definition: Mesh.cpp:2586
int GetClosestNodeDistance(XYZ Position, double dTol) const
Get the index of the node within a given tolerance distance to the given position space.
Definition: Mesh.cpp:550
void Clear()
Empty mesh nodes and indices.
Definition: Mesh.cpp:1448
CMesh m_Mesh
Mesh used to store input node points and elements.
Definition: TetgenMesh.h:52
void SaveToVTK(string Filename)
Save output mesh to VTK format.
Definition: TetgenMesh.cpp:331
tetgenio m_in
Tetgen input and output structures.
Definition: TetgenMesh.h:54
void SaveTetgenMesh(CTextile &Textile, string OutputFilename, string Parameters, bool bPeriodic, int FileType)
Save a textile as a tetrahedralized mesh using Tetgen.
Definition: TetgenMesh.cpp:41
vector< POINT_INFO > m_ElementsInfo
Element information for output mesh.
Definition: TetgenMesh.h:58
CMesh m_OutputMesh
Mesh used to store output nodes and elements.
Definition: TetgenMesh.h:56
void SaveToAbaqus(string Filename, CTextile &Textile)
Save output mesh to Abaqus export file.
Definition: TetgenMesh.cpp:325
virtual ~CTetgenMesh(void)
Definition: TetgenMesh.cpp:37
void SaveMesh(CTextile &Textile)
Save tetgenio data to CMesh.
Definition: TetgenMesh.cpp:288
Represents a textile cell containing yarns.
Definition: Textile.h:39
void AddSurfaceToMesh(CMesh &Mesh, bool bTrimToDomain=false)
Create surface mesh for this textile and add it to the mesh object.
Definition: Textile.cpp:187
void GetPointInformation(const vector< XYZ > &Points, vector< POINT_INFO > &PointsInfo, double dTolerance=1e-9)
Get useful information of a list of points.
Definition: Textile.cpp:410
Namespace containing a series of customised math operations not found in the standard c++ library.
std::string RemoveExtension(std::string &Filename, std::string Extension)
Strip the extension from the filename.
Definition: Misc.cpp:122
@ INP_EXPORT
Definition: Misc.h:113
Struct for representing points in 3D space.
Definition: mymath.h:56
double z
Definition: mymath.h:57
double x
Definition: mymath.h:57
double y
Definition: mymath.h:57