TexGen
Mesher.cpp
Go to the documentation of this file.
1/*=============================================================================
2TexGen: Geometric textile modeller.
3Copyright (C) 2006 Martin Sherburn
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 "Mesher.h"
22#include "TexGen.h"
23#include "PeriodicBoundaries.h"
24//#include "Yarn.h"
25extern "C"
26{
27#include "../Triangle/triangle.h"
28}
29
30using namespace TexGen;
31CMesher::CMesher( int iBoundaryConditions )
32: m_bHybrid(false)
33, m_bQuadratic(false)
34, m_bProjectMidSideNodes(true)
35, m_dLayerMergeTolerance(1e-3)
36, m_iBoundaryConditions(iBoundaryConditions)
37{
38 switch( iBoundaryConditions )
39 {
43 break;
44 case SHEARED_BC:
46 break;
48 default:
50 break;
51 }
52}
53
55{
57 {
59 }
60}
61
62bool CMesherBase::CreateMesh(string TextileName)
63{
64 CTextile* pTextile = TEXGEN.GetTextile(TextileName);
65 if (pTextile)
66 return CreateMesh(*pTextile);
67 else
68 return false;
69}
70
72{
73 m_ProjectedNodes.clear();
74
75 if (!CreateBasicVolumes(Textile))
76 return false;
77
78 TGLOG("Meshing basic volumes in 3D");
79 CreateVolumeMesh(Textile);
80
81 TGLOG("Getting element data");
83
84 if (m_bQuadratic)
85 {
86 TGLOG("Converting mesh to quadratic");
89 {
91 }
92 }
93
94 TGLOG("Meshing complete with " << m_VolumeMesh.GetNumElements() << " elements and " << m_VolumeMesh.GetNumNodes() << " nodes");
95
96// SaveVolumeMeshToVTK("Volume");
97
98 return true;
99}
100
101void CMesher::SaveVolumeMeshToVTK(string Filename)
102{
103 TGLOG("Save Volume Mesh to VTK");
104 CMeshData<unsigned short> RegionIndex("RegionIndex", CMeshDataBase::ELEMENT);
106 CMeshData<char> YarnIndex("YarnIndex", CMeshDataBase::ELEMENT);
107 CMeshData<XYZ> YarnTangent("YarnTangent", CMeshDataBase::ELEMENT);
108 CMeshData<XY> Location("Location", CMeshDataBase::ELEMENT);
109 CMeshData<double> VolumeFraction("VolumeFraction", CMeshDataBase::ELEMENT);
110 CMeshData<double> SurfaceDistance("SurfaceDistance", CMeshDataBase::ELEMENT);
111 CMeshData<XYZ> Orientation("Orientation", CMeshDataBase::ELEMENT);
112
113 list<MESHER_ELEMENT_DATA>::iterator itElemData;
114 int i;
115 for (i = 0; i < CMesh::NUM_ELEMENT_TYPES; ++i)
116 {
117 for (itElemData = m_ElementData[i].begin(); itElemData != m_ElementData[i].end(); ++itElemData)
118 {
119 RegionIndex.m_Data.push_back(itElemData->iRegion);
120 Layer.m_Data.push_back(itElemData->iLayer);
121 YarnIndex.m_Data.push_back(itElemData->iYarnIndex);
122 YarnTangent.m_Data.push_back(itElemData->YarnTangent);
123 Location.m_Data.push_back(itElemData->Location);
124 VolumeFraction.m_Data.push_back(itElemData->dVolumeFraction);
125 SurfaceDistance.m_Data.push_back(itElemData->dSurfaceDistance);
126 Orientation.m_Data.push_back(itElemData->Orientation);
127 }
128 }
129
130 vector<CMeshDataBase*> MeshData;
131
132 MeshData.push_back(&RegionIndex);
133 MeshData.push_back(&Layer);
134 MeshData.push_back(&YarnIndex);
135 MeshData.push_back(&YarnTangent);
136 MeshData.push_back(&Location);
137 MeshData.push_back(&VolumeFraction);
138 MeshData.push_back(&SurfaceDistance);
139 MeshData.push_back(&Orientation);
140
141 TGLOG("Calling SaveToVTK");
142 m_VolumeMesh.SaveToVTK(Filename, &MeshData);
143}
144
145void CMesher::SaveVolumeMeshToABAQUS(string Filename, string TextileName )
146{
147 CTextile* pTextile = TEXGEN.GetTextile(TextileName);
148 if ( pTextile == NULL )
149 {
150 TGERROR("Cannot save to ABAQUS: no textile created");
151 return;
152 }
153 SaveVolumeMeshToABAQUS( Filename, *pTextile );
154}
155
156void CMesher::SaveVolumeMeshToABAQUS(string Filename, CTextile& Textile )
157{
158 TGLOG("Replacing spaces in filename with underscore for ABAQUS compatibility");
159 Filename = ReplaceFilenameSpaces( Filename );
160 vector<POINT_INFO> ElementsInfo;
161 POINT_INFO Info;
162 list<MESHER_ELEMENT_DATA>::const_iterator itData;
163 int i;
164
165 for (i = 0; i < CMesh::NUM_ELEMENT_TYPES; ++i)
166 {
167 for (itData = m_ElementData[i].begin(); itData != m_ElementData[i].end(); ++itData)
168 {
169 Info.iYarnIndex = itData->iYarnIndex;
170 Info.Location = itData->Location;
171 Info.YarnTangent = itData->YarnTangent;
172 Info.dVolumeFraction = itData->dVolumeFraction;
173 Info.dSurfaceDistance = itData->dSurfaceDistance;
174 Info.Orientation = itData->Orientation;
175 Info.Up = itData->Up;
176
177 ElementsInfo.push_back(Info);
178 }
179 }
180 m_VolumeMesh.SaveToABAQUS(Filename, &ElementsInfo, false, false);
181
182 ofstream Output(Filename.c_str(), ofstream::app );
183 // Output material properties
185 m_Materials->SetupMaterials( Textile );
186 m_Materials->OutputMaterials( Output, Textile.GetNumYarns(), false );
187 delete( m_Materials );
188
190 {
192 if (SaveNodeSets() )
193 {
194 //ofstream Output(Filename.c_str(), ofstream::app );
195 Output << "*****************" << endl;
196 Output << "*** NODE SETS ***" << endl;
197 Output << "*****************" << endl;
198 Output << "** AllNodes - Node set containing all elements" << endl;
199 Output << "*NSet, NSet=AllNodes, Generate" << endl;
200 Output << "1, " << m_VolumeMesh.GetNumNodes() << ", 1" << endl;
202 }
203 else
204 TGERROR("Unable to generate node sets");
205 }
206}
207
209{
210 int iNumNodes = (int)m_ProjectedMesh.GetNumNodes();
211 m_ProjectedNodes.clear();
212 m_ProjectedNodes.resize(iNumNodes);
213
214 NODE_PAIR_SETS EdgeNodePairSets;
215 const vector<XYZ> &Repeats = Textile.GetYarn(0)->GetRepeats();
216
217 if ( m_bCreatePeriodic )
218 {
219 // Find matching nodes on opposite edges of domain
220 vector<XYZ>::const_iterator itRepeat;
221
222 for (itRepeat=Repeats.begin(); itRepeat!=Repeats.end(); ++itRepeat)
223 {
224 NODE_PAIR_SET NodePairs;
225 m_ProjectedMesh.GetNodePairs(*itRepeat, NodePairs, 1e-5);
226 SortPairs( NodePairs, (*itRepeat).y == 0 ? true:false ); // If pairs with constant x, sort by y
227 EdgeNodePairSets.push_back( NodePairs );
228 }
229 }
230
231
232 int i, j;
233 set<int> CornerIndex;
234 for (i=0; i<iNumNodes; ++i)
235 {
237 if ( m_bCreatePeriodic )
238 {
239 // Set up so that columns of nodes on opposite faces match
240 if ( m_ProjectedNodes[i].RaisedNodes.empty() ) // Might already have been filled if RaiseNode was called for node on opposite face
241 {
242 set<int> PairIndices;
243 RaiseNodes(i);
244 GetEdgePairIndices(EdgeNodePairSets, i, PairIndices); // Find matching nodes on opposite sides of domain. If it's a corner will return all 4 nodes
245 if ( !PairIndices.empty() ) // If found matching pairs add them to the projected nodes array
246 {
247 if ( PairIndices.size() == 4 )
248 CornerIndex = PairIndices;
249 set<int>::iterator itPairIndices;
250 for ( itPairIndices = PairIndices.begin(); itPairIndices != PairIndices.end(); ++itPairIndices )
251 {
252 if ( *itPairIndices != i )
253 m_ProjectedNodes[*itPairIndices].RaisedNodes = m_ProjectedNodes[i].RaisedNodes;
254 }
255 }
256 }
257 }
258 else
259 {
260 RaiseNodes(i);
261 }
262 }
263
265 int iIndexCount=0;
266 XYZ Pos;
267 for (i=0; i<iNumNodes; ++i)
268 {
269 pair<int,vector<int> > ProjectedVolumeNode;
270 vector<int> VolumeNodes;
271 ProjectedVolumeNode.first = i;
272 Pos = m_ProjectedNodes[i].Position;
273 vector<RAISED_NODE> &RaisedNodes = m_ProjectedNodes[i].RaisedNodes;
274 int iRaisedNum = (int)RaisedNodes.size();
275 for (j=0; j<iRaisedNum; ++j)
276 {
277 RaisedNodes[j].iIndex = iIndexCount++;
278 Pos.z = RaisedNodes[j].dZ;
280 }
281 }
282
284 {
285 CreateNodeSets( EdgeNodePairSets, CornerIndex, Repeats );
286 }
287
288 list<int>::iterator itIndex;
289 list<int> &Indices = m_ProjectedMesh.GetIndices(CMesh::TRI);
290 int iRegion;
291 for (i = 0; i < CMesh::NUM_ELEMENT_TYPES; ++i)
292 {
293 m_ElementData[i].clear();
294 }
295 m_EdgeConstraints.clear();
296 TRIANGLE Tri;
297 for (itIndex = Indices.begin(), i=0; itIndex != Indices.end(); ++i)
298 {
299 for (j=0; j<3; ++j)
300 Tri.i[j] = *(itIndex++);
301 iRegion = m_TriangleRegions[i];
302 MeshColumn(Tri, iRegion);
303 }
304
305}
306
307void CMesher::RaiseNodes(int iIndex)
308{
309 set<int> YarnIndices;
310 insert_iterator<set<int> > iiYarnIndices(YarnIndices, YarnIndices.end());
311 set<int>::iterator itYarnIndex;
312
313 list<int>::iterator itIndex;
314 list<int> &Indices = m_ProjectedMesh.GetIndices(CMesh::TRI);
315 int i, j, iNode, iRegion;
316
317 // Find projected triangles which have node (iIndex) as a corner
318 for (itIndex = Indices.begin(), i=0; itIndex != Indices.end(); ++i)
319 {
320 for (j=0; j<3; ++j)
321 {
322 iNode = *(itIndex++);
323 if (iNode == iIndex)
324 {
325 iRegion = m_TriangleRegions[i];
326 copy(m_ProjectedRegions[iRegion].YarnIndices.begin(), m_ProjectedRegions[iRegion].YarnIndices.end(), iiYarnIndices);
327 }
328 }
329 }
330
331 // Get the domain bounds
332 XYZ Point = m_ProjectedMesh.GetNode(iIndex);
333 pair<double, double> DomainBounds(0,0);
334 bool bFound = GetMeshVerticalBounds(m_DomainMesh, Point, DomainBounds.first, DomainBounds.second, true);
335 assert(bFound);
336
337 // Get the yarn bounds
338 map<int, pair<double, double> > YarnBounds;
339 for (itYarnIndex=YarnIndices.begin(); itYarnIndex!=YarnIndices.end(); ++itYarnIndex)
340 {
341 pair<double, double> Bounds(0,0);
342 bool bFound = GetMeshVerticalBounds(m_YarnMeshes[*itYarnIndex], Point, Bounds.first, Bounds.second, true);
343 assert(bFound);
344 //if ( bFound )
345 YarnBounds[*itYarnIndex] = Bounds;
346 }
347
348 // Remove overlaps that may exist between yarn boundaries
349 map<int, pair<double, double> >::iterator itYarnBound, itCompareBound;
350 pair<double, double> *pAbove, *pBelow;
351 double dAverage;
352 for (itYarnBound = YarnBounds.begin(); itYarnBound != YarnBounds.end(); ++itYarnBound)
353 {
354 // Make sure all the yarns fit within the domain
355 if (itYarnBound->second.first < DomainBounds.first)
356 itYarnBound->second.first = DomainBounds.first;
357 if (itYarnBound->second.second > DomainBounds.second)
358 itYarnBound->second.second = DomainBounds.second;
359 // Make sure the yarns don't overlap each other
360 for (itCompareBound = itYarnBound, ++itCompareBound; itCompareBound != YarnBounds.end(); ++itCompareBound)
361 {
362 if (itYarnBound->second.first+itYarnBound->second.second > // Check which yarn is on top
363 itCompareBound->second.first+itCompareBound->second.second)
364 {
365 pAbove = &itYarnBound->second;
366 pBelow = &itCompareBound->second;
367 }
368 else
369 {
370 pAbove = &itCompareBound->second;
371 pBelow = &itYarnBound->second;
372 }
373
374 dAverage = 0.5*(pAbove->first + pBelow->second); // Average of overlapping edges
375
376 pAbove->first = max(pAbove->first, dAverage);
377 pAbove->second = max(pAbove->second, dAverage);
378
379 pBelow->first = min(pBelow->first, dAverage);
380 pBelow->second = min(pBelow->second, dAverage);
381 }
382 }
383
384 // Domain bounds
385 {
386 RAISED_NODE RaisedNode;
387// RaisedNode.YarnBoundaryIndices.push_back(-1); // Not really necessary, and seems to be causing some bugs...
388 RaisedNode.dZ = DomainBounds.first;
389 m_ProjectedNodes[iIndex].RaisedNodes.push_back(RaisedNode);
390 RaisedNode.dZ = DomainBounds.second;
391 m_ProjectedNodes[iIndex].RaisedNodes.push_back(RaisedNode);
392 }
393 // Yarn bounds
394 for (itYarnBound = YarnBounds.begin(); itYarnBound != YarnBounds.end(); ++itYarnBound)
395 {
396 RAISED_NODE RaisedNode;
397 RaisedNode.YarnBoundaryIndices.push_back(itYarnBound->first);
398 RaisedNode.dZ = itYarnBound->second.first;
399 m_ProjectedNodes[iIndex].RaisedNodes.push_back(RaisedNode);
400 RaisedNode.dZ = itYarnBound->second.second;
401 m_ProjectedNodes[iIndex].RaisedNodes.push_back(RaisedNode);
402 }
403
404 SubdivideNodes(iIndex);
405}
406
408{
409 PROJECTED_NODE &ProjectedNode = m_ProjectedNodes[iIndex];
410 // Sort the nodes in ascending order of Z
411 sort(ProjectedNode.RaisedNodes.begin(), ProjectedNode.RaisedNodes.end());
412
413 double dZ1, dZ2;
414 int i, j;
415 bool bBottom, bTop;
416 for (i=0; i<(int)ProjectedNode.RaisedNodes.size()-1; )
417 {
418 dZ1 = ProjectedNode.RaisedNodes[i].dZ;
419 dZ2 = ProjectedNode.RaisedNodes[i+1].dZ;
420 // Is Node1 the bottom-most node?
421 bBottom = (i == 0);
422 // Is Node2 the top-most node?
423 bTop = (i == (int)ProjectedNode.RaisedNodes.size()-2);
424 // Merge the boundaries that are less than a certain tolerance
425 if (abs(dZ1 - dZ2) < m_dLayerMergeTolerance && !(bBottom && bTop))
426 {
427 ProjectedNode.RaisedNodes[i].bMerged = true;
428 if (bBottom)
429 ProjectedNode.RaisedNodes[i].dZ = dZ1;
430 else if (bTop)
431 ProjectedNode.RaisedNodes[i].dZ = dZ2;
432 else
433 ProjectedNode.RaisedNodes[i].dZ = 0.5*(dZ1+dZ2);
434 for (j=0; j<(int)ProjectedNode.RaisedNodes[i+1].YarnBoundaryIndices.size(); ++j)
435 {
436 ProjectedNode.RaisedNodes[i].YarnBoundaryIndices.push_back(
437 ProjectedNode.RaisedNodes[i+1].YarnBoundaryIndices[j]);
438 }
439 ProjectedNode.RaisedNodes.erase(ProjectedNode.RaisedNodes.begin()+i+1);
440 }
441 else
442 {
443 ++i;
444 }
445 }
446
447 // Divide these nodes up some..
448// double dSeed = m_dSeed;
449 double dSeed = GetBestSeed(iIndex);
450 double dNumDivs;
451 int iNumDivisions;
452 RAISED_NODE RaisedNode;
453 int iSize = (int)ProjectedNode.RaisedNodes.size();
454 for (i=0; i<iSize-1; ++i)
455 {
456 dZ1 = ProjectedNode.RaisedNodes[i].dZ;
457 dZ2 = ProjectedNode.RaisedNodes[i+1].dZ;
458 dNumDivs = (dZ2-dZ1)/dSeed;
459 iNumDivisions = int(dNumDivs);
460 if (dNumDivs-iNumDivisions > 0.5)
461 ++iNumDivisions;
462 for (j=0; j<iNumDivisions-1; ++j)
463 {
464 RaisedNode.dZ = dZ1 + (j+1)*((dZ2-dZ1)/iNumDivisions);
465 ProjectedNode.RaisedNodes.push_back(RaisedNode);
466 }
467 }
468
469 // Sort in the new nodes that where just pushed in on the end
470 sort(ProjectedNode.RaisedNodes.begin(), ProjectedNode.RaisedNodes.end());
471}
472
473double CMesher::GetBestSeed(int iIndex)
474{
475 list<int>::iterator itIndex;
476 list<int> &Indices = m_ProjectedMesh.GetIndices(CMesh::TRI);
477 int iCorner[3];
478 int i;
479 double dEdgeLength = 0;
480 int iNumEdges = 0;
481 for (itIndex = Indices.begin(), i=0; itIndex != Indices.end(); ++i)
482 {
483 for (i=0; i<3; ++i)
484 {
485 iCorner[i] = *(itIndex++);
486 }
487 for (i=0; i<3; ++i)
488 {
489 if (iCorner[i] == iIndex)
490 {
491 dEdgeLength += GetLength(m_ProjectedMesh.GetNode(iCorner[i]), m_ProjectedMesh.GetNode(iCorner[(i+1)%3]));
492 dEdgeLength += GetLength(m_ProjectedMesh.GetNode(iCorner[i]), m_ProjectedMesh.GetNode(iCorner[(i+2)%3]));
493 ++iNumEdges;
494 ++iNumEdges;
495 }
496 }
497 }
498 double dSeed = m_dSeed;
499 if (iNumEdges)
500 dSeed = dEdgeLength/iNumEdges;
501 return dSeed;
502}
503
504void CMesher::MeshColumn(TRIANGLE Triangle, int iRegion)
505{
506 vector<int> &YarnIndices = m_ProjectedRegions[iRegion].YarnIndices;
507 vector<vector<RAISED_NODE> > Column1, Column2, Column3;
508 // Split each column into a number of smaller columns standing on top of each
509 // other separated by the yarn boundaries
510 SplitColumn(m_ProjectedNodes[Triangle.i[0]], YarnIndices, Column1);
511 SplitColumn(m_ProjectedNodes[Triangle.i[1]], YarnIndices, Column2);
512 SplitColumn(m_ProjectedNodes[Triangle.i[2]], YarnIndices, Column3);
513 int i, iNumLayers = YarnIndices.size()*2+1;
514 MESHER_ELEMENT_DATA ElemData;
515 ElemData.iRegion = iRegion;
516 int iTopYarnIndex, iBottomYarnIndex;
517 for (i=0; i<iNumLayers; ++i)
518 {
519 ElemData.iLayer = i;
520 if (i%2 == 0)
521 {
522 ElemData.iYarnIndex = -1;
523 iBottomYarnIndex = -1;
524 iTopYarnIndex = -1;
525 if (i>0)
526 iBottomYarnIndex = YarnIndices[(i/2)-1];
527 if (i/2<(int)YarnIndices.size())
528 iTopYarnIndex = YarnIndices[i/2];
529 }
530 else
531 {
532 iBottomYarnIndex = iTopYarnIndex = ElemData.iYarnIndex = YarnIndices[i/2];
533 }
534 vector<RAISED_NODE> Columns[3];
535 Columns[0] = Column1[i];
536 Columns[1] = Column2[i];
537 Columns[2] = Column3[i];
538 if (m_bQuadratic && m_bProjectMidSideNodes && iBottomYarnIndex==iTopYarnIndex && iBottomYarnIndex!=-1)
539 BuildMidSideNodes(Columns, iBottomYarnIndex);
540 set<pair<int, int> > EdgeConstraints[3];
541 BuildEdgeConstraints(Columns, EdgeConstraints);
542 int iNumTets = TetMeshColumn(Columns, EdgeConstraints);
543 m_ElementData[CMesh::TET].resize(m_ElementData[CMesh::TET].size()+iNumTets, ElemData);
544/* int iNumTets = m_VolumeMesh.GetNumElements(CMesh::TET);
545 int iNumPyramids = m_VolumeMesh.GetNumElements(CMesh::PYRAMID);
546 int iNumWedges = m_VolumeMesh.GetNumElements(CMesh::WEDGE);
547 if (!m_bHybrid)
548 {
549 TetMeshColumn(Columns, EdgeConstraints);
550 }
551 else
552 {
553 MixedMeshColumn(Columns, EdgeConstraints);
554 }
555 iNumTets = m_VolumeMesh.GetNumElements(CMesh::TET) - iNumTets;
556 iNumPyramids = m_VolumeMesh.GetNumElements(CMesh::PYRAMID) - iNumPyramids;
557 iNumWedges = m_VolumeMesh.GetNumElements(CMesh::WEDGE) - iNumWedges;
558 if (iNumTets)
559 m_ElementData[CMesh::TET].resize(m_ElementData[CMesh::TET].size()+iNumTets, ElemData);
560 if (iNumPyramids)
561 m_ElementData[CMesh::PYRAMID].resize(m_ElementData[CMesh::PYRAMID].size()+iNumPyramids, ElemData);
562 if (iNumWedges)
563 m_ElementData[CMesh::WEDGE].resize(m_ElementData[CMesh::WEDGE].size()+iNumWedges, ElemData);*/
564 }
565}
566
567bool CMesher::SplitColumn(PROJECTED_NODE &Node, vector<int> &YarnIndices, vector<vector<RAISED_NODE> > &Column)
568{
569 int i, j, iNumLayers = YarnIndices.size()*2+1;
570 Column.clear();
571 Column.resize(iNumLayers);
572 int iLayer = 0;
573 for (i=0; i<(int)Node.RaisedNodes.size(); ++i)
574 {
575 Column[iLayer].push_back(Node.RaisedNodes[i]);
576 for (j=0; j<(int)Node.RaisedNodes[i].YarnBoundaryIndices.size(); ++j)
577 {
578 if (count(YarnIndices.begin(), YarnIndices.end(), Node.RaisedNodes[i].YarnBoundaryIndices[j]))
579 {
580 ++iLayer;
581 if (iLayer < iNumLayers)
582 {
583 Column[iLayer].push_back(Node.RaisedNodes[i]);
584 }
585 else
586 {
587 assert(false);
588 return false;
589 }
590 }
591 }
592 }
593 return true;
594}
595
596void CMesher::BuildMidSideNodes(vector<RAISED_NODE> Columns[3], int iYarnIndex)
597{
598 int i, i1, i2;
599 for (i=0; i<3; ++i)
600 {
601 i1 = i;
602 i2 = (i+1)%3;
603 if (!Columns[i1].empty() && !Columns[i2].empty())
604 {
605 if (!Columns[i1].front().bMerged && !Columns[i2].front().bMerged)
606 BuildMidSideNode(Columns[i1].front().iIndex, Columns[i2].front().iIndex, iYarnIndex, false);
607 if (!Columns[i1].back().bMerged && !Columns[i2].back().bMerged)
608 BuildMidSideNode(Columns[i1].back().iIndex, Columns[i2].back().iIndex, iYarnIndex, true);
609 }
610 }
611}
612
613void CMesher::BuildMidSideNode(int iNodeIndex1, int iNodeIndex2, int iYarnIndex, bool bTop)
614{
615 if (iNodeIndex2 > iNodeIndex1)
616 swap(iNodeIndex1, iNodeIndex2);
617
618 pair<int, int> MidIndex(iNodeIndex1, iNodeIndex2);
619
620 if (m_MidSideNodeLocations.count(MidIndex))
621 return;
622
623 XYZ MidPos = 0.5 * (m_VolumeMesh.GetNode(iNodeIndex1) + m_VolumeMesh.GetNode(iNodeIndex2));
624
625 pair<double, double> YarnBounds;
626 bool bFound = GetMeshVerticalBounds(m_YarnMeshes[iYarnIndex], MidPos, YarnBounds.first, YarnBounds.second, true);
627 if (bFound)
628 {
629 if (bTop)
630 MidPos.z = YarnBounds.second;
631 else
632 MidPos.z = YarnBounds.first;
633 m_MidSideNodeLocations[MidIndex] = MidPos;
634 }
635 else
636 assert(false);
637}
638
639XYZ CMesher::GetMidSideNode(int iNodeIndex1, int iNodeIndex2)
640{
641 if (iNodeIndex2 > iNodeIndex1)
642 swap(iNodeIndex1, iNodeIndex2);
643 pair<int, int> MidIndex(iNodeIndex1, iNodeIndex2);
644 map<pair<int, int>, XYZ>::iterator itNode = m_MidSideNodeLocations.find(MidIndex);
645 if (itNode != m_MidSideNodeLocations.end())
646 return itNode->second;
647 return 0.5 * (m_VolumeMesh.GetNode(iNodeIndex1) + m_VolumeMesh.GetNode(iNodeIndex2));
648}
649
651{
652 CMesh QuadraticMesh;
653 QuadraticMesh.GetNodes() = m_VolumeMesh.GetNodes();
654 const list<int> &Indices = m_VolumeMesh.GetIndices(CMesh::TET);
655 list<int>::const_iterator itIndex;
656 int i1, i2, i3, i4;
657 for (itIndex = Indices.begin(); itIndex != Indices.end(); )
658 {
659 i1 = *(itIndex++);
660 i2 = *(itIndex++);
661 i3 = *(itIndex++);
662 i4 = *(itIndex++);
663 vector<int> QuadraticTet;
664 QuadraticTet.push_back(i1);
665 QuadraticTet.push_back(i2);
666 QuadraticTet.push_back(i3);
667 QuadraticTet.push_back(i4);
668 QuadraticTet.push_back(QuadraticMesh.AddNode(GetMidSideNode(i1, i2)));
669 QuadraticTet.push_back(QuadraticMesh.AddNode(GetMidSideNode(i2, i3)));
670 QuadraticTet.push_back(QuadraticMesh.AddNode(GetMidSideNode(i3, i1)));
671 QuadraticTet.push_back(QuadraticMesh.AddNode(GetMidSideNode(i1, i4)));
672 QuadraticTet.push_back(QuadraticMesh.AddNode(GetMidSideNode(i2, i4)));
673 QuadraticTet.push_back(QuadraticMesh.AddNode(GetMidSideNode(i3, i4)));
674 QuadraticMesh.AddElement(CMesh::QUADRATIC_TET, QuadraticTet);
675 }
676 // Merge the nodes, because we added some new nodes that share the same location
677 QuadraticMesh.MergeNodes(1e-9);
678 m_VolumeMesh = QuadraticMesh;
679}
680
681void CMesher::BuildEdgeConstraints(vector<RAISED_NODE> Columns[3], set<pair<int, int> > EdgeConstraints[3])
682{
683 // This structure contains the list of edge constraints that must be
684 // respected in order for the mesh edges to be well matched
685 int k;
686 int i1, i2;
687 vector<RAISED_NODE>::iterator itRaisedNode1, itRaisedNode2;
688 vector<int>::iterator itYarnBound1, itYarnBound2;
689 map<int, int> BoundCount1;
690 map<int, int> BoundCount2;
691 // Conform to edge constraints caused by yarn boundaries
692 for (k=0; k<3; ++k)
693 {
694 BoundCount1.clear();
695 for (i1 = 0; i1 < (int)Columns[k].size(); ++i1)
696 {
697 vector<int> &YarnBounds1 = Columns[k][i1].YarnBoundaryIndices;
698 for (itYarnBound1 = YarnBounds1.begin(); itYarnBound1 != YarnBounds1.end(); ++itYarnBound1)
699 {
700 ++BoundCount1[*itYarnBound1];
701 BoundCount2.clear();
702 for (i2 = 0; i2 < (int)Columns[(k+1)%3].size(); ++i2)
703 {
704 vector<int> &YarnBounds2 = Columns[(k+1)%3][i2].YarnBoundaryIndices;
705 for (itYarnBound2 = YarnBounds2.begin(); itYarnBound2 != YarnBounds2.end(); ++itYarnBound2)
706 {
707 ++BoundCount2[*itYarnBound2];
708 if (*itYarnBound1 == *itYarnBound2 &&
709 BoundCount1[*itYarnBound1] == BoundCount2[*itYarnBound2])
710// *itYarnBound1 != iTopYarnIndex &&
711// *itYarnBound1 != iBottomYarnIndex)
712 {
713 EdgeConstraints[k].insert(make_pair(i1, i2));
714 }
715 }
716 }
717 }
718 }
719 }
720
721 // Conform to edge constraints caused by existing elements
722 pair<int, int> Edge;
723 for (k=0; k<3; ++k)
724 {
725 for (i1 = 0; i1 < (int)Columns[k].size(); ++i1)
726 {
727 for (i2 = 0; i2 < (int)Columns[(k+1)%3].size(); ++i2)
728 {
729 Edge.first = Columns[k][i1].iIndex;
730 Edge.second = Columns[(k+1)%3][i2].iIndex;
731 if (Edge.first > Edge.second)
732 swap(Edge.first, Edge.second);
733 if (m_EdgeConstraints.count(Edge))
734 {
735 EdgeConstraints[k].insert(make_pair(i1, i2));
736 }
737 }
738 }
739 }
740
741}
742
743int CMesher::TetMeshColumn(vector<RAISED_NODE> Columns[3], set<pair<int, int> > EdgeConstraints[3])
744{
745/* vector<PROJECTED_NODE*> Nodes;
746 Nodes.push_back(&m_ProjectedNodes[iColumn1]);
747 Nodes.push_back(&m_ProjectedNodes[iColumn2]);
748 Nodes.push_back(&m_ProjectedNodes[iColumn3]);*/
749
750
751 int i, i1, i2;
752
753 int h[3] = {0, 0, 0};
754 int Sizes[3];
755 for (i=0; i<3; ++i)
756 {
757 Sizes[i] = (int)Columns[i].size();
758 }
759
760 double dZ, dZMin;
761 int iMinIndex;
762 int iNumElements = 0;
763 set<pair<int, int> >::iterator itEdge;
764 bool bEdgeConstraintViolation;
765 while (h[0] < Sizes[0] && h[1] < Sizes[1] && h[2] < Sizes[2])
766 {
767 iMinIndex = -1;
768 for (i=0; i<3; ++i)
769 {
770 i1 = (i+1)%3;
771 i2 = (i+2)%3;
772 if (h[i]+1 < Sizes[i])
773 {
774 dZ = Columns[i][h[i]+1].dZ;
775 if (iMinIndex==-1 || dZ < dZMin)
776 {
777 // Check if adding this as a tetrahedron would violate any of the edge constraints
778 bEdgeConstraintViolation = ViolatesEdgeConstraint(EdgeConstraints[i], EdgeConstraints[i2], h[i], h[i1], h[i2]);
779/* bEdgeConstraintViolation = false;
780 for (itEdge = EdgeConstraints[i].begin(); itEdge != EdgeConstraints[i].end(); ++itEdge)
781 {
782 if (h[i] >= itEdge->first && h[(i+1)%3] < itEdge->second)
783 {
784 bEdgeConstraintViolation = true;
785 }
786 }
787 for (itEdge = EdgeConstraints[(i+2)%3].begin(); itEdge != EdgeConstraints[(i+2)%3].end(); ++itEdge)
788 {
789 if (h[i] >= itEdge->second && h[(i+2)%3] < itEdge->first)
790 {
791 bEdgeConstraintViolation = true;
792 }
793 }*/
794 if (!bEdgeConstraintViolation)
795 {
796 dZMin = dZ;
797 iMinIndex = i;
798 }
799 }
800 }
801 }
802 if (iMinIndex == -1)
803 {
804 // This tet can't be meshed directly due to the edge constraints
805// if (h[0]+1 < Sizes[0] && h[1]+1 < Sizes[1] && h[2]+1 < Sizes[2])
806 {
807 int Limits[6];
808 Limits[0] = Limits[3] = h[0];
809 Limits[1] = Limits[4] = h[1];
810 Limits[2] = Limits[5] = h[2];
811 bool bChanges;
812 // Identify which region is going to be hard to mesh and store its limits in the Limits
813 // array.
814 do
815 {
816 bChanges = false;
817 for (i=0; i<3; ++i)
818 {
819 for (itEdge = EdgeConstraints[i].begin(); itEdge != EdgeConstraints[i].end(); ++itEdge)
820 {
821 if (Limits[i] <= itEdge->first && itEdge->first < max(Limits[i+3], Limits[i]+1) &&
822 Limits[3+(i+1)%3] < itEdge->second)
823 {
824 Limits[3+(i+1)%3] = itEdge->second;
825 bChanges = true;
826 }
827 }
828 for (itEdge = EdgeConstraints[(i+2)%3].begin(); itEdge != EdgeConstraints[(i+2)%3].end(); ++itEdge)
829 {
830 if (Limits[i] <= itEdge->second && itEdge->second < max(Limits[i+3], Limits[i]+1) &&
831 Limits[3+(i+2)%3] < itEdge->first)
832 {
833 Limits[3+(i+2)%3] = itEdge->first;
834 bChanges = true;
835 }
836 }
837 }
838 } while (bChanges);
839
840 if (Limits[0] == Limits[3] &&
841 Limits[1] == Limits[4] &&
842 Limits[2] == Limits[5])
843 break; // We don't have anything to mesh here, game over...
844
845 // Mesh it by adding an additional point to the mesh
846 iNumElements += MeshDifficultRegion(Columns, Limits, EdgeConstraints);
847
848 // Done! move up to the next layer
849 h[0] = Limits[3];
850 h[1] = Limits[4];
851 h[2] = Limits[5];
852 }
853/* else
854 {
855// assert(false);
856 break;
857 }*/
858 }
859 else
860 {
861 vector<int> Indices;
862 for (i=0; i<3; ++i)
863 {
864 Indices.push_back(Columns[i][h[i]].iIndex);
865 }
866 ++h[iMinIndex];
867 Indices.push_back(Columns[iMinIndex][h[iMinIndex]].iIndex);
868
869 AddElement(CMesh::TET, Indices);
870// copy(Indices.begin(), Indices.end(), back_inserter(m_VolumeMesh.GetIndices(CMesh::TET)));
871
872 ++iNumElements;
873 }
874 }
875 return iNumElements;
876}
877
878int CMesher::MeshDifficultRegion(vector<RAISED_NODE> Columns[3], int Limits[6], set<pair<int, int> > EdgeConstraints[3])
879{
880 XYZ Center;
881 int i, j;
882 double dMinZ, dMaxZ;
883 // Use projected triangle center for x and y components
884 for (i=0; i<3; ++i)
885 {
886 Center += m_VolumeMesh.GetNode(Columns[i][Limits[i]].iIndex);
887 }
888 Center /= 3;
889 // Find maximum and lowest Z, use the average as center z coordinate
890 dMinZ = dMaxZ = Columns[0][Limits[0]].dZ;
891 for (i=0; i<3; ++i)
892 {
893 for (j=Limits[i]; j<=Limits[i+3]; ++j)
894 {
895 if (Columns[i][j].dZ < dMinZ)
896 dMinZ = Columns[i][j].dZ;
897 else if (Columns[i][j].dZ > dMaxZ)
898 dMaxZ = Columns[i][j].dZ;
899 }
900 }
901 Center.z = 0.5*(dMinZ + dMaxZ);
902
903 int iCenter = (int)m_VolumeMesh.GetNumNodes();
904 m_VolumeMesh.AddNode(Center);
905
906 set<pair<int, int> >::iterator itEdge;
907
908 int iElementsCreated = 0;
909 // Bottom tet
910 {
911 vector<int> Indices;
912 Indices.push_back(Columns[0][Limits[0]].iIndex);
913 Indices.push_back(Columns[1][Limits[1]].iIndex);
914 Indices.push_back(Columns[2][Limits[2]].iIndex);
915 Indices.push_back(iCenter);
916 AddElement(CMesh::TET, Indices);
917 }
918 ++iElementsCreated;
919 int h1, h2;
920 bool bEdgeConstraintViolation;
921 // Side tets
922 for (i=0; i<3; ++i)
923 {
924 h1 = Limits[i];
925 h2 = Limits[(i+1)%3];
926 while (h1 <= Limits[i+3])
927 {
928 while (h2 < Limits[(i+1)%3+3])
929 {
930 // If there is no edge constraint between higher than h1 to h2 or lower build a tet
931 bEdgeConstraintViolation = false;
932 for (itEdge = EdgeConstraints[i].begin(); itEdge != EdgeConstraints[i].end(); ++itEdge)
933 {
934 if (h1 < itEdge->first && h2 >= itEdge->second)
935 {
936 bEdgeConstraintViolation = true;
937 }
938 }
939 if (bEdgeConstraintViolation)
940 break;
941 vector<int> Indices;
942 Indices.push_back(iCenter);
943 Indices.push_back(Columns[i][h1].iIndex);
944 Indices.push_back(Columns[(i+1)%3][h2].iIndex);
945 Indices.push_back(Columns[(i+1)%3][h2+1].iIndex);
946 AddElement(CMesh::TET, Indices);
947 ++iElementsCreated;
948 ++h2;
949 }
950 if (h1 < Limits[i+3] && h2 <= Limits[(i+1)%3+3])
951 {
952 // If there is no edge constraint between higher than h2 to h1 or lower build a tet
953 bEdgeConstraintViolation = false;
954 for (itEdge = EdgeConstraints[i].begin(); itEdge != EdgeConstraints[i].end(); ++itEdge)
955 {
956 if (h1 >= itEdge->first && h2 < itEdge->second)
957 {
958 bEdgeConstraintViolation = true;
959 }
960 }
961 if (!bEdgeConstraintViolation)
962 {
963 vector<int> Indices;
964 Indices.push_back(iCenter);
965 Indices.push_back(Columns[i][h1].iIndex);
966 Indices.push_back(Columns[(i+1)%3][h2].iIndex);
967 Indices.push_back(Columns[i][h1+1].iIndex);
968 AddElement(CMesh::TET, Indices);
969 ++iElementsCreated;
970 }
971 else
972 {
973 assert(false); // should never get here
974 }
975 }
976 ++h1;
977 }
978 }
979 // Top tet
980 {
981 vector<int> Indices;
982 Indices.push_back(iCenter);
983 Indices.push_back(Columns[0][Limits[3]].iIndex);
984 Indices.push_back(Columns[1][Limits[4]].iIndex);
985 Indices.push_back(Columns[2][Limits[5]].iIndex);
986 AddElement(CMesh::TET, Indices);
987 }
988 ++iElementsCreated;
989
990 return iElementsCreated;
991
992}
993/*
994int CMesher::MixedMeshColumn(vector<RAISED_NODE> Columns[3], set<pair<int, int> > EdgeConstraints[3])
995{
996 int h[3] = {0, 0, 0};
997 int Sizes[3];
998 int i, i1, i2, j;
999 for (i=0; i<3; ++i)
1000 {
1001 Sizes[i] = (int)Columns[i].size();
1002 }
1003
1004 set<pair<int, int> >::iterator itEdge;
1005 int iNumElements = 0;
1006// while (h[0] < Sizes[0] && h[1] < Sizes[1] && h[2] < Sizes[2])
1007 while (true)
1008 {
1009 bool up[3] = {true, true, true};
1010 bool bChanges;
1011 do
1012 {
1013 bChanges = false;
1014 for (i=0; i<3; ++i)
1015 {
1016 if (!up[i])
1017 continue;
1018 i1 = (i+1)%3;
1019 i2 = (i+2)%3;
1020 if (h[i]+1 >= Sizes[i] ||
1021 ShouldConnect(Columns[i], Columns[i1], h[i], h[i1]+1) ||
1022 ShouldConnect(Columns[i], Columns[i2], h[i], h[i2]+1) ||
1023 ViolatesEdgeConstraint(EdgeConstraints[i], EdgeConstraints[i2], h[i], h[i1], h[i2]))
1024 {
1025 up[i] = false;
1026 bChanges = true;
1027 }
1028 }
1029 } while(bChanges);
1030 int UpCount = count(up, up+3, true);
1031 if (UpCount == 0)
1032 {
1033 for (i=0; i<3; ++i)
1034 {
1035 if (h[i]+1 != Sizes[i])
1036 assert(false);
1037 }
1038 break;
1039// THIS IS DIRECTLY PASTED FROM TETMESH, FIX IT UP...
1040//
1041// int Limits[6];
1042// Limits[0] = Limits[3] = h[0];
1043// Limits[1] = Limits[4] = h[1];
1044// Limits[2] = Limits[5] = h[2];
1045// bool bChanges;
1046// // Identify which region is going to be hard to mesh and store its limits in the Limits
1047// // array.
1048// do
1049// {
1050// bChanges = false;
1051// for (i=0; i<3; ++i)
1052// {
1053// for (itEdge = EdgeConstraints[i].begin(); itEdge != EdgeConstraints[i].end(); ++itEdge)
1054// {
1055// if (Limits[i] <= itEdge->first && itEdge->first < max(Limits[i+3], Limits[i]+1) &&
1056// Limits[3+(i+1)%3] < itEdge->second)
1057// {
1058// Limits[3+(i+1)%3] = itEdge->second;
1059// bChanges = true;
1060// }
1061// }
1062// for (itEdge = EdgeConstraints[(i+2)%3].begin(); itEdge != EdgeConstraints[(i+2)%3].end(); ++itEdge)
1063// {
1064// if (Limits[i] <= itEdge->second && itEdge->second < max(Limits[i+3], Limits[i]+1) &&
1065// Limits[3+(i+2)%3] < itEdge->first)
1066// {
1067// Limits[3+(i+2)%3] = itEdge->first;
1068// bChanges = true;
1069// }
1070// }
1071// }
1072// } while (bChanges);
1073//
1074// if (Limits[0] == Limits[3] &&
1075// Limits[1] == Limits[4] &&
1076// Limits[2] == Limits[5])
1077// break; // We don't have anything to mesh here, game over...
1078//
1079// // Mesh it by adding an additional point to the mesh
1080// iNumElements += MeshDifficultRegion(Columns, Limits, EdgeConstraints);
1081//
1082// // Done! move up to the next layer
1083// h[0] = Limits[3];
1084// h[1] = Limits[4];
1085// h[2] = Limits[5];
1086// continue;
1087 }
1088
1089 switch (UpCount)
1090 {
1091 case 3:
1092 {
1093 // Mesh with wedge elements
1094// list<int> &Indices = m_VolumeMesh.GetIndices(CMesh::WEDGE);
1095 vector<int> Indices;
1096 for (i=0; i<3; ++i)
1097 {
1098 Indices.push_back(Columns[i][h[i]+1].iIndex);
1099 }
1100 for (i=0; i<3; ++i)
1101 {
1102 Indices.push_back(Columns[i][h[i]].iIndex);
1103 }
1104 AddElement(CMesh::WEDGE, Indices);
1105 }
1106 break;
1107 case 2:
1108 {
1109 // Mesh with pyramid elements
1110// list<int> &Indices = m_VolumeMesh.GetIndices(CMesh::PYRAMID);
1111 vector<int> Indices;
1112 int iNoUp = 0;
1113 for (i=0; i<3; ++i)
1114 {
1115 if (!up[i])
1116 iNoUp = i;
1117 }
1118 i1 = (iNoUp+2)%3;
1119 i2 = (iNoUp+1)%3;
1120 Indices.push_back(Columns[i1][h[i1]].iIndex);
1121 Indices.push_back(Columns[i2][h[i2]].iIndex);
1122
1123 Indices.push_back(Columns[i2][h[i2]+1].iIndex);
1124 Indices.push_back(Columns[i1][h[i1]+1].iIndex);
1125
1126 Indices.push_back(Columns[iNoUp][h[iNoUp]].iIndex);
1127 AddElement(CMesh::PYRAMID, Indices);
1128 }
1129 break;
1130 case 1:
1131 {
1132 // Mesh with wedge elements
1133// list<int> &Indices = m_VolumeMesh.GetIndices(CMesh::TET);
1134 vector<int> Indices;
1135 for (i=0; i<3; ++i)
1136 {
1137 Indices.push_back(Columns[i][h[i]].iIndex);
1138 }
1139 for (i=0; i<3; ++i)
1140 {
1141 if (up[i])
1142 {
1143 Indices.push_back(Columns[i][h[i]+1].iIndex);
1144 }
1145 }
1146 AddElement(CMesh::TET, Indices);
1147 }
1148 break;
1149 }
1150
1151 ++iNumElements;
1152
1153 for (i=0; i<3; ++i)
1154 {
1155 if (up[i])
1156 ++h[i];
1157 }
1158 }
1159 return iNumElements;
1160}
1161*/
1162void CMesher::AddElement(CMesh::ELEMENT_TYPE Type, const vector<int> &Indices)
1163{
1164 if (!m_VolumeMesh.AddElement(Type, Indices))
1165 return;
1166
1167 switch (Type)
1168 {
1169 case CMesh::TET:
1170 {
1171 NODE_PAIR NodePair;
1172 AddEdgeConstraint(Indices[0], Indices[1]);
1173 if ( GetPairIndices( Indices[0], Indices[1], NodePair ) )
1174 AddEdgeConstraint( NodePair.first, NodePair.second );
1175 AddEdgeConstraint(Indices[0], Indices[2]);
1176 if ( GetPairIndices( Indices[0], Indices[2], NodePair ) )
1177 AddEdgeConstraint( NodePair.first, NodePair.second );
1178 AddEdgeConstraint(Indices[0], Indices[3]);
1179 if ( GetPairIndices( Indices[0], Indices[3], NodePair ) )
1180 AddEdgeConstraint( NodePair.first, NodePair.second );
1181 AddEdgeConstraint(Indices[1], Indices[2]);
1182 if ( GetPairIndices( Indices[1], Indices[2], NodePair ) )
1183 AddEdgeConstraint( NodePair.first, NodePair.second );
1184 AddEdgeConstraint(Indices[1], Indices[3]);
1185 if ( GetPairIndices( Indices[1], Indices[3], NodePair ) )
1186 AddEdgeConstraint( NodePair.first, NodePair.second );
1187 AddEdgeConstraint(Indices[2], Indices[3]);
1188 if ( GetPairIndices( Indices[2], Indices[3], NodePair ) )
1189 AddEdgeConstraint( NodePair.first, NodePair.second );
1190 break;
1191 }
1192 case CMesh::PYRAMID:
1193 AddEdgeConstraint(Indices[0], Indices[1]);
1194 AddEdgeConstraint(Indices[1], Indices[2]);
1195 AddEdgeConstraint(Indices[2], Indices[3]);
1196 AddEdgeConstraint(Indices[3], Indices[0]);
1197
1198 AddEdgeConstraint(Indices[0], Indices[4]);
1199 AddEdgeConstraint(Indices[1], Indices[4]);
1200 AddEdgeConstraint(Indices[2], Indices[4]);
1201 AddEdgeConstraint(Indices[3], Indices[4]);
1202 break;
1203 case CMesh::WEDGE:
1204 AddEdgeConstraint(Indices[0], Indices[1]);
1205 AddEdgeConstraint(Indices[1], Indices[2]);
1206 AddEdgeConstraint(Indices[2], Indices[0]);
1207
1208 AddEdgeConstraint(Indices[3], Indices[4]);
1209 AddEdgeConstraint(Indices[4], Indices[5]);
1210 AddEdgeConstraint(Indices[5], Indices[3]);
1211
1212 AddEdgeConstraint(Indices[0], Indices[3]);
1213 AddEdgeConstraint(Indices[1], Indices[4]);
1214 AddEdgeConstraint(Indices[2], Indices[5]);
1215 break;
1216 }
1217}
1218
1219void CMesher::AddEdgeConstraint(int i1, int i2)
1220{
1221 pair<int, int> EdgeConstraint(i1, i2);
1222 if (EdgeConstraint.first > EdgeConstraint.second)
1223 swap(EdgeConstraint.first, EdgeConstraint.second);
1224 m_EdgeConstraints.insert(EdgeConstraint);
1225}
1226
1227bool CMesher::ViolatesEdgeConstraint(const set<pair<int, int> > &EdgeConstraints1, const set<pair<int, int> > &EdgeConstraints2, int h, int h1, int h2)
1228{
1229 set<pair<int, int> >::const_iterator itEdge;
1230 for (itEdge = EdgeConstraints1.begin(); itEdge != EdgeConstraints1.end(); ++itEdge)
1231 {
1232 if (h >= itEdge->first && h1 < itEdge->second)
1233 {
1234 return true;
1235 }
1236 }
1237 for (itEdge = EdgeConstraints2.begin(); itEdge != EdgeConstraints2.end(); ++itEdge)
1238 {
1239 if (h >= itEdge->second && h2 < itEdge->first)
1240 {
1241 return true;
1242 }
1243 }
1244 return false;
1245}
1246
1247bool CMesher::ShouldConnect(vector<RAISED_NODE> &Column1, vector<RAISED_NODE> &Column2, int h1, int h2)
1248{
1249 if (h1 >= (int)Column1.size())
1250 return false;
1251 if (h2 >= (int)Column2.size())
1252 return false;
1253
1254 double dDist = abs(Column1[h1].dZ - Column2[h2].dZ);
1255 bool bClosest = true;
1256 int j;
1257 for (j=0; j<(int)Column1.size(); ++j)
1258 {
1259 if (j == h1)
1260 continue;
1261 if (abs(Column1[j].dZ - Column2[h2].dZ) <= dDist)
1262 {
1263 bClosest = false;
1264 break;
1265 }
1266 }
1267 if (bClosest)
1268 return true;
1269 bClosest = true;
1270 for (j=0; j<(int)Column2.size(); ++j)
1271 {
1272 if (j == h2)
1273 continue;
1274 if (abs(Column1[h1].dZ - Column2[j].dZ) <= dDist)
1275 {
1276 bClosest = false;
1277 break;
1278 }
1279 }
1280 return bClosest;
1281}
1282
1284{
1285 if (!m_pTextile)
1286 return;
1287 const CDomain* pDomain = m_pTextile->GetDomain();
1288 // This value may need tweaking
1289 //double dTolerance = 1e-1;
1290 double dTolerance = 1e-5;
1291 list<MESHER_ELEMENT_DATA>::iterator itElementData;
1292 list<int>::const_iterator itIndex;
1293 int i, iNumNodes;
1294 int iNumYarns = m_pTextile->GetNumYarns();
1295 bool bInside;
1296 vector<vector<XYZ> > YarnTranslations;
1297 YarnTranslations.resize(iNumYarns);
1298 if (pDomain)
1299 {
1300 for (i=0; i<iNumYarns; ++i)
1301 {
1302 YarnTranslations[i] = pDomain->GetTranslations(*m_pTextile->GetYarn(i));
1303 }
1304 }
1305 int j;
1306 for (j = 0; j < CMesh::NUM_ELEMENT_TYPES; ++j)
1307 {
1308 list<int> &Indices = m_VolumeMesh.GetIndices((CMesh::ELEMENT_TYPE)j);
1309 list<MESHER_ELEMENT_DATA> &ElementData = m_ElementData[(CMesh::ELEMENT_TYPE)j];
1311 for (itIndex = Indices.begin(), itElementData = ElementData.begin(); itIndex != Indices.end() && itElementData != ElementData.end(); ++itElementData)
1312 {
1313 XYZ AvgPos;
1314 for (i=0; i<iNumNodes; ++i)
1315 {
1316 AvgPos += m_VolumeMesh.GetNode(*(itIndex++));
1317 }
1318 AvgPos /= iNumNodes;
1319
1320 if (itElementData->iYarnIndex >= 0 && itElementData->iYarnIndex < iNumYarns)
1321 {
1322 CYarn* pYarn = m_pTextile->GetYarn(itElementData->iYarnIndex);
1323 bInside = pYarn->PointInsideYarn(AvgPos, YarnTranslations[itElementData->iYarnIndex], &itElementData->YarnTangent, &itElementData->Location, &itElementData->dVolumeFraction, &itElementData->dSurfaceDistance, dTolerance, &itElementData->Orientation, &itElementData->Up);
1324 //assert(bInside);
1325 if ( !bInside )
1326 TGLOG("PointInsideYarn false");
1327 }
1328 }
1329 }
1330}
1331
1332const list<MESHER_ELEMENT_DATA> *CMesher::GetElementData(CMesh::ELEMENT_TYPE ElementType)
1333{
1334 if (ElementType < 0 || ElementType >= CMesh::NUM_ELEMENT_TYPES)
1335 {
1336 TGERROR("Unable to get element data, invalid element type: " << ElementType);
1337 return NULL;
1338 }
1339 return &m_ElementData[ElementType];
1340}
1341
1342bool CMesher::GetPairIndices(int iIndex1, int iIndex2, NODE_PAIR &MatchPair)
1343{
1344 NODE_PAIR_SETS::iterator itSets = m_NodePairSets.begin();
1345 bool bFoundFirst = false, bFoundSecond = false;
1346
1347 // Iterate through node pair sets until find one which contains both nodes (node pair set contains pairs on opposite boundaries)
1348 while ( itSets != m_NodePairSets.end() && !(bFoundFirst && bFoundSecond) )
1349 {
1350 NODE_PAIR_SET::iterator itNodePairSet = (*itSets).begin();
1351 bFoundFirst = false;
1352 bFoundSecond = false;
1353 while( itNodePairSet != (*itSets).end() && !(bFoundFirst && bFoundSecond) ) // Iterate through node pair set until found match for both nodes
1354 {
1355 if (!bFoundFirst)
1356 {
1357 if ( (*itNodePairSet).first == iIndex1 )
1358 {
1359 MatchPair.first = (*itNodePairSet).second;
1360 bFoundFirst = true;
1361 }
1362 else if ( (*itNodePairSet).second == iIndex1 )
1363 {
1364 MatchPair.first = (*itNodePairSet).first;
1365 bFoundFirst = true;
1366 }
1367 }
1368 if ( !bFoundSecond )
1369 {
1370 if ( (*itNodePairSet).first == iIndex2 )
1371 {
1372 MatchPair.second = (*itNodePairSet).second;
1373 bFoundSecond = true;
1374 }
1375 else if ( (*itNodePairSet).second == iIndex2 )
1376 {
1377 MatchPair.second = (*itNodePairSet).first;
1378 bFoundSecond = true;
1379 }
1380 }
1381 ++itNodePairSet;
1382 }
1383 ++itSets;
1384 }
1385 return ( bFoundFirst && bFoundSecond );
1386}
1387
1388void CMesher::GetEdgePairIndices(const NODE_PAIR_SETS &NodePairSets, int iIndex, set<int> &Match)
1389{
1390 NODE_PAIR_SETS::const_iterator itSets = NodePairSets.begin();
1391 int iNumFound = 0;
1392
1393 while ( itSets != NodePairSets.end() )
1394 {
1395 NODE_PAIR_SET::const_iterator itNodePairSet = (*itSets).begin();
1396 pair<set<int>::iterator, bool> ret;
1397 bool bFound = false;
1398
1399 while( itNodePairSet != (*itSets).end() && !bFound )
1400 {
1401 if ( (*itNodePairSet).first == iIndex )
1402 {
1403 ret = Match.insert( (*itNodePairSet).second );
1404 if ( ret.second ) // Returns true in second if new element was added
1405 {
1406 bFound = true;
1407 iNumFound++;
1408 }
1409 }
1410 else if ( (*itNodePairSet).second == iIndex )
1411 {
1412 ret = Match.insert( (*itNodePairSet).first );
1413 if ( ret.second )
1414 {
1415 bFound = true;
1416 iNumFound++;
1417 }
1418 }
1419 ++itNodePairSet;
1420 }
1421 ++itSets;
1422 }
1423 if ( iNumFound > 1 ) // If found more than one must be a corner so call function again to get other corner node
1424 {
1425 GetEdgePairIndices( NodePairSets, *(Match.begin()), Match );
1426 }
1427}
1428
1429void CMesher::SortPairs( NODE_PAIR_SET &NodePairs, bool bSwapY )
1430{
1431 NODE_PAIR_SET::iterator itNodePairs;
1432
1433 for ( itNodePairs = NodePairs.begin(); itNodePairs != NodePairs.end(); ++itNodePairs )
1434 {
1435 XYZ Node1 = m_ProjectedMesh.GetNode((*itNodePairs).first);
1436 XYZ Node2 = m_ProjectedMesh.GetNode((*itNodePairs).second);
1437 if (bSwapY )
1438 {
1439 if ( Node1.y > Node2.y )
1440 {
1441 swap( (*itNodePairs).first, (*itNodePairs).first );
1442 }
1443 }
1444 else
1445 {
1446 if ( Node1.x > Node2.x )
1447 {
1448 swap( (*itNodePairs).first, (*itNodePairs).first );
1449 }
1450 }
1451 }
1452}
1453
1454void CMesher::CreateNodeSets( NODE_PAIR_SETS &EdgeNodePairSets, set<int> &CornerIndex, const vector<XYZ> &Repeats )
1455{
1456 // Find boundary node pair sets
1457 m_NodePairSets.clear();
1458 NODE_PAIR_SETS::iterator itEdgeNodeSets;
1459
1460 set<int> CompletedCorners;
1461 set<int> EdgeIndices;
1462
1463 m_Edges.resize(12);
1464 m_Vertices.resize(8);
1465 int j = 0;
1466
1467 for ( itEdgeNodeSets = EdgeNodePairSets.begin(); itEdgeNodeSets != EdgeNodePairSets.end(); ++itEdgeNodeSets )
1468 {
1469 NODE_PAIR_SET::iterator itNodePairs;
1470 NODE_PAIR_SET VolMeshPairs;
1471 VolMeshPairs.clear();
1472
1473 bool bConstX = (Repeats[j++].y == 0);
1474
1475 for ( itNodePairs = (*itEdgeNodeSets).begin(); itNodePairs != (*itEdgeNodeSets).end(); ++itNodePairs )
1476 {
1477 // Indices in the pairs in the edge node sets correspond to index into m_Projected Nodes
1478 NODE_PAIR NodePair;
1479 vector<RAISED_NODE>::iterator itRaisedNodes;
1480 int ind1 = (*itNodePairs).first;
1481 int ind2 = (*itNodePairs).second;
1482 int size = m_ProjectedNodes[ind1].RaisedNodes.size();
1483 EdgeIndices.insert(ind1);
1484 EdgeIndices.insert(ind2);
1485
1486 assert( size == m_ProjectedNodes[ind2].RaisedNodes.size() );
1487 if ( CornerIndex.find(ind1) != CornerIndex.end() ) // Is corner node
1488 {
1489 if ( CompletedCorners.find(ind1) == CompletedCorners.end() ) // Check if already entered nodes
1490 {
1491 vector<int> Edge1, Edge2;
1492 for ( int i = 1; i < size-1; ++i )
1493 {
1494 Edge1.push_back(m_ProjectedNodes[ind1].RaisedNodes[i].iIndex + 1);
1495 Edge2.push_back(m_ProjectedNodes[ind2].RaisedNodes[i].iIndex + 1);
1496 }
1497 if ( m_Edges[0].empty() )
1498 {
1499 m_Edges[0] = Edge1;
1500 m_Edges[1] = Edge2;
1501 }
1502 else
1503 {
1504 m_Edges[2] = Edge2;
1505 m_Edges[3] = Edge1;
1506 }
1507
1508 int StartInd = 0;
1509 if ( !CompletedCorners.empty() )
1510 {
1511 StartInd = 2;
1512 swap(ind1,ind2);
1513 }
1514 m_Vertices[StartInd++] = (m_ProjectedNodes[ind1].RaisedNodes[0].iIndex + 1);
1515 m_Vertices[StartInd++] = (m_ProjectedNodes[ind2].RaisedNodes[0].iIndex + 1);
1516 StartInd += 2;
1517
1518 m_Vertices[StartInd++] = (m_ProjectedNodes[ind1].RaisedNodes[size-1].iIndex + 1);
1519 m_Vertices[StartInd] = (m_ProjectedNodes[ind2].RaisedNodes[size-1].iIndex + 1);
1520
1521 CompletedCorners.insert(ind1);
1522 CompletedCorners.insert(ind2);
1523 }
1524 }
1525 else
1526 {
1527 int StartInd = bConstX ? 4 : 8;
1528 m_Edges[StartInd++].push_back(m_ProjectedNodes[ind1].RaisedNodes[0].iIndex + 1);
1529 m_Edges[StartInd++].push_back(m_ProjectedNodes[ind2].RaisedNodes[0].iIndex + 1);
1530 m_Edges[StartInd++].push_back(m_ProjectedNodes[ind2].RaisedNodes[size-1].iIndex + 1);
1531 m_Edges[StartInd++].push_back(m_ProjectedNodes[ind1].RaisedNodes[size-1].iIndex + 1);
1532
1533 for ( int i = 1; i < size-1; ++i )
1534 {
1535 if ( bConstX )
1536 {
1537 m_FaceA.push_back(m_ProjectedNodes[ind2].RaisedNodes[i].iIndex + 1);
1538 m_FaceB.push_back(m_ProjectedNodes[ind1].RaisedNodes[i].iIndex + 1);
1539 }
1540 else
1541 {
1542 m_FaceC.push_back(m_ProjectedNodes[ind2].RaisedNodes[i].iIndex + 1);
1543 m_FaceD.push_back(m_ProjectedNodes[ind1].RaisedNodes[i].iIndex + 1);
1544 }
1545 }
1546 }
1547 // Iterate through the column of nodes and match up the corresponding nodes for each of the pair
1548 for ( int i = 0; i < m_ProjectedNodes[ind1].RaisedNodes.size(); ++i )
1549 {
1550 NodePair.first = m_ProjectedNodes[ind1].RaisedNodes[i].iIndex + 1; // RaisedNodes[i].iIndex contains index in the volume mesh
1551 NodePair.second = m_ProjectedNodes[ind2].RaisedNodes[i].iIndex + 1;
1552 VolMeshPairs.push_back( NodePair );
1553 }
1554 }
1555 m_NodePairSets.push_back( VolMeshPairs );
1556 }
1557
1558
1559 int Size = m_ProjectedNodes.size();
1560 for ( int i = 0; i < Size; ++i )
1561 {
1562 if ( EdgeIndices.find(i) == EdgeIndices.end() )
1563 {
1564 m_FaceE.push_back(m_ProjectedNodes[i].RaisedNodes[m_ProjectedNodes[i].RaisedNodes.size()-1].iIndex + 1);
1565 m_FaceF.push_back(m_ProjectedNodes[i].RaisedNodes[0].iIndex + 1);
1566 }
1567 }
1568}
1569
1571{
1572 if (m_Vertices.size() != 8 )
1573 return false;
1574 for ( int i = 0; i < 8; ++i )
1575 {
1577 }
1578
1579 if ( m_Edges.size() != 12 )
1580 return false;
1581 for ( int i = 0; i < 12; ++i )
1582 {
1584 }
1585
1586 if ( m_FaceA.size() == 0 || m_FaceB.size() == 0 || m_FaceC.size() == 0 || m_FaceD.size() == 0
1587 || m_FaceE.size() == 0 || m_FaceF.size() == 0 )
1588 return false;
1592
1593 return true;
1594}
1595
1597{
1598 vector< set<int> > FaceSets;
1599 SetupFaceSets( FaceSets );
1600
1601 int NumNodes = m_VolumeMesh.GetNumNodes();
1602 map<int,vector<int> > FaceSetIndices;
1603
1604 for ( int i = 1; i <= NumNodes; ++i )
1605 {
1606 vector<int> FaceSet = FindFaceSets( FaceSets, i );
1607 if ( FaceSet.size() > 0 )
1608 {
1609 FaceSetIndices[i] = FaceSet;
1610 }
1611 }
1612
1613 const list<int> &Indices = m_VolumeMesh.GetIndices(CMesh::QUADRATIC_TET);
1615 list<int>::const_iterator itIndex;
1616 map<int,vector<int> >::iterator itEndIndices = FaceSetIndices.end();
1617
1618 vector<int> iIndex;
1619 for (itIndex = Indices.begin(); itIndex != Indices.end(); )
1620 {
1621 list<int> Faces;
1622
1623 iIndex.clear();
1624 list<int>::const_iterator itEndIndex = itIndex;
1625 advance( itEndIndex, NumNodes);
1626 iIndex.insert( iIndex.begin(), itIndex, itEndIndex );
1627 for ( int i = 0; i < 4; ++i )
1628 {
1629 if ( FaceSetIndices.find(iIndex[i]+1) == itEndIndices )
1630 continue; // Node not on surface therefore mid node won't be either
1631
1632 for ( int j = i+1; j < 4; ++j )
1633 {
1634
1635 if ( FaceSetIndices.find(iIndex[j]+1) == itEndIndices )
1636 continue; // Node not on surface
1637 AddQuadNodeToSet( i, j, FaceSetIndices[iIndex[i]+1], FaceSetIndices[iIndex[j]+1], iIndex );
1638
1639 }
1640 }
1641
1642 advance(itIndex, NumNodes);
1643 }
1645}
1646
1647void CMesher::SetupFaceSets( vector< set<int> >& FaceSets )
1648{
1649 set<int> FaceSet;
1650 FaceSet.insert( m_FaceA.begin(), m_FaceA.end() );
1651 FaceSet.insert( m_Edges[1].begin(), m_Edges[1].end() );
1652 FaceSet.insert( m_Edges[2].begin(), m_Edges[2].end() );
1653 FaceSet.insert( m_Edges[5].begin(), m_Edges[5].end() );
1654 FaceSet.insert(m_Edges[6].begin(), m_Edges[6].end() );
1655 FaceSet.insert( m_Vertices[1] );
1656 FaceSet.insert( m_Vertices[2] );
1657 FaceSet.insert( m_Vertices[5] );
1658 FaceSet.insert( m_Vertices[6] );
1659 FaceSets.push_back( FaceSet );
1660
1661 FaceSet.clear();
1662 FaceSet.insert( m_FaceB.begin(), m_FaceB.end() );
1663 FaceSet.insert( m_Edges[0].begin(), m_Edges[0].end() );
1664 FaceSet.insert( m_Edges[3].begin(), m_Edges[3].end() );
1665 FaceSet.insert( m_Edges[4].begin(), m_Edges[4].end() );
1666 FaceSet.insert( m_Edges[7].begin(), m_Edges[7].end() );
1667 FaceSet.insert( m_Vertices[0] );
1668 FaceSet.insert( m_Vertices[3] );
1669 FaceSet.insert( m_Vertices[4] );
1670 FaceSet.insert( m_Vertices[7] );
1671 FaceSets.push_back( FaceSet );
1672
1673 FaceSet.clear();
1674 FaceSet.insert( m_FaceC.begin(), m_FaceC.end() );
1675 FaceSet.insert( m_Edges[2].begin(), m_Edges[2].end() );
1676 FaceSet.insert( m_Edges[3].begin(), m_Edges[3].end() );
1677 FaceSet.insert( m_Edges[9].begin(), m_Edges[9].end() );
1678 FaceSet.insert( m_Edges[10].begin(), m_Edges[10].end() );
1679 FaceSet.insert( m_Vertices[2] );
1680 FaceSet.insert( m_Vertices[3] );
1681 FaceSet.insert( m_Vertices[6] );
1682 FaceSet.insert( m_Vertices[7] );
1683 FaceSets.push_back( FaceSet );
1684
1685 FaceSet.clear();
1686 FaceSet.insert( m_FaceD.begin(), m_FaceD.end() );
1687 FaceSet.insert( m_Edges[0].begin(), m_Edges[0].end() );
1688 FaceSet.insert( m_Edges[1].begin(), m_Edges[1].end() );
1689 FaceSet.insert( m_Edges[8].begin(), m_Edges[8].end() );
1690 FaceSet.insert( m_Edges[11].begin(), m_Edges[11].end() );
1691 FaceSet.insert( m_Vertices[0] );
1692 FaceSet.insert( m_Vertices[1] );
1693 FaceSet.insert( m_Vertices[4] );
1694 FaceSet.insert( m_Vertices[5] );
1695 FaceSets.push_back( FaceSet );
1696
1697 FaceSet.clear();
1698 FaceSet.insert( m_FaceE.begin(), m_FaceE.end() );
1699 FaceSet.insert( m_Edges[6].begin(), m_Edges[6].end() );
1700 FaceSet.insert( m_Edges[7].begin(), m_Edges[7].end() );
1701 FaceSet.insert( m_Edges[10].begin(), m_Edges[10].end() );
1702 FaceSet.insert( m_Edges[11].begin(), m_Edges[11].end() );
1703 FaceSet.insert( m_Vertices[4] );
1704 FaceSet.insert( m_Vertices[5] );
1705 FaceSet.insert( m_Vertices[6] );
1706 FaceSet.insert( m_Vertices[7] );
1707 FaceSets.push_back( FaceSet );
1708
1709 FaceSet.clear();
1710 FaceSet.insert( m_FaceF.begin(), m_FaceF.end() );
1711 FaceSet.insert( m_Edges[4].begin(), m_Edges[4].end() );
1712 FaceSet.insert( m_Edges[5].begin(), m_Edges[5].end() );
1713 FaceSet.insert( m_Edges[8].begin(), m_Edges[8].end() );
1714 FaceSet.insert( m_Edges[9].begin(), m_Edges[9].end() );
1715 FaceSet.insert( m_Vertices[0] );
1716 FaceSet.insert( m_Vertices[1] );
1717 FaceSet.insert( m_Vertices[2] );
1718 FaceSet.insert( m_Vertices[3] );
1719 FaceSets.push_back( FaceSet );
1720}
1721
1722vector<int> CMesher::FindFaceSets( vector< set<int> >& FaceSets, int iIndex )
1723{
1724 int i;
1725 vector<int> Indices;
1726 for ( i = 0; i < FaceSets.size(); ++i )
1727 {
1728 if ( FaceSets[i].find( iIndex ) != FaceSets[i].end() )
1729 Indices.push_back(i);
1730 }
1731 return( Indices );
1732}
1733
1734void CMesher::AddQuadNodeToSet( int i, int j, vector<int>& FaceSet1, vector<int>& FaceSet2, vector<int> &Indices )
1735{
1736 int iSize1 = FaceSet1.size();
1737 int iSize2 = FaceSet2.size();
1738
1739 if ( iSize1 == 1 && iSize2 == 1 ) // Both face sets
1740 {
1741 if ( FaceSet1[0] == FaceSet2[0] ) // Same face, add mid node to it
1742 AddQuadNodeToFace( i, j, FaceSet1[0], Indices );
1743 return;
1744 }
1745 else if ( (iSize1 == 1 && iSize2 == 2) || (iSize1 == 2 && iSize2 == 1) ) // One face, one edge
1746 {
1747 if ( iSize1 == 1 )
1748 {
1749 if ( FaceSet1[0] == FaceSet2[0] || FaceSet1[0] == FaceSet2[1] )
1750 AddQuadNodeToFace( i, j, FaceSet1[0], Indices );
1751 }
1752 else
1753 {
1754 if ( FaceSet2[0] == FaceSet1[0] || FaceSet2[0] == FaceSet1[1] )
1755 AddQuadNodeToFace( i, j, FaceSet2[0], Indices );
1756 }
1757 }
1758 else if ( iSize1 == 2 && iSize2 == 2 ) // Both edges
1759 {
1760 if ( (FaceSet1[0] == FaceSet2[0]) && (FaceSet1[1] == FaceSet2[1]) ) // Created from sets so assume sorted
1761 {
1762 AddQuadNodeToEdge( i, j, GetEdge(FaceSet1[0], FaceSet1[1]), Indices ); // Faces same so both have common edge
1763 }
1764 else if ( (FaceSet1[0] == FaceSet2[0]) || (FaceSet1[0] == FaceSet2[1]) ) // One face in common so node on face between two edges
1765 {
1766 AddQuadNodeToFace( i, j, FaceSet1[0], Indices );
1767 }
1768 else if ( (FaceSet1[1] == FaceSet2[0]) || (FaceSet1[1] == FaceSet2[1]) )
1769 {
1770 AddQuadNodeToFace( i, j, FaceSet1[1], Indices );
1771 }
1772 }
1773 else if ( (iSize1 == 1 && iSize2 == 3) || (iSize1 == 3 && iSize2 == 1) ) // One face, one corner
1774 {
1775 if ( iSize1 == 1 )
1776 {
1777 if ( (FaceSet1[0] == FaceSet2[0]) || (FaceSet1[0] == FaceSet2[1]) || (FaceSet1[0] == FaceSet2[2]) )
1778 AddQuadNodeToFace( i, j, FaceSet1[0], Indices );
1779 }
1780 else
1781 {
1782 if ( (FaceSet2[0] == FaceSet1[0]) || (FaceSet2[0] == FaceSet1[1]) || (FaceSet2[0] == FaceSet1[2]) )
1783 AddQuadNodeToFace( i, j, FaceSet2[0], Indices );
1784 }
1785 }
1786 else if ( (iSize1 == 2 && iSize2 == 3) || (iSize1 == 3 && iSize2 == 2) ) // One edge, one corner
1787 {
1788 vector<int> Face1 = iSize1 == 2 ? FaceSet1 : FaceSet2;
1789 vector<int> Face2 = iSize1 == 2 ? FaceSet2 : FaceSet1;
1790
1791 if ( Face1[0] == Face2[0] )
1792 {
1793 if ( Face1[1] == Face2[1] || Face1[1] == Face2[2] )
1794 {
1795 AddQuadNodeToEdge( i, j, GetEdge( Face1[0], Face1[1]), Indices );
1796 }
1797 else
1798 AddQuadNodeToFace( i, j, Face1[0], Indices );
1799 }
1800 else if ( Face1[0] == Face2[1] )
1801 {
1802 if ( Face1[1] == Face2[2] )
1803 {
1804 AddQuadNodeToEdge( i, j, GetEdge( Face1[0], Face1[1] ), Indices);
1805 }
1806 else
1807 AddQuadNodeToFace( i, j, Face1[0], Indices );
1808 }
1809 else if ( Face1[0] == Face2[2] )
1810 {
1811 AddQuadNodeToFace( i, j, Face1[0], Indices );
1812 }
1813 else if ( Face1[1] == Face2[0] || Face1[1] == Face2[1] || Face1[1] == Face2[2] )
1814 {
1815 AddQuadNodeToFace( i, j, Face1[1], Indices );
1816 }
1817 }
1818 else if ( iSize1 == 3 && iSize2 == 3 ) // Both corners
1819 {
1820 // Will only occur if mesh is one element wide between corners - need to code? See notes for 26-11-13
1821 }
1822}
1823
1824void CMesher::AddQuadNodeToFace( int i, int j, int iFace, vector<int> &Indices )
1825{
1826 int iNode = GetQuadNodeToAdd( i, j );
1827 switch (iFace)
1828 {
1829 case FACE_A:
1830 m_FaceA.push_back( Indices[iNode]+1 );
1831 break;
1832 case FACE_B:
1833 m_FaceB.push_back( Indices[iNode]+1 );
1834 break;
1835 case FACE_C:
1836 m_FaceC.push_back( Indices[iNode]+1 );
1837 break;
1838 case FACE_D:
1839 m_FaceD.push_back( Indices[iNode]+1 );
1840 break;
1841 case FACE_E:
1842 m_FaceE.push_back( Indices[iNode]+1 );
1843 break;
1844 case FACE_F:
1845 m_FaceF.push_back( Indices[iNode]+1 );
1846 break;
1847 }
1848}
1849
1850void CMesher::AddQuadNodeToEdge( int i, int j, int iEdge, vector<int> &Indices )
1851{
1852 int iNode = GetQuadNodeToAdd( i, j );
1853 m_Edges[iEdge].push_back( Indices[iNode]+1);
1854}
1855
1856int CMesher::GetEdge( int iFace1, int iFace2 )
1857{
1858 switch ( iFace1 )
1859 {
1860 case FACE_A:
1861 {
1862 switch ( iFace2 )
1863 {
1864 case FACE_C:
1865 return 2;
1866 case FACE_D:
1867 return 1;
1868 case FACE_E:
1869 return 6;
1870 case FACE_F:
1871 return 5;
1872 }
1873 break;
1874 }
1875
1876 case FACE_B:
1877 {
1878 switch ( iFace2 )
1879 {
1880 case FACE_C:
1881 return 3;
1882 case FACE_D:
1883 return 0;
1884 case FACE_E:
1885 return 7;
1886 case FACE_F:
1887 return 4;
1888 }
1889 break;
1890 }
1891
1892 case FACE_C:
1893 {
1894 switch ( iFace2 )
1895 {
1896 case FACE_E:
1897 return 10;
1898 case FACE_F:
1899 return 9;
1900 }
1901 break;
1902 }
1903
1904 case FACE_D:
1905 {
1906 switch ( iFace2 )
1907 {
1908 case FACE_E:
1909 return 11;
1910 case FACE_F:
1911 return 8;
1912 }
1913 break;
1914 }
1915
1916 default:
1917 break;
1918 }
1919 return -1;
1920}
1921
1922int CMesher::GetQuadNodeToAdd( int i, int j )
1923{
1924 if ( i == 0 )
1925 {
1926 if ( j == 1 )
1927 return 4;
1928 if ( j == 2 )
1929 return 6;
1930 if ( j == 3 )
1931 return 7;
1932 }
1933 if ( i == 1 )
1934 {
1935 if ( j == 2 )
1936 return 5;
1937 if ( j == 3 )
1938 return 8;
1939 }
1940 return 9;
1941}
1942
1944{
1945 vector<vector<int> >::iterator itEdge;
1952
1953 for ( itEdge = m_Edges.begin(); itEdge != m_Edges.end(); ++itEdge )
1954 {
1955 RemoveDuplicateFaceNodes( *itEdge );
1956 }
1957}
1958
1959void CMesher::RemoveDuplicateFaceNodes( vector<int>& FaceSet )
1960{
1961 vector<int>::iterator itNewEnd;
1962 sort( FaceSet.begin(), FaceSet.end() );
1963 itNewEnd = unique(FaceSet.begin(), FaceSet.end()); // remove duplicates
1964 FaceSet.erase(itNewEnd, FaceSet.end());
1965}
1966
1967
1968
1969
1970
1971
1972
1973
1974
#define TGERROR(MESSAGE)
Macros used to report the file name and line number to the TexGenError and TexGenLog functions.
Definition: Logger.h:29
#define TGLOG(MESSAGE)
Definition: Logger.h:36
#define NULL
Definition: ShinyConfig.h:50
#define TEXGEN
Helper macro to get the texgen instance.
Definition: TexGen.h:76
vector< CMesh > m_YarnMeshes
Definition: BasicVolumes.h:114
vector< PROJECTED_REGION > m_ProjectedRegions
Definition: BasicVolumes.h:115
vector< int > m_TriangleRegions
Definition: BasicVolumes.h:119
bool CreateBasicVolumes(CTextile &Textile)
bool GetMeshVerticalBounds(const CMesh &Mesh, XYZ Point, double &dMinZ, double &dMaxZ, bool bForceFind=false)
Abstract base class representing the domain in which a textile cell may lie.
Definition: Domain.h:34
const CMesh & GetMesh() const
Get the mesh representing the domain as a surface mesh.
Definition: Domain.h:73
vector< XYZ > GetTranslations(const CYarn &Yarn) const
Get the translation vectors necessary to fully fill the domain.
Definition: Domain.cpp:83
vector< T > m_Data
Definition: MeshData.h:87
Defines the nodes and elements of a surface or volume mesh.
Definition: Mesh.h:58
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
int MergeNodes(const double Tolerance=1e-8)
If any nodes share the same coordinates merge the nodes together and adjust indices accordingly.
Definition: Mesh.cpp:382
vector< pair< int, int > > GetNodePairs(XYZ Vector, const double Tolerance=1e-6) const
Return a list of node pairs (A, B) where A == B + Vector.
Definition: Mesh.cpp:463
const vector< XYZ > & GetNodes() const
Get a const reference to the nodes.
Definition: Mesh.cpp:2656
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
const XYZ & GetNode(int iIndex) const
Get the node with given ID.
Definition: Mesh.cpp:2636
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
@ PYRAMID
Definition: Mesh.h:70
@ QUADRATIC_TET
Definition: Mesh.h:75
int GetNumElements(ELEMENT_TYPE Type) const
Get the number of elements of a given type.
Definition: Mesh.cpp:2586
void Clear()
Empty mesh nodes and indices.
Definition: Mesh.cpp:1448
virtual bool CreateMesh(CTextile &Textile)=0
int TetMeshColumn(vector< RAISED_NODE > Columns[3], set< pair< int, int > > EdgeConstraints[3])
Definition: Mesher.cpp:743
void RaiseNodes(int iIndex)
Definition: Mesher.cpp:307
void BuildEdgeConstraints(vector< RAISED_NODE > Columns[3], set< pair< int, int > > EdgeConstraints[3])
Definition: Mesher.cpp:681
void SaveVolumeMeshToVTK(string Filename)
Definition: Mesher.cpp:101
void AddElement(CMesh::ELEMENT_TYPE Type, const vector< int > &Indices)
Definition: Mesher.cpp:1162
bool GetPairIndices(int iIndex1, int iIndex2, NODE_PAIR &MatchPair)
Definition: Mesher.cpp:1342
vector< int > m_FaceD
Definition: Mesher.h:204
vector< PROJECTED_NODE > m_ProjectedNodes
Definition: Mesher.h:189
void BuildMidSideNode(int iNodeIndex1, int iNodeIndex2, int iYarnIndex, bool bTop)
Definition: Mesher.cpp:613
vector< int > m_FaceF
Definition: Mesher.h:206
bool m_bProjectMidSideNodes
Definition: Mesher.h:192
XYZ GetMidSideNode(int iNodeIndex1, int iNodeIndex2)
Definition: Mesher.cpp:639
pair< int, int > NODE_PAIR
Definition: Mesher.h:114
void BuildMidSideNodes(vector< RAISED_NODE > Columns[3], int iYarnIndex)
Definition: Mesher.cpp:596
int GetEdge(int iFace1, int iFace2)
Definition: Mesher.cpp:1856
void SetupFaceSets(vector< set< int > > &FaceSets)
Definition: Mesher.cpp:1647
bool SplitColumn(PROJECTED_NODE &Node, vector< int > &YarnIndices, vector< vector< RAISED_NODE > > &Column)
Definition: Mesher.cpp:567
void MeshColumn(TRIANGLE Triangle, int iRegion)
Definition: Mesher.cpp:504
double m_dLayerMergeTolerance
Definition: Mesher.h:193
set< pair< int, int > > m_EdgeConstraints
Definition: Mesher.h:179
bool ViolatesEdgeConstraint(const set< pair< int, int > > &EdgeConstraints1, const set< pair< int, int > > &EdgeConstraints2, int h, int h1, int h2)
Definition: Mesher.cpp:1227
void GetEdgePairIndices(const NODE_PAIR_SETS &NodePairSets, int iIndex, set< int > &Match)
Definition: Mesher.cpp:1388
bool SaveNodeSets()
Definition: Mesher.cpp:1570
vector< int > m_FaceE
Definition: Mesher.h:205
CPeriodicBoundaries * m_PeriodicBoundaries
Definition: Mesher.h:197
vector< int > m_FaceC
Definition: Mesher.h:203
int MeshDifficultRegion(vector< RAISED_NODE > Columns[3], int Limits[6], set< pair< int, int > > EdgeConstraints[3])
Definition: Mesher.cpp:878
vector< NODE_PAIR_SET > NODE_PAIR_SETS
Definition: Mesher.h:116
~CMesher(void)
Definition: Mesher.cpp:54
list< MESHER_ELEMENT_DATA > m_ElementData[CMesh::NUM_ELEMENT_TYPES]
Definition: Mesher.h:195
NODE_PAIR_SETS m_NodePairSets
Definition: Mesher.h:187
void AddEdgeConstraint(int i1, int i2)
Definition: Mesher.cpp:1219
bool CreateMesh(CTextile &Textile)
Definition: Mesher.cpp:71
CTextileMaterials * m_Materials
Definition: Mesher.h:211
bool ShouldConnect(vector< RAISED_NODE > &Column1, vector< RAISED_NODE > &Column2, int h1, int h2)
Definition: Mesher.cpp:1247
void SubdivideNodes(int iIndex)
Definition: Mesher.cpp:407
void SortPairs(NODE_PAIR_SET &NodePairs, bool bSwapY)
Definition: Mesher.cpp:1429
double GetBestSeed(int iIndex)
Definition: Mesher.cpp:473
vector< int > m_Vertices
Definition: Mesher.h:208
void ConvertMeshToQuadratic()
Definition: Mesher.cpp:650
vector< int > FindFaceSets(vector< set< int > > &FaceSets, int iIndex)
Definition: Mesher.cpp:1722
void CreateNodeSets(NODE_PAIR_SETS &EdgeNodePairSets, set< int > &CornerIndex, const vector< XYZ > &Repeats)
Definition: Mesher.cpp:1454
void SaveVolumeMeshToABAQUS(string Filename, string TextileName)
Definition: Mesher.cpp:145
vector< int > m_FaceB
Definition: Mesher.h:202
void FillYarnTangentsData()
Definition: Mesher.cpp:1283
vector< vector< int > > m_Edges
Definition: Mesher.h:207
void CreateVolumeMesh(CTextile &Textile)
Definition: Mesher.cpp:208
void AddQuadNodeToEdge(int i, int j, int iEdge, vector< int > &Indices)
Definition: Mesher.cpp:1850
CMesh m_VolumeMesh
Definition: Mesher.h:173
map< pair< int, int >, XYZ > m_MidSideNodeLocations
Definition: Mesher.h:184
vector< NODE_PAIR > NODE_PAIR_SET
Definition: Mesher.h:115
void RemoveDuplicateFaceNodes(vector< int > &FaceSet)
Definition: Mesher.cpp:1959
void AddQuadraticNodesToSets()
Definition: Mesher.cpp:1596
vector< int > m_FaceA
Definition: Mesher.h:201
const list< MESHER_ELEMENT_DATA > * GetElementData(CMesh::ELEMENT_TYPE ElementType)
Definition: Mesher.cpp:1332
void RemoveDuplicateNodes()
Definition: Mesher.cpp:1943
void AddQuadNodeToFace(int i, int j, int iFace, vector< int > &Indices)
Definition: Mesher.cpp:1824
int m_iBoundaryConditions
Definition: Mesher.h:198
int GetQuadNodeToAdd(int i, int j)
Definition: Mesher.cpp:1922
void AddQuadNodeToSet(int i, int j, vector< int > &FaceSeti, vector< int > &FaceSetj, vector< int > &Indices)
Definition: Mesher.cpp:1734
bool m_bQuadratic
Definition: Mesher.h:191
Class used to generate Abaqus output for periodic boundary conditions.
void SetFaceB(vector< int > &B1, vector< int > &B2)
void CreatePeriodicBoundaries(ostream &Output, int iDummyNodeNum, CTextile &Textile, int iBoundarConditions, bool bMatrixOnly)
void SetEdges(vector< int > &Edge)
virtual void SetDomainSize(const CMesh &Mesh)
void SetFaceA(vector< int > &A1, vector< int > &A2)
void SetFaceC(vector< int > &C1, vector< int > &C2)
Class used to generate Abaqus input file for periodic boundary conditions for a textile with sheared ...
Represents a textile cell containing yarns.
Definition: Textile.h:39
const CDomain * GetDomain() const
Definition: Textile.h:287
int GetNumYarns() const
Definition: Textile.cpp:704
const CYarn * GetYarn(int iIndex) const
Definition: Textile.cpp:693
void OutputMaterials(ostream &Output, int iNumYarns, bool bMatrixOnly)
Output materials and assign to yarn element sets.
Definition: Materials.cpp:187
void SetupMaterials(CTextile &Textile)
Set up a material for each unique set of material constants.
Definition: Materials.cpp:31
Represents a yarn consisting of master nodes, section and interpolation function.
Definition: Yarn.h:49
const vector< XYZ > & GetRepeats() const
Definition: Yarn.h:448
bool PointInsideYarn(const XYZ &Point, XYZ *pTangent=NULL, XY *pLoc=NULL, double *pVolumeFraction=NULL, double *pDistanceToSurface=NULL, double dTolerance=1e-9, XYZ *pOrientation=NULL, XYZ *pUp=NULL, bool bSurface=false) const
Determine if the given point lies within the yarn (this function doesn't take the repeats into accoun...
Definition: Yarn.cpp:1336
Namespace containing a series of customised math operations not found in the standard c++ library.
@ FACE_D
Definition: Mesher.h:42
@ FACE_F
Definition: Mesher.h:44
@ FACE_A
Definition: Mesher.h:39
@ FACE_C
Definition: Mesher.h:41
@ FACE_E
Definition: Mesher.h:43
@ FACE_B
Definition: Mesher.h:40
std::string ReplaceFilenameSpaces(std::string Filename)
Replaces spaces in filename with underscore.
Definition: Misc.cpp:130
double GetLength(const XYZ &Point1, const XYZ &Point2)
Get the length between two points.
Definition: mymath.h:540
@ SINGLE_LAYER_RVE
Definition: Misc.h:265
@ MATERIAL_CONTINUUM
Definition: Misc.h:264
@ SHEARED_BC
Definition: Misc.h:267
@ NO_BOUNDARY_CONDITIONS
Definition: Misc.h:270
vector< RAISED_NODE > RaisedNodes
Definition: Mesher.h:105
vector< int > YarnBoundaryIndices
Definition: Mesher.h:94
Structure used to retreive information about a particular point in space.
Definition: Misc.h:217
double dSurfaceDistance
Returns the closest distance from the point to the surface of the yarn.
Definition: Misc.h:226
int iYarnIndex
Index of the yarn, -1 when the point is not inside a yarn.
Definition: Misc.h:218
XYZ Orientation
Local fibre orientation.
Definition: Misc.h:227
XY Location
Location of the point relative to the yarn centerline.
Definition: Misc.h:220
XYZ YarnTangent
Tangent of the yarn centreline.
Definition: Misc.h:219
XYZ Up
Local Up vector.
Definition: Misc.h:228
double dVolumeFraction
Definition: Misc.h:221
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