TexGen
Yarn.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 "Yarn.h"
22#include "Section.h"
23#include "Plane.h"
24#include "Domain.h"
25#include "SectionEllipse.h"
26#include "Textile.h"
27
28using namespace TexGen;
29
30CYarn::CYarn(void)
31: m_iNumSlaveNodes(0)
32, m_iNumSectionPoints(0)
33, m_iNeedsBuilding(ALL)
34, m_bEquiSpacedSectionMesh(true)
35//, m_pParent(NULL)
36{
38}
39
41{
42}
43
44CYarn::CYarn(TiXmlElement &Element)
45: CPropertiesYarn(Element)
46, m_iNumSlaveNodes(0)
47, m_iNumSectionPoints(0)
48, m_iNeedsBuilding(ALL)
49, m_bEquiSpacedSectionMesh(true)
50//, m_pParent(NULL)
51{
53 Element.Attribute("NumSlaveNodes", &m_iNumSlaveNodes);
54 Element.Attribute("NumSectionPoints", &m_iNumSectionPoints);
55 TiXmlElement* pInterpolation = Element.FirstChildElement("Interpolation");
56 if (pInterpolation)
57 {
59 }
60 TiXmlElement* pYarnSection = Element.FirstChildElement("YarnSection");
61 if (pYarnSection)
62 {
64 }
65 TiXmlElement* pFibreDistribution = Element.FirstChildElement("FibreDistribution");
66 if (pFibreDistribution)
67 {
68 // TODO: Implement in a similar way to above
69 const string* pType = pFibreDistribution->Attribute(string("type"));
70 if (pType)
71 {
72 if (*pType == "CFibreDistribution1DQuad")
74 else if (*pType == "CFibreDistributionConst")
75 m_pFibreDistribution = CFibreDistributionConst(*pFibreDistribution);
76 }
77 }
78 FOR_EACH_TIXMLELEMENT(pRepeat, Element, "Repeat")
79 {
80 m_Repeats.push_back(valueify<XYZ>(pRepeat->Attribute("value")));
81 }
82 FOR_EACH_TIXMLELEMENT(pMasterNode, Element, "MasterNode")
83 {
84 m_MasterNodes.push_back(CNode(*pMasterNode));
85 }
86 FOR_EACH_TIXMLELEMENT(pSlaveNode, Element, "SlaveNode")
87 {
88 m_SlaveNodes.push_back(CSlaveNode(*pSlaveNode));
89 }
90 m_AABB.first = valueify<XYZ>(Element.Attribute("AABB.first"));
91 m_AABB.second = valueify<XYZ>(Element.Attribute("AABB.second"));
92 FOR_EACH_TIXMLELEMENT(pSectionAABB, Element, "SectionAABB")
93 {
94 m_SectionAABBs.push_back(make_pair(
95 valueify<XYZ>(pSectionAABB->Attribute("first")),
96 valueify<XYZ>(pSectionAABB->Attribute("second"))));
97 }
98 FOR_EACH_TIXMLELEMENT(pSectionLength, Element, "SectionLength")
99 {
100 m_SectionLengths.push_back(valueify<double>(pSectionLength->Attribute("value")));
101 }
102
103 Element.Attribute("NeedsBuilding", &m_iNeedsBuilding);
104}
105
106void CYarn::PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType)
107{
108 CPropertiesYarn::PopulateTiXmlElement(Element, OutputType);
109
110 Element.SetAttribute("NumSlaveNodes", m_iNumSlaveNodes);
111 Element.SetAttribute("NumSectionPoints", m_iNumSectionPoints);
113 {
114 TiXmlElement Interpolation("Interpolation");
115 m_pInterpolation->PopulateTiXmlElement(Interpolation, OutputType);
116 Element.InsertEndChild(Interpolation);
117 }
118 if (m_pYarnSection)
119 {
120 TiXmlElement YarnSection("YarnSection");
121 m_pYarnSection->PopulateTiXmlElement(YarnSection, OutputType);
122 Element.InsertEndChild(YarnSection);
123 }
125 {
126 TiXmlElement FibreDistribution("FibreDistribution");
127 m_pFibreDistribution->PopulateTiXmlElement(FibreDistribution, OutputType);
128 Element.InsertEndChild(FibreDistribution);
129 }
130 vector<XYZ>::iterator itXYZ;
131 for (itXYZ = m_Repeats.begin(); itXYZ!=m_Repeats.end(); ++itXYZ)
132 {
133 TiXmlElement Repeat("Repeat");
134 Repeat.SetAttribute("value", stringify(*itXYZ));
135 Element.InsertEndChild(Repeat);
136 }
137 int i;
138 for (i=0; i<(int)m_MasterNodes.size(); ++i)
139 {
140 TiXmlElement MasterNode("MasterNode");
141 MasterNode.SetAttribute("index", i);
142 m_MasterNodes[i].PopulateTiXmlElement(MasterNode, OutputType);
143 Element.InsertEndChild(MasterNode);
144 }
145 if (OutputType == OUTPUT_FULL)
146 {
147 vector<CSlaveNode>::iterator itSlaveNode;
148 for (itSlaveNode = m_SlaveNodes.begin(); itSlaveNode!=m_SlaveNodes.end(); ++itSlaveNode)
149 {
150 TiXmlElement SlaveNode("SlaveNode");
151 itSlaveNode->PopulateTiXmlElement(SlaveNode, OutputType);
152 Element.InsertEndChild(SlaveNode);
153 }
154 Element.SetAttribute("AABB.first", stringify(m_AABB.first));
155 Element.SetAttribute("AABB.second", stringify(m_AABB.second));
156 for (i=0; i<(int)m_SectionAABBs.size(); ++i)
157 {
158 TiXmlElement SectionAABB("SectionAABB");
159 SectionAABB.SetAttribute("index", i);
160 SectionAABB.SetAttribute("first", stringify(m_SectionAABBs[i].first));
161 SectionAABB.SetAttribute("second", stringify(m_SectionAABBs[i].second));
162 Element.InsertEndChild(SectionAABB);
163 }
164 for (i=0; i<(int)m_SectionLengths.size(); ++i)
165 {
166 TiXmlElement SectionLength("SectionLength");
167 SectionLength.SetAttribute("index", i);
168 SectionLength.SetAttribute("value", stringify(m_SectionLengths[i]));
169 Element.InsertEndChild(SectionLength);
170 }
171 Element.SetAttribute("NeedsBuilding", m_iNeedsBuilding | VOLUME);
172 }
173 else
174 {
175 Element.SetAttribute("NeedsBuilding", ALL);
176 }
177}
178
180{
181 // Set the yarn defaults
185 SetResolution(20, 40); // Changed default numSectionPoints from 20 8-4-13
186}
187
188void CYarn::SetNodes(const vector<CNode> &Nodes)
189{
190 m_MasterNodes = Nodes;
191 // When the nodes are set the yarn needs to be rebuilt
193}
194
195
196void CYarn::AddNode(const CNode &Node)
197{
198 XYZ NodePos = Node.GetPosition();
199 vector<CNode>::iterator itNode;
200 for ( itNode = m_MasterNodes.begin(); itNode != m_MasterNodes.end(); ++itNode )
201 {
202 if ( itNode->GetPosition() == NodePos )
203 {
204 TGERROR( "Trying to add duplicate node: node at " << Node.GetPosition() << " not added" );
205 return;
206 }
207 }
208 m_MasterNodes.push_back(Node);
209 // When a node is added the yarn needs to be rebuilt
211}
212
213bool CYarn::InsertNode(const CNode &Node, const CNode* pBefore)
214{
215 vector<CNode>::iterator itNode;
216 int i;
217 for (itNode = m_MasterNodes.begin(), i = 0; itNode != m_MasterNodes.end(); ++itNode, ++i)
218 {
219 if (&(*itNode) == pBefore)
220 {
221 m_MasterNodes.insert(itNode, Node);
222 if ( m_pYarnSection->GetType() == "CYarnSectionInterpNode" )
223 {
225 InterpNode.InsertSection( i, InterpNode.GetNodeSection(i) );
226 }
227 // When a node is added we need to rebuild the yarn
229 return true;
230 }
231 }
232 TGERROR("Unable to insert node, given node is not contained within the yarn");
233 return false;
234}
235
236bool CYarn::InsertNode(const CNode &Node, int iIndex)
237{
238 if (iIndex < 0 || iIndex > (int)m_MasterNodes.size())
239 {
240 TGERROR("Unable to insert node, index invalid: " << iIndex);
241 return false;
242 }
243 vector<CNode>::iterator itNode;
244 itNode = m_MasterNodes.begin()+iIndex;
245 m_MasterNodes.insert(itNode, Node);
246
247 if ( m_pYarnSection->GetType() == "CYarnSectionInterpNode" )
248 {
249 CYarnSectionInterpNode* pInterpNodeSection = (CYarnSectionInterpNode*)m_pYarnSection->Copy();
250 const CSection& Section = pInterpNodeSection->GetNodeSection(iIndex);
251 pInterpNodeSection->InsertSection( iIndex, Section );
252 AssignSection(*pInterpNodeSection);
253 delete pInterpNodeSection;
254 }
255
256 // When a node is added we need to rebuild the yarn
258 return true;
259}
260
261bool CYarn::ReplaceNode(int iIndex, CNode NewNode)
262{
263 if (iIndex < 0 || iIndex >= (int)m_MasterNodes.size())
264 return false;
265 XYZ NodePos = NewNode.GetPosition();
266 vector<CNode>::iterator itNode;
267 int i = 0;
268 for ( itNode = m_MasterNodes.begin(); itNode != m_MasterNodes.end(); ++itNode, ++i )
269 {
270 if ( itNode->GetPosition() == NodePos && i != iIndex ) // If i == iIndex position might be same but tangent or Up might have changed so still want to replace
271 {
272 TGERROR( "Trying to replace duplicate node: node at " << NodePos << " not added" );
273 return false;
274 }
275 }
276 m_MasterNodes[iIndex] = NewNode;
277 // When a node is replaced the yarn needs to be rebuilt
279 return true;
280}
281
282bool CYarn::DeleteNode(int iIndex)
283{
284 if (iIndex < 0 || iIndex >= (int)m_MasterNodes.size())
285 return false;
286 m_MasterNodes.erase(m_MasterNodes.begin()+iIndex);
287 if ( m_pYarnSection->GetType() == "CYarnSectionInterpNode" )
288 {
289 CYarnSectionInterpNode* pInterpNodeSection = (CYarnSectionInterpNode*)m_pYarnSection->Copy();
290 pInterpNodeSection->DeleteSection(iIndex);
291 AssignSection(*pInterpNodeSection);
292 }
293
294 // When a node is deleted the yarn needs to be rebuilt
296 return true;
297}
298
299const CNode* CYarn::GetNode(int iIndex) const
300{
301 if (iIndex < 0 || iIndex >= (int)m_MasterNodes.size())
302 return NULL;
303 return &m_MasterNodes[iIndex];
304}
305
306void CYarn::SetResolution(int iNumSlaveNodes, int iNumSectionPoints)
307{
308 m_iNumSlaveNodes = iNumSlaveNodes;
309 m_iNumSectionPoints = iNumSectionPoints;
310
311 // When the resolution is changed the yarn needs to be rebuilt
313}
314
315void CYarn::SetEquiSpacedSectionMesh(bool bEquiSpacedSectionMesh)
316{
317 m_bEquiSpacedSectionMesh = bEquiSpacedSectionMesh;
318
319 // When the resolution is changed the yarn needs to be rebuilt
321}
322
323bool CYarn::SetResolution(int iNumSectionPoints)
324{
325 TGLOGINDENT("Calculating slave node resolution given " << iNumSectionPoints << " section points");
326 double dNodeDistance;
327 double dYarnLength;
328 double dNumNodes;
329 int iNumNodes = 10; // Set the an initial resolution, and refine from here
330 int i, iMaxIterations = 100;
331 for (i=0; i<iMaxIterations; ++i)
332 {
333 // Set the new resolution
334 SetResolution(iNumNodes, iNumSectionPoints);
335 // Build the yarn with given resolution
337 {
338 TGERROR("Unable to calculate slave node resolution");
339 return false;
340 }
341 // Loop over all the slave nodes and sum the circumference of each
342 vector<CSlaveNode>::iterator itSlaveNode;
343 dNodeDistance = 0;
344 for (itSlaveNode = m_SlaveNodes.begin(); itSlaveNode != m_SlaveNodes.end(); ++itSlaveNode)
345 {
346 dNodeDistance += CSection::GetCircumference(itSlaveNode->Get2DSectionPoints());
347 }
348 if (dNodeDistance == 0)
349 {
350 TGERROR("Unable to calculate slave node resolution");
351 return false;
352 }
353 // Dividing the sum of circumferences by the number of nodes and section points gives
354 // the average distance between section points
355 dNodeDistance /= m_SlaveNodes.size() * iNumSectionPoints;
356 dYarnLength = GetRawYarnLength();
357 // Number of nodes can then be calculated with the equation below
358 dNumNodes = (dYarnLength / dNodeDistance)+1;
359 // We then need to round the number from a double to an int
360 iNumNodes = (int)dNumNodes;
361 if (dNumNodes-iNumNodes > 0.5)
362 ++iNumNodes;
363 // If the number of nodes is the same as in the previous iteration or different by 1
364 // then the operation was successful, otherwise do another iteration
365 if (abs(iNumNodes - m_iNumSlaveNodes) <= 1)
366 {
367 TGLOG("Slave node resolution set to " << m_iNumSlaveNodes << " after " << i+1 << " iterations");
368 return true;
369 }
370 };
371 TGERROR("Unable to calculate slave node resolution");
372 return false;
373}
374
375bool CYarn::BuildYarnIfNeeded(int iBuildType) const
376{
377 // If a volume build is required then a surface build is also required
378 if (iBuildType & VOLUME)
379 iBuildType |= SURFACE;
380
381 // If a surface build is required then a line build is also required
382 if (iBuildType & SURFACE)
383 iBuildType |= LINE;
384
385 // If the build type is LINE and it needs building, then build the slave nodes
386 if (iBuildType & m_iNeedsBuilding & LINE)
387 {
388 if (!BuildSlaveNodes())
389 return false;
390 }
391 // If the build type is SURFACE and it needs building, then build the slave nodes
392 if (iBuildType & m_iNeedsBuilding & SURFACE)
393 {
394 if (!BuildSections())
395 return false;
396 }
397 // If the build type is VOLUME and it needs building, then build the slave nodes
398 if (iBuildType & m_iNeedsBuilding & VOLUME)
399 {
400 if (!BuildSectionMeshes())
401 return false;
402 }
403
404 return true;
405}
406
408{
409 TGLOG("Building yarn slave nodes");
410 if (m_MasterNodes.size() <= 1)
411 {
412 TGERROR("Unable to build slave nodes, not enough master nodes specified");
413 assert(false);
414 return false;
415 }
416 if (!m_pInterpolation)
417 {
418 TGERROR("Unable to build slave nodes, no interpolation function specified");
419 assert(false);
420 return false;
421 }
422
423 // Set a default resolution of 20 if no resolution is specified
424/* if (m_iNumSlaveNodes == 0)
425 SetResolution(20);*/
427
428 // Populate m_SectionLengths
429 int i, j;
430 XYZ PrevPos;
431 m_SectionLengths.resize(m_MasterNodes.size()-1);
432
433 // Calculate the section length by summing the distances between the two master nodes
434 // on each end and all the slave nodes in between.
435 for (i=0; i<int(m_MasterNodes.size()-1); ++i)
436 {
437 m_SectionLengths[i] = 0;
438 PrevPos = m_MasterNodes[i].GetPosition();
439 for (j=0; j<int(m_SlaveNodes.size()); ++j)
440 {
441 if (m_SlaveNodes[j].GetIndex() == i)
442 {
443 m_SectionLengths[i] += GetLength(PrevPos, m_SlaveNodes[j].GetPosition());
444 PrevPos = m_SlaveNodes[j].GetPosition();
445 }
446 }
447 m_SectionLengths[i] += GetLength(PrevPos, m_MasterNodes[i+1].GetPosition());
448 }
449
450 // Center-line is built, but everything else needs rebuilding
452
453 return true;
454}
455
457{
458 TGLOG("Building yarn sections");
459 if (m_SlaveNodes.empty())
460 {
461 TGERROR("Unable to build sections, no slave nodes created");
462 assert(false);
463 return false;
464 }
465 if (!m_pYarnSection)
466 {
467 // Assign default circular section with diameter 1 tenth of the length of the yarn
468/* double dDiameter = GetRawYarnLength()/10;
469 AssignSection(CYarnSectionConstant(CSectionEllipse(dDiameter, dDiameter)));*/
470 TGERROR("Unable to build sections, no yarn section specified");
471 assert(false);
472 return false;
473 }
474
475 YARN_POSITION_INFORMATION YarnPositionInfo;
476 YarnPositionInfo.SectionLengths = m_SectionLengths;
477
478 bool bFirst = true;
479 m_AABB = pair<XYZ, XYZ>(XYZ(), XYZ());
480// vector<bool> SectionFirst;
481// SectionFirst.resize(m_MasterNodes.size()-1, true);
482// int iSectionMin, iSectionMax;
483
484 vector<XY> Section;
485 vector<XYZ>::const_iterator itPoint;
486 vector<CSlaveNode>::iterator itSlaveNode;
487 XYZ PrevPos = m_SlaveNodes[0].GetPosition();
488 for (itSlaveNode = m_SlaveNodes.begin(); itSlaveNode != m_SlaveNodes.end(); ++itSlaveNode)
489 {
490/* iSectionMin = iSectionMax = itSlaveNode->GetIndex();
491
492 if (itSlaveNode!=m_SlaveNodes.begin() && (itSlaveNode-1)->GetIndex() != iSectionMin)
493 --iSectionMin;
494 if ((itSlaveNode+1)!=m_SlaveNodes.end() && (itSlaveNode+1)->GetIndex() != iSectionMax)
495 ++iSectionMax;*/
496
497 YarnPositionInfo.dSectionPosition = itSlaveNode->GetT();
498 YarnPositionInfo.iSection = itSlaveNode->GetIndex();
499
500 Section = m_pYarnSection->GetSection(YarnPositionInfo, m_iNumSectionPoints);
501 itSlaveNode->UpdateSectionPoints(&Section);
502
503 PrevPos = itSlaveNode->GetPosition();
504
505 for (itPoint = itSlaveNode->GetSectionPoints().begin(); itPoint != itSlaveNode->GetSectionPoints().end(); ++itPoint)
506 {
507 if (bFirst)
508 {
509 m_AABB.first = m_AABB.second = *itPoint;
510 bFirst = false;
511 }
512 m_AABB.first = Min(m_AABB.first, *itPoint);
513 m_AABB.second = Max(m_AABB.second, *itPoint);
514/* for (iIndex = iSectionMin; iIndex <= iSectionMax; ++iIndex)
515 {
516 if (SectionFirst[iIndex])
517 {
518 m_SectionAABBs[iIndex].first = m_SectionAABBs[iIndex].second = *itPoint;
519 SectionFirst[iIndex] = false;
520 }
521 m_SectionAABBs[iIndex].first = Min(m_SectionAABBs[iIndex].first, *itPoint);
522 m_SectionAABBs[iIndex].second = Max(m_SectionAABBs[iIndex].second, *itPoint);
523 }*/
524 }
525 }
526
528/* const double TOL = 1e-9;
529 m_AABB.first.x -= TOL;
530 m_AABB.first.y -= TOL;
531 m_AABB.first.z -= TOL;
532 m_AABB.second.x += TOL;
533 m_AABB.second.y += TOL;
534 m_AABB.second.z += TOL;
535
536 vector<pair<XYZ, XYZ> >::iterator itSectionAABB;
537 for (itSectionAABB = m_SectionAABBs.begin(); itSectionAABB != m_SectionAABBs.end(); ++itSectionAABB)
538 {
539 itSectionAABB->first.x -= TOL;
540 itSectionAABB->first.y -= TOL;
541 itSectionAABB->first.z -= TOL;
542 itSectionAABB->second.x += TOL;
543 itSectionAABB->second.y += TOL;
544 itSectionAABB->second.z += TOL;
545 }*/
546
547 // Surface points are built
549
550 return true;
551}
552
554{
555 vector<XYZ>::const_iterator itPoint;
556 vector<CSlaveNode>::iterator itSlaveNode;
557 int iIndex;
558 int i, j;
559 int iSlaveNodeMin;
560 int iSlaveNodeMax;
561 m_SectionAABBs.resize(m_MasterNodes.size()-1);
562 for (i=0; i<(int)m_SectionAABBs.size(); ++i)
563 {
564 iSlaveNodeMin = 0;
565 iSlaveNodeMax = (int)m_SlaveNodes.size()-1;
566 for (itSlaveNode = m_SlaveNodes.begin(), j=0; itSlaveNode != m_SlaveNodes.end(); ++itSlaveNode, ++j)
567 {
568 iIndex = itSlaveNode->GetIndex();
569 if (iIndex < i)
570 iSlaveNodeMin = j;
571 if (iIndex > i)
572 {
573 iSlaveNodeMax = j;
574 break;
575 }
576 }
577 bool bFirst = true;
578 for (j=iSlaveNodeMin; j<=iSlaveNodeMax; ++j)
579 {
580 for (itPoint = m_SlaveNodes[j].GetSectionPoints().begin(); itPoint != m_SlaveNodes[j].GetSectionPoints().end(); ++itPoint)
581 {
582 if (bFirst)
583 {
584 m_SectionAABBs[i].first = m_SectionAABBs[i].second = *itPoint;
585 bFirst = false;
586 }
587 m_SectionAABBs[i].first = Min(m_SectionAABBs[i].first, *itPoint);
588 m_SectionAABBs[i].second = Max(m_SectionAABBs[i].second, *itPoint);
589 }
590 }
591 }
592}
593
595{
596 TGLOG("Building yarn section meshes");
597 if (m_SlaveNodes.empty())
598 {
599 TGERROR("Unable to build section meshes, no slave nodes created");
600 assert(false);
601 return false;
602 }
603 if (!m_pYarnSection)
604 {
605 TGERROR("Unable to build section meshes, no yarn section specified");
606 assert(false);
607 return false;
608 }
609
610 if ( m_pYarnSection->GetForceMeshLayers() )
611 {
612 m_pYarnSection->SetSectionMeshLayersEqual(m_iNumSectionPoints);
613 }
614
615 YARN_POSITION_INFORMATION YarnPositionInfo;
616 YarnPositionInfo.SectionLengths = m_SectionLengths;
617
618 vector<XY> Section;
619 CMesh Mesh;
620 vector<CSlaveNode>::iterator itSlaveNode;
621 XYZ PrevPos = m_SlaveNodes[0].GetPosition();
622
623 for (itSlaveNode = m_SlaveNodes.begin(); itSlaveNode != m_SlaveNodes.end(); ++itSlaveNode)
624 {
625 YarnPositionInfo.dSectionPosition = itSlaveNode->GetT();
626 YarnPositionInfo.iSection = itSlaveNode->GetIndex();
627
628 Mesh = m_pYarnSection->GetSectionMesh(YarnPositionInfo, m_iNumSectionPoints, m_bEquiSpacedSectionMesh);
629 if ( Mesh.GetNumNodes() == 0 )
630 return false;
631 itSlaveNode->UpdateSectionMesh(&Mesh);
632
633 PrevPos = itSlaveNode->GetPosition();
634 }
635
636 // Volume mesh points are built
638 return true;
639}
640
642{
643 m_pInterpolation = Interpolation;
644
645 // When a new interpolation is assigned the yarn needs to be rebuilt
647}
648
649void CYarn::AssignSection(const CYarnSection &YarnSection)
650{
651 if ( m_pYarnSection != &YarnSection )
652 m_pYarnSection = YarnSection;
653
654 // When a new section is assigned the yarn needs to be rebuilt
656}
657
659{
660 m_pFibreDistribution = Distribution;
661}
662
663void CYarn::Rotate(WXYZ Rotation, XYZ Origin)
664{
665 vector<CNode>::iterator itNode;
666 for (itNode = m_MasterNodes.begin(); itNode != m_MasterNodes.end(); ++itNode)
667 {
668 itNode->Rotate(Rotation, Origin);
669 }
670 vector<XYZ>::iterator itRepeat;
671 for (itRepeat = m_Repeats.begin(); itRepeat != m_Repeats.end(); ++itRepeat)
672 {
673 *itRepeat = Rotation * (*itRepeat);
674 }
675/* vector<CSlaveNode>::iterator itSlaveNode;
676 for (itSlaveNode = m_SlaveNodes.begin(); itSlaveNode != m_SlaveNodes.end(); ++itSlaveNode)
677 {
678 itSlaveNode->Rotate(Rotation, Origin);
679 }*/
680 // Will need to rebuild for the AABBs to be re-created properly
682}
683
685{
686 vector<CNode>::iterator itNode;
687 for (itNode = m_MasterNodes.begin(); itNode != m_MasterNodes.end(); ++itNode)
688 {
689 itNode->Translate(Vector);
690 }
691/* vector<CSlaveNode>::iterator itSlaveNode;
692 for (itSlaveNode = m_SlaveNodes.begin(); itSlaveNode != m_SlaveNodes.end(); ++itSlaveNode)
693 {
694 itSlaveNode->Translate(Vector);
695 }*/
696
697 // Will need to rebuild slave nodes, AABBs, etc... to be translated (could easily be translated as well
698 // but this method is more robust, if this becomes a performance issue recode)
700}
701
703{
704 // If the yarn needs building then build it before creating the mesh
706 return false;
707
708 XYZ Min, Max;
709
710 CMesh AABB;
711
712 // Find AABB
713 vector<CSlaveNode>::iterator itNode;
714 vector<XYZ>::const_iterator itSectionPoint;
715
716 for (itNode = m_SlaveNodes.begin(); itNode != m_SlaveNodes.end(); ++itNode)
717 {
718 const vector<XYZ> NodeSectionPoints = itNode->GetSectionPoints();
719
720 for (itSectionPoint = NodeSectionPoints.begin(); itSectionPoint != NodeSectionPoints.end(); ++itSectionPoint)
721 {
722 if (itNode == m_SlaveNodes.begin() && itSectionPoint == NodeSectionPoints.begin())
723 Min = Max = *itSectionPoint;
724 else
725 {
726 Min = ::Min(Min, *itSectionPoint);
727 Max = ::Max(Max, *itSectionPoint);
728 }
729 }
730 }
731
732 /*for (itNode = m_SlaveNodes.begin(); itNode != m_SlaveNodes.end(); ++itNode)
733 {
734 for (itSectionPoint = itNode->GetSectionPoints().begin(); itSectionPoint != itNode->GetSectionPoints().end(); ++itSectionPoint)
735 {
736 if (itNode == m_SlaveNodes.begin() && itSectionPoint == itNode->GetSectionPoints().begin())
737 Min = Max = *itSectionPoint;
738 else
739 {
740 Min = ::Min(Min, *itSectionPoint);
741 Max = ::Max(Max, *itSectionPoint);
742 }
743 }
744 }*/
745
746 // Add nodes to the mesh
747 // Adds bounding box
748 AABB.AddNode(Min);
749 AABB.AddNode(XYZ(Max.x, Min.y, Min.z));
750 AABB.AddNode(XYZ(Max.x, Max.y, Min.z));
751 AABB.AddNode(XYZ(Min.x, Max.y, Min.z));
752 AABB.AddNode(XYZ(Min.x, Min.y, Max.z));
753 AABB.AddNode(XYZ(Max.x, Min.y, Max.z));
754 AABB.AddNode(Max);
755 AABB.AddNode(XYZ(Min.x, Max.y, Max.z));
756
757 // Add indices to the mesh
758 vector<int> Indices;
759 Indices.push_back(0);
760 Indices.push_back(1);
761 Indices.push_back(2);
762 Indices.push_back(3);
763 Indices.push_back(4);
764 Indices.push_back(5);
765 Indices.push_back(6);
766 Indices.push_back(7);
767
768 AABB.AddElement(CMesh::HEX, Indices);
769
770// AABB.ConvertHextoQuad();
771
772 Mesh.InsertMesh(AABB);
773
774 return true;
775}
776
777bool CYarn::AddAABBToMesh(CMesh &Mesh, const vector<pair<int, int> > &RepeatLimits) const
778{
779 if (m_Repeats.size() != RepeatLimits.size())
780 {
781 TGERROR("Unable to create repeated AABB mesh, number of repeats (" << m_Repeats.size() << ") doesn't match the number of limits (" << RepeatLimits.size() << ")");
782 assert(false);
783 return false;
784 }
785
786 CMesh AABB;
787
788 if (!AddAABBToMesh(AABB))
789 return false;
790
791 vector<XYZ>::const_iterator itRepeat;
792 vector<pair<int, int> >::const_iterator itLimits;
793 for (itRepeat = m_Repeats.begin(), itLimits = RepeatLimits.begin(); itRepeat != m_Repeats.end() && itLimits != RepeatLimits.end(); ++itRepeat, ++itLimits)
794 {
795 AABB.CopySelfToRange(*itRepeat, itLimits->first, itLimits->second);
796 }
797
798 Mesh.InsertMesh(AABB);
799
800 return true;
801}
802
804{
805 vector<CNode>::const_iterator itNode;
806 for (itNode = m_MasterNodes.begin(); itNode != m_MasterNodes.end(); ++itNode)
807 {
808 Mesh.AddNode(itNode->GetPosition());
809 }
810 return true;
811}
812
814{
816 return false;
817 int iStartIndex = Mesh.GetNumNodes();
818 vector<CSlaveNode>::iterator itSlaveNode;
819 for (itSlaveNode = m_SlaveNodes.begin(); itSlaveNode != m_SlaveNodes.end(); ++itSlaveNode)
820 {
821 Mesh.AddNode(itSlaveNode->GetPosition());
822 }
823 int iEndIndex = Mesh.GetNumNodes();
824
825 vector<int> Indices;
826 Indices.push_back(iStartIndex);
827 Indices.push_back(iEndIndex);
828 Mesh.AddElement(CMesh::POLYLINE, Indices);
829
830 return true;
831}
832
833bool CYarn::AddSurfaceToMesh(CMesh &Mesh, const CDomain &Domain, bool bAddEndCaps, bool bFillGaps) const
834{
835 CMesh YarnMesh;
836 if (AddSurfaceToMesh(YarnMesh, Domain.GetTranslations(*this), bAddEndCaps))
837 {
838 Domain.ClipMeshToDomain(YarnMesh, bFillGaps );
839 Mesh.InsertMesh(YarnMesh);
840 return true;
841 }
842 else
843 return false;
844}
845
846bool CYarn::AddSurfaceToMesh( CMesh &Mesh, const CDomain &Domain, vector<CMesh> &DomainMeshes ) const
847{
848 CMesh YarnMesh;
849 if (AddSurfaceToMesh(YarnMesh, Domain.GetTranslations(*this)))
850 {
851 if ( !Domain.ClipMeshToDomain(YarnMesh, DomainMeshes) )
852 return false;
853 Mesh.InsertMesh(YarnMesh);
854 return true;
855 }
856 else
857 return false;
858}
859
860bool CYarn::AddSurfaceToMesh(CMesh &Mesh, bool bAddEndCaps) const
861{
862 TGLOG("Adding yarn surface to mesh");
863 // If the yarn needs building then build it before creating the mesh
865 return false;
866
867 // Check the number of section points on all the nodes is the same
868 int iNumPoints = -1;
869 int iNumNodes = (int)m_SlaveNodes.size();
870 vector<CSlaveNode>::iterator itNode;
871 for (itNode = m_SlaveNodes.begin(); itNode != m_SlaveNodes.end(); ++itNode)
872 {
873 if (iNumPoints == -1)
874 {
875 iNumPoints = (int)itNode->GetSectionPoints().size();
876 }
877 else if (iNumPoints != (int)itNode->GetSectionPoints().size())
878 {
879 // Cannot create surface mesh if the number of section points is not the same for all nodes
880 TGERROR("Unable to create surface mesh, number of section points is not the same for all slave nodes");
881 assert(false);
882 return false;
883 }
884 }
885
886 // Add nodes to the mesh
887 vector<XYZ>::const_iterator itSectionPoint;
888 int iFirstNode = (int)Mesh.GetNumNodes();
889 for (itNode = m_SlaveNodes.begin(); itNode != m_SlaveNodes.end(); ++itNode)
890 {
891 for (itSectionPoint = itNode->GetSectionPoints().begin(); itSectionPoint != itNode->GetSectionPoints().end(); ++itSectionPoint)
892 {
893 Mesh.AddNode(*itSectionPoint);
894 }
895 }
896
897 // Create the surface mesh elements
898 int i, j, u, v;
899 for (i=0; i<iNumNodes-1; ++i)
900 {
901 for (j=0; j<iNumPoints; ++j)
902 {
903 vector<int> Indices;
904 // Add quad (if triangles are needed they can be converted to triangles later)
905 u = i; v = j; if (v == iNumPoints) v = 0; Indices.push_back(iFirstNode+v+u*iNumPoints);
906 u = i+1; v = j; if (v == iNumPoints) v = 0; Indices.push_back(iFirstNode+v+u*iNumPoints);
907 u = i+1; v = j+1; if (v == iNumPoints) v = 0; Indices.push_back(iFirstNode+v+u*iNumPoints);
908 u = i; v = j+1; if (v == iNumPoints) v = 0; Indices.push_back(iFirstNode+v+u*iNumPoints);
909 Mesh.AddElement(CMesh::QUAD, Indices);
910 }
911 }
912
913 if (bAddEndCaps)
914 AddEndCapsToMesh(Mesh);
915
916 return true;
917}
918
920{
921 if (m_SlaveNodes.empty())
922 return;
923
924 const CSlaveNode &StartNode = m_SlaveNodes[0];
925 const CSlaveNode &EndNode = m_SlaveNodes[m_SlaveNodes.size()-1];
926
927 if (StartNode.GetPosition() == EndNode.GetPosition())
928 return;
929
930 CMesh StartMesh, EndMesh;
931
934
935 XYZ StartSide = CrossProduct(StartNode.GetTangent(), StartNode.GetUp());
936 XYZ EndSide = CrossProduct(EndNode.GetTangent(), EndNode.GetUp());
937
938 StartMesh.Rotate(WXYZ(StartSide, StartNode.GetUp(), -StartNode.GetTangent()));
939 EndMesh.Rotate(WXYZ(EndSide, EndNode.GetUp(), -EndNode.GetTangent()));
940
941 EndMesh.FlipNormals();
942
943 Mesh.InsertMesh(StartMesh, StartNode.GetPosition());
944 Mesh.InsertMesh(EndMesh, EndNode.GetPosition());
945}
946
947bool CYarn::AddSurfaceToMesh(CMesh &Mesh, const vector<pair<int, int> > &RepeatLimits) const
948{
949 if (m_Repeats.size() != RepeatLimits.size())
950 {
951 TGERROR("Unable to create repeated surface mesh, number of repeats (" << m_Repeats.size() << ") doesn't match the number of limits (" << RepeatLimits.size() << ")");
952 assert(false);
953 return false;
954 }
955
956 CMesh YarnMesh;
957
958 if (!AddSurfaceToMesh(YarnMesh))
959 return false;
960
961 vector<XYZ>::const_iterator itRepeat;
962 vector<pair<int, int> >::const_iterator itLimits;
963 for (itRepeat = m_Repeats.begin(), itLimits = RepeatLimits.begin(); itRepeat != m_Repeats.end() && itLimits != RepeatLimits.end(); ++itRepeat, ++itLimits)
964 {
965 YarnMesh.CopySelfToRange(*itRepeat, itLimits->first, itLimits->second);
966 }
967
968 YarnMesh.MergeNodes();
969 YarnMesh.RemoveOpposingTriangles();
970
971 Mesh.InsertMesh(YarnMesh);
972
973 return true;
974}
975
976bool CYarn::AddSurfaceToMesh(CMesh &Mesh, const vector<XYZ> &Translations, bool bAddEndCaps) const
977{
978 CMesh SingleYarnMesh, FinalYarnMesh;
979
980 if (!AddSurfaceToMesh(SingleYarnMesh, bAddEndCaps))
981 return false;
982
983 vector<XYZ>::const_iterator itTranslation;
984 for (itTranslation = Translations.begin(); itTranslation != Translations.end(); ++itTranslation)
985 {
986 FinalYarnMesh.InsertMesh(SingleYarnMesh, *itTranslation);
987 }
988
989 FinalYarnMesh.MergeNodes();
990 FinalYarnMesh.RemoveOpposingTriangles();
991
992 Mesh.InsertMesh(FinalYarnMesh);
993
994 return true;
995}
996
997bool CYarn::AddVolumeToMesh(CMesh &Mesh, const CDomain &Domain) const
998{
999 CMesh YarnMesh;
1000 if (AddVolumeToMesh(YarnMesh, Domain.GetTranslations(*this)))
1001 {
1002 Domain.ClipMeshToDomain(YarnMesh);
1003 Mesh.InsertMesh(YarnMesh);
1004 return true;
1005 }
1006 else
1007 return false;
1008}
1009
1011{
1012 TGLOG("Adding yarn volume to mesh");
1013 // Build the yarn with section meshes if needed
1015 return false;
1016
1017 // Check the section meshes are compatible
1018 bool bFirst = true;
1019 CMesh ReferenceMesh;
1020// int iNumNodes = (int)m_SlaveNodes.size();
1021 vector<CSlaveNode>::iterator itNode;
1022 for (itNode = m_SlaveNodes.begin(); itNode != m_SlaveNodes.end(); ++itNode)
1023 {
1024 if (bFirst)
1025 {
1026 ReferenceMesh = itNode->GetSectionMesh();
1027 bFirst = false;
1028 }
1029 else
1030 {
1031 // Check mesh is compatible
1032 bool bCompatible = ReferenceMesh.GetNumNodes() == itNode->GetSectionMesh().GetNumNodes();
1033 int i;
1034 for (i = 0; i < CMesh::NUM_ELEMENT_TYPES; ++i)
1035 {
1036 if (!bCompatible)
1037 break;
1038 if (ReferenceMesh.GetIndices((CMesh::ELEMENT_TYPE)i) != itNode->GetSectionMesh().GetIndices((CMesh::ELEMENT_TYPE)i))
1039 bCompatible = false;
1040 }
1041 if (!bCompatible)
1042 {
1043 // Cannot create surface mesh if the section meshes are not compatible
1044 TGERROR("Unable to create volume mesh, not all section meshes are compatible");
1045 assert(false);
1046 return false;
1047 }
1048 }
1049 }
1050
1051 // Add nodes and elements to the mesh
1052 list<int>::const_iterator itIndex;
1053 int iPrevIndex = -1;
1054 int iIndex;
1055 int aiTriangles[3];
1056 int aiQuads[4];
1057 for (itNode = m_SlaveNodes.begin(); itNode != m_SlaveNodes.end(); ++itNode)
1058 {
1059 const CMesh &SectionMesh = itNode->GetSectionMesh();
1060 iIndex = Mesh.InsertNodes(SectionMesh);
1061 const list<int> &PolygonIndices = SectionMesh.GetIndices(CMesh::POLYGON);
1062 for ( itIndex = PolygonIndices.begin(); itIndex != PolygonIndices.end(); ++itIndex )
1063 {
1064 Mesh.GetIndices(CMesh::POLYGON).push_back(*(itIndex) + iIndex);
1065 }
1066
1067 if (iPrevIndex != -1)
1068 {
1069 const list<int> &TriIndices = SectionMesh.GetIndices(CMesh::TRI);
1070 for (itIndex = TriIndices.begin(); itIndex != TriIndices.end(); )
1071 {
1072 aiTriangles[0] = *(itIndex++);
1073 aiTriangles[1] = *(itIndex++);
1074 aiTriangles[2] = *(itIndex++);
1075
1076 // Element node ordering as defined in VTK
1077 Mesh.GetIndices(CMesh::WEDGE).push_back(aiTriangles[0] + iPrevIndex);
1078 Mesh.GetIndices(CMesh::WEDGE).push_back(aiTriangles[1] + iPrevIndex);
1079 Mesh.GetIndices(CMesh::WEDGE).push_back(aiTriangles[2] + iPrevIndex);
1080
1081 Mesh.GetIndices(CMesh::WEDGE).push_back(aiTriangles[0] + iIndex);
1082 Mesh.GetIndices(CMesh::WEDGE).push_back(aiTriangles[1] + iIndex);
1083 Mesh.GetIndices(CMesh::WEDGE).push_back(aiTriangles[2] + iIndex);
1084 }
1085 const list<int> &QuadIndices = SectionMesh.GetIndices(CMesh::QUAD);
1086 for (itIndex = QuadIndices.begin(); itIndex != QuadIndices.end(); )
1087 {
1088 aiQuads[0] = *(itIndex++);
1089 aiQuads[1] = *(itIndex++);
1090 aiQuads[2] = *(itIndex++);
1091 aiQuads[3] = *(itIndex++);
1092
1093 // Element node ordering as defined in VTK
1094 Mesh.GetIndices(CMesh::HEX).push_back(aiQuads[0] + iIndex);
1095 Mesh.GetIndices(CMesh::HEX).push_back(aiQuads[1] + iIndex);
1096 Mesh.GetIndices(CMesh::HEX).push_back(aiQuads[2] + iIndex);
1097 Mesh.GetIndices(CMesh::HEX).push_back(aiQuads[3] + iIndex);
1098
1099 Mesh.GetIndices(CMesh::HEX).push_back(aiQuads[0] + iPrevIndex);
1100 Mesh.GetIndices(CMesh::HEX).push_back(aiQuads[1] + iPrevIndex);
1101 Mesh.GetIndices(CMesh::HEX).push_back(aiQuads[2] + iPrevIndex);
1102 Mesh.GetIndices(CMesh::HEX).push_back(aiQuads[3] + iPrevIndex);
1103 }
1104 }
1105 iPrevIndex = iIndex;
1106 }
1107 return true;
1108}
1109
1110bool CYarn::AddVolumeToMesh(CMesh &Mesh, const vector<pair<int, int> > &RepeatLimits) const
1111{
1112 if (m_Repeats.size() != RepeatLimits.size())
1113 {
1114 TGERROR("Unable to create repeated volume mesh, number of repeats (" << m_Repeats.size() << ") doesn't match the number of limits (" << RepeatLimits.size() << ")");
1115 assert(false);
1116 return false;
1117 }
1118
1119 CMesh YarnMesh;
1120
1121 if (!AddVolumeToMesh(YarnMesh))
1122 return false;
1123
1124 vector<XYZ>::const_iterator itRepeat;
1125 vector<pair<int, int> >::const_iterator itLimits;
1126 for (itRepeat = m_Repeats.begin(), itLimits = RepeatLimits.begin(); itRepeat != m_Repeats.end() && itLimits != RepeatLimits.end(); ++itRepeat, ++itLimits)
1127 {
1128 YarnMesh.CopySelfToRange(*itRepeat, itLimits->first, itLimits->second);
1129 }
1130
1131 YarnMesh.MergeNodes();
1132
1133 Mesh.InsertMesh(YarnMesh);
1134
1135 return true;
1136}
1137
1138bool CYarn::AddVolumeToMesh(CMesh &Mesh, const vector<XYZ> &Translations) const
1139{
1140 CMesh SingleYarnMesh, FinalYarnMesh;
1141
1142 if (!AddVolumeToMesh(SingleYarnMesh))
1143 return false;
1144
1145 vector<XYZ>::const_iterator itTranslation;
1146 for (itTranslation = Translations.begin(); itTranslation != Translations.end(); ++itTranslation)
1147 {
1148 FinalYarnMesh.InsertMesh(SingleYarnMesh, *itTranslation);
1149 }
1150
1151 FinalYarnMesh.MergeNodes();
1152 FinalYarnMesh.RemoveOpposingTriangles();
1153
1154 Mesh.InsertMesh(FinalYarnMesh);
1155
1156 return true;
1157}
1158
1160{
1161 TGLOG("Adding centre plane to mesh");
1162 // Build the yarn with section meshes if needed
1164 return false;
1165
1166 YARN_POSITION_INFORMATION YarnPositionInfo;
1167 YarnPositionInfo.SectionLengths = m_SectionLengths;
1168
1169 vector<CSlaveNode>::iterator itSlaveNode;
1170 vector<XY> Points2D;
1171 int iNumPoints = m_iNumSectionPoints / 2;
1172
1173 CMesh YarnMesh;
1174
1175 // Add nodes to mesh
1176 for (itSlaveNode = m_SlaveNodes.begin(); itSlaveNode != m_SlaveNodes.end(); ++itSlaveNode)
1177 {
1178 vector<XY> StartEnd;
1179 double xSpacing, ySpacing;
1180
1181 YarnPositionInfo.dSectionPosition = itSlaveNode->GetT();
1182 YarnPositionInfo.iSection = itSlaveNode->GetIndex();
1183
1184 // GetSection called with two points will return the points at 0 and 180 degrees
1185 // (ie the outer points of the horizontal axis of the section)
1186 // Then interpolate between these points to generate the mesh
1187 StartEnd = m_pYarnSection->GetSection(YarnPositionInfo, 2);
1188 xSpacing = (StartEnd[1].x - StartEnd[0].x)/(iNumPoints-1);
1189 ySpacing = (StartEnd[1].y - StartEnd[0].y)/(iNumPoints-1);
1190
1191 for ( int i = 0; i < iNumPoints; ++i )
1192 {
1193 XY Point(StartEnd[0].x + i*xSpacing, StartEnd[0].y + i*ySpacing);
1194 XYZ Point3D = itSlaveNode->GetPointOnSection(Point);
1195 YarnMesh.AddNode(Point3D);
1196 }
1197
1198 }
1199 int iOffset = Mesh.InsertNodes(YarnMesh);
1200
1201 // Add elements to the mesh
1202 list<int>::const_iterator itIndex;
1203
1204 int iIndex = 0, iSlaveIndex = 0;
1205
1206 for (iSlaveIndex = 0; iSlaveIndex < m_SlaveNodes.size()-1; ++iSlaveIndex)
1207 {
1208
1209 for (int i = 0; i < iNumPoints-1; ++i )
1210 {
1211 Mesh.GetIndices(CMesh::QUAD).push_back(i+(iSlaveIndex)*iNumPoints + iOffset);
1212 Mesh.GetIndices(CMesh::QUAD).push_back(i+(iSlaveIndex+1)*iNumPoints + iOffset);
1213 Mesh.GetIndices(CMesh::QUAD).push_back(i+1+(iSlaveIndex+1)*iNumPoints + iOffset);
1214 Mesh.GetIndices(CMesh::QUAD).push_back(i+1+(iSlaveIndex)*iNumPoints + iOffset);
1215 }
1216 }
1217 return true;
1218}
1219
1220bool CYarn::AddCentrePlaneToMesh(CMesh &Mesh, const CDomain &Domain) const
1221{
1222 CMesh YarnMesh;
1223 if (AddCentrePlaneToMesh(YarnMesh, Domain.GetTranslations(*this)))
1224 {
1225 Domain.ClipMeshToDomain(YarnMesh);
1226 Mesh.InsertMesh(YarnMesh);
1227 return true;
1228 }
1229 else
1230 return false;
1231}
1232
1233bool CYarn::AddCentrePlaneToMesh(CMesh &Mesh, const vector<XYZ> &Translations) const
1234{
1235 CMesh SingleYarnMesh, FinalYarnMesh;
1236
1237 if (!AddCentrePlaneToMesh(SingleYarnMesh))
1238 return false;
1239
1240 vector<XYZ>::const_iterator itTranslation;
1241 for (itTranslation = Translations.begin(); itTranslation != Translations.end(); ++itTranslation)
1242 {
1243 FinalYarnMesh.InsertMesh(SingleYarnMesh, *itTranslation);
1244 }
1245
1246 FinalYarnMesh.MergeNodes();
1247
1248 Mesh.InsertMesh(FinalYarnMesh);
1249
1250 return true;
1251}
1252
1254{
1255 m_Repeats.push_back(Repeat);
1256}
1257
1259{
1260 m_Repeats.clear();
1261}
1262
1263void CYarn::SetRepeats(const vector<XYZ> &Repeats)
1264{
1265 m_Repeats = Repeats;
1266}
1267
1269{
1270 if (m_MasterNodes.empty())
1271 return false;
1272 XYZ Origin = m_MasterNodes.front().GetPosition();
1273 XYZ End = m_MasterNodes.back().GetPosition();
1274 XYZ YarnVec = End - Origin;
1275 const double dTolerance = 1e-6;
1276 if (GetLength(YarnVec, Repeat) < dTolerance)
1277 return true;
1278 if (GetLength(YarnVec, -Repeat) < dTolerance)
1279 return true;
1280 return false;
1281}
1282
1284{
1285 vector<CNode>::iterator itNode;
1286 for (itNode = m_MasterNodes.begin(); itNode != m_MasterNodes.end(); ++itNode)
1287 {
1288 itNode->SetTangent(XYZ()); // Set to 0
1289 itNode->SetUp(XYZ()); // Set to 0
1290 }
1291}
1292
1293void CYarn::StraightenYarn(double dStraightness)
1294{
1295 TGLOG("Straightening yarn " << dStraightness);
1296 int i, j;
1297 double dAngle;
1298 XYZ DeltaPos1, DeltaPos2, Pos;
1299 XYZ Axis;
1300 WXYZ Rotation;
1301 for (i=1; i<(int)m_MasterNodes.size()-1; ++i)
1302 {
1303 Pos = m_MasterNodes[i].GetPosition();
1304 DeltaPos1 = Pos - m_MasterNodes[i-1].GetPosition();
1305 DeltaPos2 = m_MasterNodes[i+1].GetPosition() - Pos;
1306
1307 Normalise(DeltaPos1);
1308 Normalise(DeltaPos2);
1309
1310 dAngle = DotProduct(DeltaPos1, DeltaPos2);
1311
1312 if (dAngle > 1)
1313 dAngle = 1;
1314 if (dAngle < -1)
1315 dAngle = -1;
1316
1317 dAngle = acos(dAngle);
1318
1319 if (dAngle > 0)
1320 {
1321 Axis = CrossProduct(DeltaPos2, DeltaPos1);
1322 Normalise(Axis);
1323 dAngle = dAngle * dStraightness;
1324 Rotation = WXYZ(Axis, dAngle);
1325
1326 for (j=i+1; j<(int)m_MasterNodes.size(); ++j)
1327 {
1328 m_MasterNodes[j].SetPosition(Pos + Rotation * (m_MasterNodes[j].GetPosition()-Pos));
1329 }
1330 }
1331 }
1332
1334}
1335
1336bool CYarn::PointInsideYarn(const XYZ &Point, XYZ *pTangent, XY *pLoc, double* pVolumeFraction, double* pDistanceToSurface, double dTolerance, XYZ *pOrientation, XYZ *pUp, bool bSurface) const
1337{
1338 //PROFILE_FUNC()
1340 return false;
1341
1342 if (!PointInsideBox(Point, m_AABB.first, m_AABB.second, dTolerance))
1343 return false;
1344
1345 bool bSectionConstant = m_pYarnSection->GetType() == "CYarnSectionConstant";
1346 if ( pOrientation && !bSectionConstant )
1347 {
1348 if ( !BuildYarnIfNeeded(VOLUME) ) // Only need to build the volume mesh if pOrientation == true and varying sections
1349 return false;
1350 }
1351
1352 int i;
1353 CSlaveNode N;
1354 double u;
1355 m_pInterpolation->Initialise(m_MasterNodes);
1356
1357 YARN_POSITION_INFORMATION YarnPositionInfo;
1358 YarnPositionInfo.SectionLengths = m_SectionLengths;
1359 vector<XY> Section;
1360
1361 bool bIsInside = false;
1362
1363 XY Loc;
1364 XYZ Relative, Up, Side;
1365 int iNumSegments = (int)m_MasterNodes.size()-1;
1366
1367 for (i=0; i<iNumSegments; ++i)
1368 {
1369 if (!PointInsideBox(Point, m_SectionAABBs[i].first, m_SectionAABBs[i].second, dTolerance))
1370 continue;
1371 if (FindPlaneContainingPoint(Point, u, dTolerance, i))
1372 {
1373 //TGLOG("Converged point inside yarn after " << iIterations << " iterations");
1374 // cout << "Num iterations: " << iIterations << endl;
1375
1376 N = m_pInterpolation->GetNode(m_MasterNodes, i, u);
1377
1378 YarnPositionInfo.dSectionPosition = N.GetT();
1379 YarnPositionInfo.iSection = N.GetIndex();
1380 Section = m_pYarnSection->GetSection(YarnPositionInfo, m_iNumSectionPoints);
1381 N.UpdateSectionPoints(&Section);
1382
1383 const vector<XY> &SectionPoints = N.Get2DSectionPoints();
1384
1385 // Calculate the location of the point projected on to the cross section plane
1386 Relative = Point - N.GetPosition();
1387 Up = N.GetUp();
1388 Side = N.GetSide();
1389 Loc.x = DotProduct(Side, Relative);
1390 Loc.y = DotProduct(Up, Relative);
1391
1392 // Check if point is inside min/max box of section.
1393 XY Min, Max;
1394 GetMinMaxXY( SectionPoints, Min, Max );
1395 if ( Loc.x < Min.x || Loc.x > Max.x || Loc.y < Min.y || Loc.y > Max.y )
1396 continue;
1397
1398 {
1399 //PROFILE_BLOCK( PointInside )
1400 if (!bSurface )
1401 bIsInside = PointInside( Loc, SectionPoints );
1402 else
1403 bIsInside = true; // If surface assume that only exporting yarns and that been sent centre point
1404 // of element which must be inside (or on surface)
1405 // If this assumption changes will need to look at how PointInside function
1406 // works for point on or very close to surface
1407 }
1408
1409 if ( bIsInside )
1410 {
1411 if (pTangent)
1412 {
1413 *pTangent = N.GetTangent();
1414 }
1415 if (pLoc)
1416 {
1417 *pLoc = Loc;
1418 }
1419 if (pVolumeFraction)
1420 {
1422 {
1423 double dFibreArea = GetFibreArea(m_pParent->GetGeometryScale()+"^2");
1424 if (dFibreArea == 0)
1425 dFibreArea = m_pParent->GetFibreArea(m_pParent->GetGeometryScale()+"^2");
1426 vector<XY> SectionPoints = N.Get2DSectionPoints();
1427 if( N.GetAngle() != 0.0 )
1428 {
1429 double CosAng = cos( N.GetAngle() );
1430 vector<XY>::iterator itSectionPoints;
1431 for ( itSectionPoints = SectionPoints.begin(); itSectionPoints != SectionPoints.end(); ++itSectionPoints )
1432 {
1433 XY Point = *itSectionPoints;
1434 Point.x = Point.x * CosAng;
1435 *itSectionPoints = Point;
1436 }
1437 }
1438 *pVolumeFraction = m_pFibreDistribution->GetVolumeFraction(SectionPoints, dFibreArea, Loc);
1439 //*pVolumeFraction = m_pFibreDistribution->GetVolumeFraction(N.Get2DSectionPoints(), dFibreArea, Loc);
1440 }
1441 else
1442 {
1443 *pVolumeFraction = -1;
1444 }
1445 }
1446 if (pDistanceToSurface)
1447 {
1448 //PROFILE_BLOCK( DistanceToSurface )
1449 double dClosestEdgeDistance = FindClosestEdgeDistance( Loc, SectionPoints, dTolerance );
1450 if ( dClosestEdgeDistance < dTolerance )
1451 *pDistanceToSurface = dClosestEdgeDistance;
1452 }
1453
1454 if ( pOrientation )
1455 {
1456 //PROFILE_BLOCK(Orientation)
1457 if ( bSectionConstant && N.GetAngle() == 0.0 )
1458 {
1459 *pOrientation = N.GetTangent(); // Don't need to calculate orientation if constant section
1460 }
1461 else
1462 {
1463 // Find which element of section mesh point lies in. Get section mesh for section either side and calculate orientation from elements
1464 CMesh SectionMesh = m_pYarnSection->GetSectionMesh(YarnPositionInfo, m_iNumSectionPoints, false);
1465
1466 int Index;
1467 CMesh::ELEMENT_TYPE ElementType = GetMeshPoint( SectionMesh, Loc, Index );
1468 if ( ElementType != CMesh::NUM_ELEMENT_TYPES )
1469 {
1470 XYZ Ori;
1471 double u1, u2;
1472 CSlaveNode N1,N2;
1473
1474 {
1475 //PROFILE_BLOCK(Orientation1)
1476 u1 = u > 0.1 ? u-0.1 : 0;
1477 //if ( u > 0.01 ) // Is 1/100th length of section suitable offset?
1478 //{
1479 N1 = m_pInterpolation->GetNode(m_MasterNodes, i, u1 );
1480 //N1 = m_pInterpolation->GetNode(m_MasterNodes, i, u - 0.01 );
1481 YarnPositionInfo.dSectionPosition = N1.GetT();
1482 YarnPositionInfo.iSection = N1.GetIndex();
1483 SectionMesh = m_pYarnSection->GetSectionMesh(YarnPositionInfo, m_iNumSectionPoints, false); // Gets 2D section
1484 N1.UpdateSectionMesh( &SectionMesh ); // Converts back to 3D section
1485 }
1486 //}
1487 // else use N1 at master node
1488
1489 {
1490 //PROFILE_BLOCK(Orientation2)
1491 u2 = u < 0.99 ? u+0.1 : 1;
1492 //if ( u < 0.99 )
1493 //{
1494 N2 = m_pInterpolation->GetNode(m_MasterNodes, i, u2 );
1495 //N2 = m_pInterpolation->GetNode(m_MasterNodes, i, u + 0.01 );
1496 YarnPositionInfo.dSectionPosition = N2.GetT();
1497 YarnPositionInfo.iSection = N2.GetIndex();
1498 SectionMesh = m_pYarnSection->GetSectionMesh(YarnPositionInfo, m_iNumSectionPoints, false);
1499 N2.UpdateSectionMesh( &SectionMesh );
1500 //}
1501 }
1502
1503 {
1504 //PROFILE_BLOCK(Orientation3)
1505 CMesh End1Mesh = N1.GetSectionMesh();
1506 CMesh End2Mesh = N2.GetSectionMesh();
1507 int iNumNodes = CMesh::GetNumNodes(ElementType);
1508 vector<int> ElementIndices1;
1509 vector<int> ElementIndices2;
1510 End1Mesh.ConvertElementListToVector( ElementType, ElementIndices1 );
1511 End2Mesh.ConvertElementListToVector( ElementType, ElementIndices2 );
1512 for ( int j = 0; j < iNumNodes; ++j )
1513 {
1514 Ori += End2Mesh.GetNode( ElementIndices2[Index] ) - End1Mesh.GetNode( ElementIndices1[Index] );
1515 Index++;
1516 }
1517 Ori /= iNumNodes;
1518 Normalise( Ori );
1519 *pOrientation = Ori;
1520 assert( fabs(Ori.x) > 1e-14 || fabs(Ori.y) > 1e-14 || fabs(Ori.z) > 1e-14 );
1521 }
1522 }
1523 }
1524 }
1525 if ( pUp )
1526 {
1527 *pUp = N.GetUp();
1528 }
1529
1530 return true;
1531 }
1532 }
1533 }
1534 return false;
1535}
1536
1537bool CYarn::PointInsideYarn(const XYZ &Point, const vector<XYZ> &Translations, XYZ *pTangent, XY* pLoc, double *pVolumeFraction, double* pDistanceToSurface, double dTolerance, XYZ *pOrientation, XYZ *pUp, bool bSurface) const
1538{
1539 // TODO OPTIMISE THIS
1540 vector<XYZ>::const_iterator itXYZ;
1541 for (itXYZ = Translations.begin(); itXYZ != Translations.end(); ++itXYZ)
1542 {
1543 if (PointInsideYarn(Point - *itXYZ, pTangent, pLoc, pVolumeFraction, pDistanceToSurface, dTolerance, pOrientation, pUp, bSurface))
1544 return true;
1545 }
1546 return false;
1547}
1548
1549bool CYarn::FindPlaneContainingPoint(const XYZ &Point, double &u, double dTolerance, int iSeg) const
1550{
1551 const double dConvergenceTolerance = 1e-6;
1552 CSlaveNode N1, N2, N;
1553 double du;
1554 PLANE Plane1, Plane2, SearchPlane;
1555 double d1, d2, d, dprev;
1556
1557 N1 = m_pInterpolation->GetNode(m_MasterNodes, iSeg, 0);
1558 N2 = m_pInterpolation->GetNode(m_MasterNodes, iSeg, 1);
1559
1560 Plane1.Normal = N1.GetNormal();
1561 Plane2.Normal = -N2.GetNormal();
1562
1563
1564 Plane1.d = DotProduct(Plane1.Normal, N1.GetPosition());
1565 Plane2.d = DotProduct(Plane2.Normal, N2.GetPosition());
1566
1567 d1 = DotProduct(Plane1.Normal, Point) - Plane1.d;
1568 d2 = DotProduct(Plane2.Normal, Point) - Plane2.d;
1569
1570 // If true then the point lies between the two planes
1571 if (d1 >= -dConvergenceTolerance && d2 >= -dConvergenceTolerance)
1572 {
1573 if ( d1 == 0.0 ) // Point lies on one of end planes if d1 or d2 == 0.0
1574 {
1575 u = 0.0;
1576 }
1577 else if ( d2 == 0.0 )
1578 {
1579 u = 1.0;
1580 }
1581 else
1582 {
1583 u = d1/(d1+d2);
1584 du = u;
1585 dprev = d1 < d2 ? d1 : d2;
1586 //dprev = d1;
1587 SearchPlane = Plane1;
1588 int iIterations = 0;
1589 while(abs(du) > dConvergenceTolerance)
1590 {
1591 N = m_pInterpolation->GetNode(m_MasterNodes, iSeg, u);
1592
1593 SearchPlane.Normal = N.GetNormal();
1594 SearchPlane.d = DotProduct(SearchPlane.Normal, N.GetPosition());
1595
1596 d = DotProduct(SearchPlane.Normal, Point) - SearchPlane.d;
1597
1598 du = d * (du/(dprev-d));
1599 if ( du > (1-u + dConvergenceTolerance) )
1600 du = 1 - u + dConvergenceTolerance;
1601 else if ( du < (-u - dConvergenceTolerance) )
1602 du = -u - dConvergenceTolerance;
1603
1604 u += du;
1605 dprev = d;
1606 ++iIterations;
1607 if ( iIterations > 100 )
1608 {
1609 TGLOG("Exceeded number of iterations. PointInsideYarn failed");
1610 return false; // TODO Very rare that doesn't converge but still need to find correct solution
1611 }
1612 }
1613 }
1614 return true;
1615 }
1616 return false;
1617}
1618
1619double CYarn::FindClosestSurfacePoint(const XYZ &Point, XYZ &SurfacePoint, int iNumSectionPoints, double dTolerance )
1620{
1622 return false;
1623
1624 int i;
1625 CSlaveNode N;
1626 double u;
1627 m_pInterpolation->Initialise(m_MasterNodes);
1628
1629 YARN_POSITION_INFORMATION YarnPositionInfo;
1630 YarnPositionInfo.SectionLengths = m_SectionLengths;
1631 vector<XY> Section;
1632
1633 bool bFound = false;
1634 XY Loc;
1635 XYZ Relative, Up, Side;
1636 int iNumSegments = (int)m_MasterNodes.size()-1;
1637 int index;
1638 double dist;
1639
1640 double minDist = -1.0;
1641 for (i=0; i<iNumSegments; ++i)
1642 {
1643 if (FindPlaneContainingPoint(Point, u, dTolerance, i))
1644 {
1645
1646 N = m_pInterpolation->GetNode(m_MasterNodes, i, u);
1647
1648 YarnPositionInfo.dSectionPosition = N.GetT();
1649 YarnPositionInfo.iSection = N.GetIndex();
1650 Section = m_pYarnSection->GetSection(YarnPositionInfo, iNumSectionPoints);
1651 N.UpdateSectionPoints(&Section);
1652 vector<XYZ> SectionPoints = N.GetSectionPoints();
1653 index = GetClosestPointIndex( SectionPoints, Point);
1654 dist = GetLength( SectionPoints[index], Point);
1655 if ( dist < minDist || minDist == -1 )
1656 {
1657 minDist = dist;
1658 SurfacePoint = SectionPoints[index];
1659 bFound = true;
1660 }
1661 }
1662 }
1663 return minDist;
1664}
1665
1666bool CYarn::FindClosestSurfacePoint(const XYZ &Point, const vector<XYZ> &Translations, XYZ &SurfacePoint, int iNumSectionPoints, double dTolerance)
1667{
1668 vector<XYZ>::const_iterator itXYZ;
1669 double minDist = -1, dist = -1.0;
1670 XYZ SPoint;
1671 for (itXYZ = Translations.begin(); itXYZ != Translations.end(); ++itXYZ)
1672 {
1673 dist = FindClosestSurfacePoint(Point - *itXYZ, SPoint, iNumSectionPoints, dTolerance);
1674 if ( fabs(dist + 1.0) > 1e-9 ) // Add 1 because FindClosestSurfacePoint returns -1 if unsuccessful
1675 {
1676 if ( dist < minDist || minDist == -1 )
1677 {
1678 minDist = dist;
1679 SPoint += *itXYZ;
1680 SurfacePoint = SPoint;
1681 }
1682 }
1683 }
1684 if ( minDist == -1 )
1685 return false;
1686 return true;
1687}
1688
1690{
1691 if (!BuildYarnIfNeeded(LINE))
1692 return 0;
1693 return accumulate(m_SectionLengths.begin(), m_SectionLengths.end(), 0.0);
1694}
1695
1697{
1698 CMesh Mesh;
1699 AddSurfaceToMesh(Mesh);
1700 return Mesh.CalculateVolume();
1701}
1702
1703double CYarn::GetRawYarnSectionLength(int iIndex) const
1704{
1705 if (!BuildYarnIfNeeded(LINE))
1706 return 0;
1707 if (iIndex < 0 || iIndex >= (int)m_SectionLengths.size())
1708 {
1709 TGERROR("Unable to get yarn section length, invalid index: " << iIndex);
1710 return 0;
1711 }
1712 return m_SectionLengths[iIndex];
1713}
1714
1715vector<double> CYarn::GetYarnSectionLengths() const
1716{
1717 if (!BuildYarnIfNeeded(LINE))
1718 return vector<double>();
1719 return m_SectionLengths;
1720}
1721
1723{
1724 if (m_Repeats.size() != 2)
1725 {
1726 TGERROR("Yarns must contain 2 repeat vectors in order to calculate yarn length per unit area");
1727 return 0;
1728 }
1729 return GetLength(CrossProduct(m_Repeats[0], m_Repeats[1]));
1730}
1731
1732
1733pair<XYZ, XYZ> CYarn::GetAABB() const
1734{
1736 return pair<XYZ, XYZ>(XYZ(), XYZ());
1737 return m_AABB;
1738}
1739
1740pair<XYZ, XYZ> CYarn::GetSectionAABB(int iIndex) const
1741{
1743 return pair<XYZ, XYZ>(XYZ(), XYZ());
1744 if (iIndex < 0 || iIndex >= (int)m_SectionAABBs.size())
1745 return pair<XYZ, XYZ>(XYZ(), XYZ());
1746 return m_SectionAABBs[iIndex];
1747}
1748
1749const vector<CSlaveNode> &CYarn::GetSlaveNodes(BUILD_TYPE Usage) const
1750{
1751 BuildYarnIfNeeded(Usage);
1752 return m_SlaveNodes;
1753}
1754
1755double CYarn::GetRealYarnLength(string Units) const
1756{
1757 if (!m_pParent)
1758 return 0;
1759 return ConvertUnits(GetRawYarnLength(), m_pParent->GetGeometryScale(), Units);
1760}
1761
1762double CYarn::GetYarnLengthPerUnitArea(string Units) const
1763{
1764 if (!m_pParent)
1765 return 0;
1766 double dRepeatArea = GetRawRepeatArea();
1767 if (dRepeatArea == 0)
1768 return 0;
1769 double dLengthPerUnitArea = GetRawYarnLength() / dRepeatArea;
1770 return ConvertUnits(dLengthPerUnitArea, "/"+m_pParent->GetGeometryScale(), Units);
1771}
1772
1773double CYarn::GetRealYarnVolume(string Units) const
1774{
1775 if (!m_pParent)
1776 return 0;
1777 double dVolume = GetRawYarnVolume();
1778 return ConvertUnits(dVolume, m_pParent->GetGeometryScale()+"^3", Units);
1779}
1780
1781double CYarn::GetYarnVolumePerUnitArea(string Units) const
1782{
1783 if (!m_pParent)
1784 return 0;
1785 double dRepeatArea = GetRawRepeatArea();
1786 if (dRepeatArea == 0)
1787 return 0;
1788 double dVolPerUnitArea = GetRawYarnVolume() / dRepeatArea;
1789 return ConvertUnits(dVolPerUnitArea, m_pParent->GetGeometryScale(), Units);
1790}
1791
1792double CYarn::GetFibreVolume(string Units) const
1793{
1794 if (!m_pParent)
1795 return 0;
1796 double dLength = GetRealYarnLength();
1797
1798 // Calculate volume based on fibre area
1799 double dFibreArea = GetFibreArea();
1800 if ( dFibreArea != 0 )
1801 {
1802 double dVolume = dLength * dFibreArea;
1803 return ConvertUnits(dVolume, "m^3", Units);
1804 }
1805
1806 // Otherwise calculate based on linear density
1807 double dYarnLinearDensity = GetYarnLinearDensity();
1808 // If yarn linear density is not specified for the yarn use textile value
1809 if (dYarnLinearDensity == 0)
1810 dYarnLinearDensity = m_pParent->GetYarnLinearDensity();
1811 if ( dYarnLinearDensity == 0 )
1812 {
1813 TGERROR( "There is no yarn linear density specified" );
1814 return 0;
1815 }
1816 double dMass = dYarnLinearDensity*dLength;
1817 double dFibreDensity = GetFibreDensity();
1818 // If fibre density is not specified for the yarn use textile value
1819 if (dFibreDensity == 0)
1820 dFibreDensity = m_pParent->GetFibreDensity();
1821 if (dFibreDensity == 0)
1822 {
1823 TGERROR( "There is no fibre density specified" );
1824 return 0;
1825 }
1826 double dVolume = dMass/dFibreDensity;
1827 return ConvertUnits(dVolume, "m^3", Units);
1828}
1829
1830double CYarn::GetFibreVolumePerUnitArea(string Units) const
1831{
1832 if (!m_pParent)
1833 return 0;
1834 double dRepeatArea = GetRawRepeatArea();
1835 if (dRepeatArea == 0)
1836 return 0;
1837 double dLengthPerUnitArea = GetYarnLengthPerUnitArea();
1838 double dYarnLinearDensity = GetYarnLinearDensity();
1839 // If yarn linear density is not specified for the yarn use textile value
1840 if (dYarnLinearDensity == 0)
1841 dYarnLinearDensity = m_pParent->GetYarnLinearDensity();
1842 if ( dYarnLinearDensity == 0 )
1843 {
1844 TGERROR( "There is no yarn linear density specified" );
1845 return 0;
1846 }
1847 double dMassPerUnitArea = dYarnLinearDensity*dLengthPerUnitArea;
1848 double dFibreDensity = GetFibreDensity();
1849 // If fibre density is not specified for the yarn use textile value
1850 if (dFibreDensity == 0)
1851 dFibreDensity = m_pParent->GetFibreDensity();
1852 if (dFibreDensity == 0)
1853 {
1854 TGERROR( "There is no fibre density specified" );
1855 return 0;
1856 }
1857 double dVolPerUnitArea = dMassPerUnitArea/dFibreDensity;
1858 return ConvertUnits(dVolPerUnitArea, "m", Units);
1859}
1860
1862{
1863 if (!m_pParent)
1864 return 0;
1865 double dYarnVolume = GetRealYarnVolume();
1866 if (dYarnVolume)
1867 return GetFibreVolume()/dYarnVolume;
1868 else
1869 return 0;
1870}
1871
1872void CYarn::SetParent(const CTextile *pParent)
1873{
1874 m_pParent = pParent;
1875}
1876
1877
1878CMesh::ELEMENT_TYPE CYarn::GetMeshPoint( CMesh &Mesh, const XY &Point, int& Index ) const
1879{
1880 //PROFILE_FUNC()
1881 list<int>::iterator itIndex;
1882 list<int> &TriIndices = Mesh.GetIndices( CMesh::TRI );
1883
1884 for ( itIndex = TriIndices.begin(), Index = 0; itIndex != TriIndices.end(); Index += 3 )
1885 {
1886 vector<XYZ> Nodes;
1887 for ( int j = 0; j < 3; j++ )
1888 {
1889 Nodes.push_back( Mesh.GetNode( *itIndex++ ));
1890 }
1891 if ( PointInside( Point, Nodes ) )
1892 {
1893 return( CMesh::TRI );
1894 }
1895 }
1896
1897 list<int> &QuadIndices = Mesh.GetIndices( CMesh::QUAD );
1898
1899 for ( itIndex = QuadIndices.begin(), Index = 0; itIndex != QuadIndices.end(); Index += 4 )
1900 {
1901 vector<XYZ> Nodes;
1902 for ( int j = 0; j < 4; j++ )
1903 {
1904 Nodes.push_back( Mesh.GetNode( *itIndex++ ));
1905 }
1906 if ( PointInside( Point, Nodes ) )
1907 {
1908 return( CMesh::QUAD );
1909 }
1910 }
1912}
1913
1914double CYarn::FindClosestEdgeDistance( XY &Loc, const vector<XY> &SectionPoints, double dTolerance ) const
1915{
1916 vector<XY>::const_iterator itP1, itP2;
1917 XY Edge, EdgeNormal;
1918 double dEdgeDistance;
1919 double dClosestEdgeDistance = 1.0;
1920 bool bStart = true;
1921
1922 itP1 = itP2 = SectionPoints.begin();
1923 ++itP2;
1924 while (itP1 != SectionPoints.end())
1925 {
1926 Edge = *itP2 - *itP1;
1927 // Calculate the edge normal as the vector pointing away from the section
1928 // This is done by rotating the edge line by 90 degrees clockwise
1929 EdgeNormal.x = Edge.y;
1930 EdgeNormal.y = -Edge.x;
1931 Normalise(EdgeNormal);
1932
1933 dEdgeDistance = DotProduct(EdgeNormal, Loc - *itP1);
1934
1935 // dClosestEdgeDistance keeps track of the closest distance from the point
1936 // to the section. This value may be negative or positive. Positive distance
1937 // represents a point outside the section, negative represents a point inside.
1938 // Note that this distance is not exact for points lying outside the section.
1939 // The distance may be less than the true value for sections with sharp edges.
1940 if ( dEdgeDistance < dTolerance ) // Point on innner side so check distance.
1941 {
1942 if ( bStart )
1943 {
1944 dClosestEdgeDistance = dEdgeDistance;
1945 bStart = false;
1946 }
1947 else
1948 dClosestEdgeDistance = max(dClosestEdgeDistance, dEdgeDistance);
1949 }
1950
1951 ++itP1;
1952 ++itP2;
1953 if (itP2 == SectionPoints.end())
1954 itP2 = SectionPoints.begin();
1955 }
1956 return dClosestEdgeDistance;
1957}
1958
1960{
1961 // Get a copy of the yarn sections that are applied to the nodes
1962 string str = GetYarnSection()->GetType();
1963 if ( str == "CYarnSectionInterpNode" )
1964 return true;
1965 if (str != "CYarnSectionConstant")
1966 return false;
1967
1969
1970 CYarnSectionInterpNode NewYarnSection(false, true);
1971 // Add section at each node
1972 for ( int i = 0; i < GetNumNodes(); ++i )
1973 {
1974 NewYarnSection.AddSection( pYarnSection->GetSection() );
1975 }
1976
1977 delete pYarnSection;
1978 AssignSection( NewYarnSection );
1979 return true;
1980}
1981
1982
1983
1984
1985
#define TGLOGINDENT(MESSAGE)
Combines the TGLOG macro and TGLOGAUTOINDENT macro in one.
Definition: Logger.h:68
#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 FOR_EACH_TIXMLELEMENT(CHILDELEMENT, PARENTELEMENT, ELEMENTNAME)
Macro to enable looping over tinyxml easier.
Definition: Misc.h:45
#define NULL
Definition: ShinyConfig.h:50
Abstract base class representing the domain in which a textile cell may lie.
Definition: Domain.h:34
virtual void ClipMeshToDomain(CMesh &Mesh, bool bFillGaps=true) const =0
Clip the surface elements to the domain.
vector< XYZ > GetTranslations(const CYarn &Yarn) const
Get the translation vectors necessary to fully fill the domain.
Definition: Domain.cpp:83
Fibre volume fraction is defined as a quadratic equation varying only along the X axis.
Fibre volume fraction is constant throughout the yarn.
Abstract base class that defines how the fibres are distributed within a yarn.
Bezier interpolation for yarn paths.
Abstract base class for describing the yarn path interpolations.
Definition: Interpolation.h:33
static CObjectContainer< CInterpolation > CreateInterpolation(TiXmlElement &Element)
Create an interpolation from TiXmlElement.
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
void InsertMesh(const CMesh &Mesh, XYZ Offset=XYZ(0, 0, 0))
Add the contents of Mesh to this mesh.
Definition: Mesh.cpp:93
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
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
void RemoveOpposingTriangles()
Remove triangles that have the same indices but opposite normals.
Definition: Mesh.cpp:136
ELEMENT_TYPE
Each element type is represented by a unique integer value.
Definition: Mesh.h:66
@ NUM_ELEMENT_TYPES
Definition: Mesh.h:77
@ POLYLINE
Definition: Mesh.h:74
@ POLYGON
Definition: Mesh.h:76
void CopySelfToRange(XYZ Vector, int iLowerLimit, int iUpperLimit)
Copy the mesh to the range given by the lower limit and upper limit with the given repeat vector.
Definition: Mesh.cpp:1437
void FlipNormals()
Flip the normals of the mesh for triangles and quads.
Definition: Mesh.cpp:1166
void ConvertElementListToVector(ELEMENT_TYPE ElementType, vector< int > &Indices)
Convert element index list to vector so can access by index.
Definition: Mesh.cpp:2683
double CalculateVolume() const
Calculate the volume of the mesh.
Definition: Mesh.cpp:1519
void Rotate(WXYZ Rotation, XYZ Origin=XYZ(0, 0, 0))
Rotate the whole mesh by given quaternion.
Definition: Mesh.cpp:1148
int InsertNodes(const CMesh &Mesh, XYZ Offset=XYZ(0, 0, 0))
Add the nodes of Mesh to this mesh.
Definition: Mesh.cpp:82
Represents a point on the centreline of a yarn.
Definition: Node.h:28
XYZ GetUp() const
Definition: Node.h:59
XYZ GetPosition() const
Definition: Node.h:57
XYZ GetTangent() const
Definition: Node.h:58
double GetAngle() const
Definition: Node.h:60
XYZ GetSide() const
Get the side vector.
Definition: Node.cpp:84
XYZ GetNormal() const
Definition: Node.cpp:94
double GetYarnLinearDensity(string Units="kg/m") const
Definition: Properties.cpp:241
double GetFibreArea(string Units="m^2") const
Get the area occupied by fibres given fibre diameter and number of fibres.
Definition: Properties.cpp:251
double GetFibreDensity(string Units="kg/m^3") const
Definition: Properties.cpp:246
Class to store properties related to a textile.
void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType)
Used for saving data to XML.
Elliptical Section.
Abstract base class respresenting a yarn cross-section.
Definition: Section.h:31
static double GetCircumference(const vector< XY > &Section)
Get the circumference of a section.
Definition: Section.cpp:273
static CMesh GetTriangleMesh(const vector< XY > &Section)
A derivation of the CNode class which contains data specific to slave nodes such as sections.
Definition: SlaveNode.h:30
const CMesh & GetSectionMesh() const
Definition: SlaveNode.h:77
void UpdateSectionMesh(const CMesh *p2DSectionMesh=NULL)
Populate m_SectionMesh from m_2DSectionMesh, Setting m_2DSectionMesh at the same time.
Definition: SlaveNode.cpp:132
double GetT() const
Definition: SlaveNode.h:70
const vector< XY > & Get2DSectionPoints() const
Definition: SlaveNode.h:75
const vector< XYZ > & GetSectionPoints() const
Definition: SlaveNode.h:74
int GetIndex() const
Definition: SlaveNode.h:72
void UpdateSectionPoints(const vector< XY > *p2DSectionPoints=NULL)
Populate m_SectionPoints from m_2DSectionPoints, Setting m_2DSectionPoints at the same time.
Definition: SlaveNode.cpp:95
Represents a textile cell containing yarns.
Definition: Textile.h:39
bool AddSurfaceToMesh(CMesh &Mesh, bool bAddEndCaps=true) const
Create surface mesh for this yarn and add it to the surface mesh object.
Definition: Yarn.cpp:860
double GetRawYarnSectionLength(int iIndex) const
Get the length of a yarn section (building the yarn if necessary)
Definition: Yarn.cpp:1703
bool DeleteNode(int iIndex)
Delete an existing node.
Definition: Yarn.cpp:282
bool m_bEquiSpacedSectionMesh
Whether or not volume meshes of the yarn should be equispaced.
Definition: Yarn.h:502
bool BuildSlaveNodes() const
Definition: Yarn.cpp:407
void AssignDefaults()
Definition: Yarn.cpp:179
vector< XYZ > m_Repeats
List of infinite repeat vectors, yarns will be repeated to infinite displaced by the specified vector...
Definition: Yarn.h:499
CWeakPointer< const CTextile > m_pParent
Stores a pointer to the CTextile it belongs to.
Definition: Yarn.h:539
void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType)
Used for saving data to XML.
Definition: Yarn.cpp:106
const CNode * GetNode(int iIndex) const
Get a master node by index.
Definition: Yarn.cpp:299
pair< XYZ, XYZ > GetAABB() const
Get axis aligned bounding box for the yarn (building the yarn if necessary)
Definition: Yarn.cpp:1733
bool BuildSectionMeshes() const
Definition: Yarn.cpp:594
void AddRepeat(XYZ Repeat)
Add a repeat vector.
Definition: Yarn.cpp:1253
void AssignInterpolation(const CInterpolation &Interpolation)
Assign an interpolation function to the yarn.
Definition: Yarn.cpp:641
bool RepeatMatchesEnds(XYZ Repeat) const
Check if the repeat vector is the same as the last master node - first master node.
Definition: Yarn.cpp:1268
void SetRepeats(const vector< XYZ > &Repeats)
Set the repeat vectors.
Definition: Yarn.cpp:1263
bool FindPlaneContainingPoint(const XYZ &Point, double &u, double dTolerance, int iSeg) const
Find the plane normal to the yarn which contains a specified point.
Definition: Yarn.cpp:1549
vector< CNode > m_MasterNodes
Ordered list of nodes belonging to this Yarn.
Definition: Yarn.h:494
int m_iNumSlaveNodes
Number of slave nodes to create.
Definition: Yarn.h:500
void AssignSection(const CYarnSection &YarnSection)
Assign a section to the yarn.
Definition: Yarn.cpp:649
const vector< CSlaveNode > & GetSlaveNodes(BUILD_TYPE Usage) const
Get the slave nodes and build them if necessary.
Definition: Yarn.cpp:1749
int m_iNeedsBuilding
Variable used to keep track of wether the yarn needs to be rebuilt or not and what part needs rebuild...
Definition: Yarn.h:507
CObjectContainer< CInterpolation > m_pInterpolation
Interpolation applied to smooth the yarn paths.
Definition: Yarn.h:495
bool ConvertToInterpNodes()
Definition: Yarn.cpp:1959
vector< double > m_SectionLengths
The length of each of the sections in the yarn.
Definition: Yarn.h:529
double FindClosestSurfacePoint(const XYZ &Point, XYZ &SurfacePoint, int iNumSectionPoints, double dTolerance=1e-9)
Finds the closest point on the yarn surface to Point.
Definition: Yarn.cpp:1619
@ SURFACE
Definition: Yarn.h:60
@ VOLUME
Definition: Yarn.h:61
bool ReplaceNode(int iIndex, CNode NewNode)
Replace an existing node with given node.
Definition: Yarn.cpp:261
void ClearMasterNodeOrientations()
Set the tangents and up vectors of all the master nodes to null.
Definition: Yarn.cpp:1283
double GetRawRepeatArea() const
Get repeat area.
Definition: Yarn.cpp:1722
CObjectContainer< CYarnSection > m_pYarnSection
Section applied to this yarn, with possibility of a varying cross-section.
Definition: Yarn.h:496
bool BuildYarnIfNeeded(int iBuildType) const
Create slave nodes and apply yarn section to them.
Definition: Yarn.cpp:375
bool BuildSections() const
Definition: Yarn.cpp:456
void SetEquiSpacedSectionMesh(bool bEquiSpacedSectionMesh)
Meshes of the yarn should be equispaced if true.
Definition: Yarn.cpp:315
vector< pair< XYZ, XYZ > > m_SectionAABBs
An axis aligned bounding box containing each section of the yarn.
Definition: Yarn.h:523
void AddNode(const CNode &Node)
Add a node to the end of the list of nodes (note the nodes must be ordered)
Definition: Yarn.cpp:196
double GetRawYarnVolume() const
Get the volume of the yarn (building the yarn if necessary)
Definition: Yarn.cpp:1696
double GetYarnLengthPerUnitArea(string Units="/m") const
Calculate the total yarn length per unit area.
Definition: Yarn.cpp:1762
int GetNumNodes() const
Definition: Yarn.h:452
const CYarnSection * GetYarnSection() const
Definition: Yarn.h:449
CYarn(void)
Definition: Yarn.cpp:30
CObjectContainer< CFibreDistribution > m_pFibreDistribution
Fibre distribution given to the yarn, used for getting Fibre Volume Fraction.
Definition: Yarn.h:497
void ClearRepeats()
Remove all repeat vectors.
Definition: Yarn.cpp:1258
pair< XYZ, XYZ > m_AABB
An axis aligned bounding box containing the full unrepeated yarn.
Definition: Yarn.h:514
void SetParent(const CTextile *pParent)
Set the yarn parent.
Definition: Yarn.cpp:1872
bool AddNodesToMesh(CMesh &Mesh) const
Add the master nodes to the mesh.
Definition: Yarn.cpp:803
CMesh::ELEMENT_TYPE GetMeshPoint(CMesh &Mesh, const XY &Point, int &Index) const
Definition: Yarn.cpp:1878
void AddEndCapsToMesh(CMesh &Mesh) const
Add end caps to the mesh.
Definition: Yarn.cpp:919
void CreateSectionAABBs() const
Create the section Axis aligned bounding boxes.
Definition: Yarn.cpp:553
double GetYarnVolumePerUnitArea(string Units="m") const
Calculate the total yarn volume per unit area.
Definition: Yarn.cpp:1781
void StraightenYarn(double dStraightness=1)
Straighten the yarn.
Definition: Yarn.cpp:1293
void SetResolution(int iNumSlaveNodes, int iNumSectionPoints)
Set the resolution of the mesh created.
Definition: Yarn.cpp:306
bool AddVolumeToMesh(CMesh &Mesh) const
Create volume mesh for this yarn and add it to the volume mesh object.
Definition: Yarn.cpp:1010
double FindClosestEdgeDistance(XY &Loc, const vector< XY > &SectionPoints, double dTolerance) const
Find closest perpendicular distance from point to polygon specified by SectionPoints.
Definition: Yarn.cpp:1914
bool InsertNode(const CNode &Node, const CNode *pBefore)
Insert a node before node pBefore.
Definition: Yarn.cpp:213
vector< double > GetYarnSectionLengths() const
Get the lengths of all the yarn sections.
Definition: Yarn.cpp:1715
double GetRealYarnLength(string Units="m") const
Calculate the total yarn length.
Definition: Yarn.cpp:1755
vector< CSlaveNode > m_SlaveNodes
Ordered list of interpolated slave nodes belonging to this Yarn.
Definition: Yarn.h:508
double GetRawYarnLength() const
Get the length of the yarn (building the yarn if necessary)
Definition: Yarn.cpp:1689
double GetRealYarnVolume(string Units="m^3") const
Calculate the yarn volume.
Definition: Yarn.cpp:1773
double GetFibreVolumePerUnitArea(string Units="m") const
Definition: Yarn.cpp:1830
int m_iNumSectionPoints
Number of section points to create.
Definition: Yarn.h:501
void AssignFibreDistribution(const CFibreDistribution &Distribution)
Assign a fibre distribution.
Definition: Yarn.cpp:658
~CYarn(void)
Definition: Yarn.cpp:40
void Rotate(WXYZ Rotation, XYZ Origin=XYZ(0, 0, 0))
Rotate the Yarn by given quaternion.
Definition: Yarn.cpp:663
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
bool AddPathToMesh(CMesh &Mesh) const
Add yarn centerline path to mesh.
Definition: Yarn.cpp:813
bool AddCentrePlaneToMesh(CMesh &Mesh) const
Create mesh of the centre plane for this yarn and add it to the plane mesh object.
Definition: Yarn.cpp:1159
void Translate(XYZ Vector)
Translate the Yarn by given vector.
Definition: Yarn.cpp:684
double GetFibreVolume(string Units="m^3") const
Definition: Yarn.cpp:1792
double GetFibreYarnVolumeFraction() const
Definition: Yarn.cpp:1861
void SetNodes(const vector< CNode > &Nodes)
Set the nodes for this yarn given as an ordered list of nodes.
Definition: Yarn.cpp:188
bool AddAABBToMesh(CMesh &Mesh) const
Add the axis aligned bounding box of the yarn to the Mesh.
Definition: Yarn.cpp:702
pair< XYZ, XYZ > GetSectionAABB(int iIndex) const
Get axis aligned bounding box for a yarn section (building the yarn if necessary)
Definition: Yarn.cpp:1740
Creates a section which is constant all along the yarn.
vector< XY > GetSection(const YARN_POSITION_INFORMATION PositionInfo, int iNumPoints, bool bEquiSpaced=false) const
This function must be implemented by derived classes.
Abstract base class used to define the sections along the length of a yarn.
Definition: YarnSection.h:58
virtual CYarnSection * Copy() const =0
This is a function to allow copying of derived classes correctly.
virtual string GetType() const =0
Derived class should return the class name.
static CObjectContainer< CYarnSection > CreateYarnSection(TiXmlElement &Element)
Create a yarn section from TiXmlElement.
Definition: YarnSection.cpp:49
Creates a section which is linearly interpolated between sections defined at the nodes.
void AddSection(const CSection &Section)
Add a section at a node.
const CSection & GetNodeSection(int iIndex) const
void InsertSection(int iIndex, const CSection &Section)
Insert a section at a node.
void DeleteSection(int iIndex)
Delete a section at a node.
Namespace containing a series of customised math operations not found in the standard c++ library.
void GetMinMaxXY(const std::vector< XY > &Points, XY &Min, XY &Max)
Definition: Misc.h:244
OUTPUT_TYPE
Definition: Misc.h:105
@ OUTPUT_FULL
Definition: Misc.h:108
bool PointInside(const XY &Point, const std::vector< XY > &Nodes)
Definition: mymath.h:1574
int GetClosestPointIndex(const std::vector< XY > &Points, const XY Position)
Definition: mymath.h:1439
double Max(XYZ &Vector)
Get maximum element of vector and return it.
Definition: mymath.h:642
bool PointInsideBox(const XYZ &Point, const XYZ &BoxMin, const XYZ &BoxMax, double dTolerance=0)
Find if a point is inside an Axis Aligned Bounding Box with given tolerance.
Definition: mymath.h:988
double GetLength(const XYZ &Point1, const XYZ &Point2)
Get the length between two points.
Definition: mymath.h:540
std::string stringify(const T &x, int iPrecision=12, bool bScientific=true)
Function to convert a value (e.g. int, double, etc...) to a string.
Definition: Misc.h:50
XYZ Min(const XYZ &P1, const XYZ &P2)
Given two points, return a new point who's coordinates are the smaller of the two.
Definition: mymath.h:1142
WXYZ & Normalise(WXYZ &Quaternion)
Normalise the quaternion and return it.
Definition: mymath.h:609
double DotProduct(const XYZ &left, const XYZ &right)
Get the dot product of two vectors.
Definition: mymath.h:512
XYZ CrossProduct(const XYZ &left, const XYZ &right)
Get the cross product of two vectors.
Definition: mymath.h:524
double ConvertUnits(double dValue, std::string SourceUnits, std::string TargetUnits)
Definition: Misc.cpp:63
Struct for representing a Plane.
Definition: Plane.h:25
XYZ Normal
Definition: Plane.h:30
double d
Definition: Plane.h:31
Struct for representing a quaternion.
Definition: mymath.h:38
Struct for representing points in 2D space.
Definition: mymath.h:103
double x
Definition: mymath.h:104
double y
Definition: mymath.h:104
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
Structure used to represent the position along the length of a yarn.
Definition: YarnSection.h:36
double dSectionPosition
This variables varies linearly with distance from 0 to 1 from the start to the end of the current lin...
Definition: YarnSection.h:37
int iSection
This variable represents the index of the current section (where a section is defined as the part bet...
Definition: YarnSection.h:38
vector< double > SectionLengths
This contains a list of lengths representing the length of each section.
Definition: YarnSection.h:39