TexGen
TextileAngleInterlock.cpp
Go to the documentation of this file.
1/*=============================================================================
2TexGen: Geometric textile modeller.
3Copyright (C) 2011 Louise Brown
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18=============================================================================*/
19
20#include "PrecompiledHeaders.h"
22
23
24using namespace TexGen;
25
26CTextileAngleInterlock::CTextileAngleInterlock(int iNumXYarns, int iNumYYarns, double dXSpacing, double dYSpacing, double dXHeight, double dYHeight)
27: CTextile3DWeave( iNumXYarns, iNumYYarns, dXSpacing, dYSpacing, dXHeight, dYHeight)
28{
29}
30
32: CTextile3DWeave(Element)
33{
34}
35
37{
38}
39
40void CTextileAngleInterlock::PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType)
41{
42 CTextile3DWeave::PopulateTiXmlElement(Element, OutputType);
43}
44
46{
47 if (x<0 || x>=m_iNumYYarns || y<0 || y>=m_iNumXYarns)
48 {
49 TGERROR("Unable to set binder position, index out of range: " << x << ", " << y);
50 return;
51 }
52 vector<PATTERN3D> &Cell = GetCell(x, y);
53 int size = Cell.size();
54 SetBinderPosition( size-1, Cell );
55 int BinderPos = (size-1) - 2;
56
57 for ( int i = 1; i <= m_iNumYYarns/2; ++i )
58 {
59 vector<PATTERN3D> &Cell = GetCell( (i+x)%m_iNumYYarns, y );
60 SetBinderPosition( BinderPos, Cell );
61 if ( BinderPos > 0 )
62 {
63 vector<PATTERN3D> &Cell = GetCell( (m_iNumYYarns-i+x)%m_iNumYYarns, y );
64 SetBinderPosition( BinderPos, Cell );
65 }
66 BinderPos -= 2;
67 }
68
69 m_bNeedsBuilding = true;
70}
71
72void CTextileAngleInterlock::SetBinderPosition( int z, vector<PATTERN3D>& Cell )
73{
74 int size = Cell.size();
75 for ( int j = 0; j < size; j+=2 )
76 {
77 if ( j == z )
78 {
79 Cell[j] = PATTERN3D_XYARN;
80 }
81 else
82 {
83 Cell[j] = PATTERN3D_NOYARN;
84 }
85 }
86}
87
88void CTextileAngleInterlock::SetupLayers( int iNumWarpLayers, int iNumWeftLayers, int iNumBinderLayers )
89{
90 if ( iNumWarpLayers != iNumWeftLayers-1 )
91 {
92 TGERROR("Unable to set up layers, number of warp layers should be one less than weft layers: warp layers " << iNumWarpLayers << ", weft layers " << iNumWeftLayers);
93 return;
94 }
96
97 // Add alternating layers
98 while( iNumWeftLayers > 0 )
99 {
100 AddYLayers();
101 if ( iNumWarpLayers > 0 )
102 {
103 AddWarpLayer();
104 iNumWarpLayers--;
105 }
106 iNumWeftLayers--;
107 }
108
110}
111
113{
114 m_Yarns.clear();
115 m_YYarns.clear();
116 m_XYarns.clear();
117
118 m_YYarns.resize(m_iNumYYarns);
119 m_XYarns.resize(m_iNumXYarns);
120
121 m_dMinZ = 0.0;
122 m_dMaxZ = 0.0;
123
124 if (!Valid() || !CheckCells())
125 {
126 TGERROR("Cannot build textile - incorrect yarn setup");
127 return false;
128 }
129
130 TGLOGINDENT("Building textile weave \"" << GetName() << "\"");
131 m_bNeedsBuilding = false;
132
133 vector<int> Yarns;
134
135 double x, y, z;
136
137 // Add x yarns (yarns parallel to the x axis)
138 int i, j, k, iYarn;
139 y = 0;
140 for (i=0; i<m_iNumXYarns; ++i)
141 {
142 y += m_XYarnData[i].dSpacing/2.0;
143 x = 0;
144 Yarns.clear();
145 for (j=0; j<=m_iNumYYarns; ++j)
146 {
147 const vector<PATTERN3D> &Cell = GetCell(j%m_iNumYYarns, i);
148 int NextCellIndex;
149 NextCellIndex = FindNextCellIndex(i);
150 const vector<PATTERN3D> &NextCell = GetCell(j%m_iNumYYarns, NextCellIndex%m_iNumXYarns );
151 if (j==0)
152 {
153 for (k=0; k<(int)Cell.size(); ++k)
154 {
155 if (Cell[k] == PATTERN3D_XYARN)
156 {
157 Yarns.push_back(AddYarn(CYarn()));
158 }
159 }
160 }
161 m_XYarns[i] = Yarns;
162 iYarn = 0;
163
164 x += m_YYarnData[j%m_iNumYYarns].dSpacing/2.0;
165
166 z = 0.0;
167 for (k=0; k<(int)Cell.size(); ++k)
168 {
169 if (Cell[k] == PATTERN3D_XYARN)
170 {
171 double dHalfHeight = m_XYarnData[i].dHeight / 2.0;
172 if ( IsBinderYarn(i) )
173 {
174 if ( k == 0 )
175 {
176 z -= dHalfHeight + m_dGapSize;
177 if ( (z - dHalfHeight) < m_dMinZ )
178 m_dMinZ = z - dHalfHeight;
179 }
180 else
181 {
182 if ( NextCell[k] == PATTERN3D_XYARN )
183 {
184 dHalfHeight = m_XYarnData[NextCellIndex].dHeight / 2.0;
185 }
186 else if ( NextCell[k] == PATTERN3D_YYARN )
187 {
188 dHalfHeight = m_YYarnData[j%m_iNumYYarns].dHeight / 2.0;
189 }
190 else // PATTERN3D_NOYARN
191 {
192 // Does this ever happen?
193 }
194 z += dHalfHeight;
195 }
196 }
197 else
198 {
199 z += dHalfHeight;
200 }
201 m_Yarns[Yarns[iYarn]].AddNode(CNode(XYZ(x, y, z), XYZ(1, 0, 0)));
202 ++iYarn;
203 z += dHalfHeight + m_dGapSize;
204 if ( z > m_dMaxZ )
205 m_dMaxZ = z;
206 }
207 else if ( Cell[k] == PATTERN3D_YYARN )
208 {
209 z += m_YYarnData[j%m_iNumYYarns].dHeight + m_dGapSize;
210 }
211 else if ( k > 0 )// PATTERN3D_NOYARN and not on bottom binder layer
212 {
213 if ( NextCell[k] == PATTERN3D_XYARN )
214 {
215 z += m_XYarnData[NextCellIndex].dHeight + m_dGapSize;
216 }
217 else if ( NextCell[k] == PATTERN3D_YYARN )
218 {
219 z += m_YYarnData[j%m_iNumYYarns].dHeight + m_dGapSize;
220 }
221 else // PATTERN3D_NOYARN
222 {
223 // Will get here if all x yarns are binder yarns so just use binder yarn height to give spacing
224 z += m_XYarnData[i%m_iNumXYarns].dHeight + m_dGapSize;
225 }
226 }
227 }
228 if (j<m_iNumYYarns)
229 x += m_YYarnData[j].dSpacing/2.0;
230 }
231 y += m_XYarnData[i].dSpacing/2.0;
232 }
233
234 // Add y yarns (yarns parallel to the y axis)
235 x = 0;
236 for (j=0; j<m_iNumYYarns; ++j)
237 {
238 y = 0;
239 Yarns.clear();
240 x += m_YYarnData[j].dSpacing/2.0;
241 for (i=0; i<=m_iNumXYarns; ++i)
242 {
243 const vector<PATTERN3D> &Cell = GetCell(j, i%m_iNumXYarns);
244
245 int NextCellIndex = FindNextCellIndex(i);
246 const vector<PATTERN3D> &NextCell = GetCell(j%m_iNumYYarns, NextCellIndex%m_iNumXYarns);
247 if (i==0)
248 {
249 for (k=0; k<(int)Cell.size(); ++k)
250 {
251 if (Cell[k] == PATTERN3D_YYARN)
252 {
253 Yarns.push_back(AddYarn(CYarn()));
254 }
255 }
256 }
257 m_YYarns[j] = Yarns;
258 iYarn = 0;
259 y += m_XYarnData[i%m_iNumXYarns].dSpacing/2.0;
260 z = 0.0;
261
262 for (k=0; k<(int)Cell.size(); ++k)
263 {
264 if (Cell[k] == PATTERN3D_YYARN)
265 {
266 double dHalfHeight = m_YYarnData[j].dHeight / 2.0;
267 z += dHalfHeight;
268 m_Yarns[Yarns[iYarn]].AddNode(CNode(XYZ(x, y, z), XYZ(0, 1, 0)));
269 ++iYarn;
270 z += dHalfHeight + m_dGapSize;
271 }
272 else if ( Cell[k] == PATTERN3D_XYARN && k > 0 ) // Don't adjust z if it's the bottom binder yarn
273 {
274 if ( IsBinderYarn(i%m_iNumXYarns) )
275 {
276 if ( NextCell[k] == PATTERN3D_XYARN )
277 {
278 z += m_XYarnData[NextCellIndex%m_iNumXYarns].dHeight + m_dGapSize;
279 }
280 else if ( NextCell[k] == PATTERN3D_YYARN )
281 {
282 z += m_YYarnData[j%m_iNumYYarns].dHeight + m_dGapSize;
283 }
284 else // PATTERN3D_NOYARN
285 {
286 // Does this ever happen?
287 }
288 }
289 else
290 {
291 z += m_XYarnData[i%m_iNumXYarns].dHeight + m_dGapSize;
292 }
293 }
294 else if ( k > 0 ) // PATTERN3D_NOYARN and not on bottom binder layer
295 {
296 if ( NextCell[k] == PATTERN3D_XYARN )
297 {
298 z += m_XYarnData[NextCellIndex%m_iNumXYarns].dHeight + m_dGapSize;
299 }
300 else if ( NextCell[k] == PATTERN3D_YYARN )
301 {
302 z += m_YYarnData[j%m_iNumYYarns].dHeight + m_dGapSize;
303 }
304 else // PATTERN3D_NOYARN
305 {
306 // Will get here if all x yarns are binder yarns so just use binder yarn height to give spacing
307 z += m_XYarnData[i%m_iNumXYarns].dHeight + m_dGapSize;
308 }
309 }
310 }
311 if (i<m_iNumXYarns)
312 y += m_XYarnData[i].dSpacing/2.0;
313 }
314 x += m_YYarnData[j].dSpacing/2.0;
315 }
316
317
318 // Assign sections to the yarns
319 vector<int>::iterator itpYarn;
320 double dWidth, dHeight;
321 for (i=0; i<m_iNumXYarns; ++i)
322 {
323 dWidth = m_XYarnData[i].dWidth;
324 dHeight = m_XYarnData[i].dHeight;
325 CSectionPowerEllipse Section(dWidth, dHeight, IsBinderYarn(i) ? m_dBinderPower : m_dWarpPower);
326 if (m_pSectionMesh)
328 for (itpYarn = m_XYarns[i].begin(); itpYarn != m_XYarns[i].end(); ++itpYarn)
329 {
330 m_Yarns[*itpYarn].AssignSection(CYarnSectionConstant(Section));
331 }
332 }
333 for (i=0; i<m_iNumYYarns; ++i)
334 {
335 dWidth = m_YYarnData[i].dWidth;
336 dHeight = m_YYarnData[i].dHeight;
337 CSectionPowerEllipse Section(dWidth, dHeight, m_dWeftPower);
338 if (m_pSectionMesh)
340 for (itpYarn = m_YYarns[i].begin(); itpYarn != m_YYarns[i].end(); ++itpYarn)
341 {
342 m_Yarns[*itpYarn].AssignSection(CYarnSectionConstant(Section));
343 }
344 }
345
347
348 // Add repeats and set interpolation
349 dWidth = GetWidth();
350 dHeight = GetHeight();
351 vector<CYarn>::iterator itYarn;
352 for (itYarn = m_Yarns.begin(); itYarn != m_Yarns.end(); ++itYarn)
353 {
354 itYarn->AssignInterpolation(CInterpolationBezier());
355 itYarn->SetResolution(m_iResolution);
356 itYarn->AddRepeat(XYZ(dWidth, 0, 0));
357 itYarn->AddRepeat(XYZ(0, dHeight, 0));
358 }
359
360 return true;
361}
362
364{
365 for ( int j = 0; j < m_iNumXYarns; ++j )
366 {
367 if ( IsBinderYarn( j ) )
368 {
369 int CurrentNode = 0;
370 for ( int i = 0; i < m_iNumYYarns; ++i )
371 {
372 CurrentNode = AddBinderNodes( CurrentNode, i, j );
373 CurrentNode++;
374 }
376 }
377 }
378}
379
380int CTextileAngleInterlock::AddBinderNodes( int CurrentNode, int i, int j ) const
381{
382 const vector<PATTERN3D> &Cell = GetCell(i,j);
383 const vector<PATTERN3D> &NextCell = GetCell( (i+1)%m_iNumYYarns, j );
384 const vector<PATTERN3D> &PrevCell = GetCell( (i+m_iNumYYarns-1)%m_iNumYYarns, j );
385
386 int iIndex = FindBinderHeight( Cell );
387 int iMaxIndex = Cell.size() - 1;
388 XY SectionPoint;
389 XYZ WeftBelowNode, WeftAboveNode;
390 int iStartNode = CurrentNode;
391
392 if ( iIndex < 0 )
393 return CurrentNode;
394
395 double dBinderOffset = m_XYarnData[j].dHeight/2.0;
396
397
398 int BinderYarnIndex = GetYarnIndex( i, j, iIndex );
399 if ( BinderYarnIndex == -1 )
400 return CurrentNode;
401
402 int WeftAboveIndex, WeftBelowIndex;
403
404 // Get indices of weft yarns above and below binder
405 if ( iIndex < (int)Cell.size() - 1 )
406 {
407 WeftAboveIndex = GetYarnIndex( i, j, iIndex + 1 );
408 WeftAboveNode = m_Yarns[WeftAboveIndex].GetNode( j )->GetPosition();
409 }
410 else
411 WeftAboveIndex = -1;
412
413 if ( iIndex > 0 )
414 {
415 WeftBelowIndex = GetYarnIndex( i, j, iIndex - 1 );
416 WeftBelowNode = m_Yarns[WeftBelowIndex].GetNode( j )->GetPosition();
417 }
418 else
419 WeftBelowIndex = -1;
420
421 XYZ BinderNode = m_Yarns[BinderYarnIndex].GetNode( CurrentNode )->GetPosition();
422 if ( iIndex > 0 && PrevCell[iIndex-2] == PATTERN3D_XYARN )
423 {
424 // Get cross section of weft yarn below
425 CSectionPowerEllipse* YarnSection = GetWeftCrossSection( WeftBelowIndex );
426 if ( YarnSection == NULL )
427 return CurrentNode;
428
429 // Insert points around Top left quadrant of weft yarn
430 {
431 XYZ NewNode = WeftBelowNode;
432
433 InsertBinderNode( YarnSection, 0.45, WeftBelowNode, CurrentNode, BinderYarnIndex, dBinderOffset + m_dGapSize );
434 InsertBinderNode( YarnSection, 0.4, WeftBelowNode, CurrentNode, BinderYarnIndex, dBinderOffset + m_dGapSize );
435 if ( !( iIndex < iMaxIndex && NextCell[iIndex+2] == PATTERN3D_XYARN ) )
436 InsertBinderNode( YarnSection, 0.35, WeftBelowNode, CurrentNode, BinderYarnIndex, dBinderOffset + m_dGapSize );
437 //InsertBinderNode( YarnSection, 0.3, WeftBelowNode, CurrentNode, BinderYarnIndex, dBinderOffset + m_dGapSize );
438 }
439 delete YarnSection;
440 }
441 else if ( iIndex < iMaxIndex && PrevCell[iIndex+2] == PATTERN3D_XYARN )
442 {
443 // Get cross section of weft yarn below
444 CSectionPowerEllipse* YarnSection = GetWeftCrossSection( WeftAboveIndex );
445 if ( YarnSection == NULL )
446 return CurrentNode;
447 // Insert points around lower left quadrant of weft yarn
448 {
449 XYZ NewNode = WeftAboveNode;
450
451 NewNode = WeftAboveNode;
452 InsertBinderNode( YarnSection, 0.55, WeftAboveNode, CurrentNode, BinderYarnIndex, -(dBinderOffset + m_dGapSize) );
453 InsertBinderNode( YarnSection, 0.6, WeftAboveNode, CurrentNode, BinderYarnIndex, -(dBinderOffset + m_dGapSize) );
454 if ( !( iIndex > 0 && NextCell[iIndex-2] == PATTERN3D_XYARN ) )
455 InsertBinderNode( YarnSection, 0.65, WeftAboveNode, CurrentNode, BinderYarnIndex, -(dBinderOffset + m_dGapSize) );
456 //InsertBinderNode( YarnSection, 0.7, WeftAboveNode, CurrentNode, BinderYarnIndex, -(dBinderOffset + m_dGapSize) );
457 }
458 }
459
460 if ( iStartNode == 0 )
461 {
462 XYZ NewNode = m_Yarns[BinderYarnIndex].GetNode(0)->GetPosition();
463 ReplaceLastNode( BinderYarnIndex, NewNode, BinderNode );
464 }
465
466 if ( iIndex > 0 && NextCell[iIndex-2] == PATTERN3D_XYARN )
467 {
468
469 // Get cross section of weft yarn below
470 CSectionPowerEllipse* YarnSection = GetWeftCrossSection( WeftBelowIndex );
471 if ( YarnSection == NULL )
472 return CurrentNode;
473
474 // Insert points around upper right quadrant of weft
475 XYZ NewNode = WeftBelowNode;
476 CurrentNode++; // Need to insert after node (ie before next node)
477 //InsertBinderNode( YarnSection, 0.2, WeftBelowNode, CurrentNode, BinderYarnIndex, dBinderOffset + m_dGapSize );
478 if ( !( iIndex < iMaxIndex && PrevCell[iIndex+2] == PATTERN3D_XYARN ) )
479 InsertBinderNode( YarnSection, 0.15, WeftBelowNode, CurrentNode, BinderYarnIndex, dBinderOffset + m_dGapSize );
480 InsertBinderNode( YarnSection, 0.1, WeftBelowNode, CurrentNode, BinderYarnIndex, dBinderOffset + m_dGapSize );
481 InsertBinderNode( YarnSection, 0.05, WeftBelowNode, CurrentNode, BinderYarnIndex, dBinderOffset + m_dGapSize );
482 CurrentNode--;
483 }
484 else if( iIndex < iMaxIndex && NextCell[iIndex+2] == PATTERN3D_XYARN )
485 {
486 // Get cross section of weft yarn below
487 CSectionPowerEllipse* YarnSection = GetWeftCrossSection( WeftAboveIndex );
488 if ( YarnSection == NULL )
489 return CurrentNode;
490 // Insert points around lower right quadrant of weft yarn
491 {
492 XYZ NewNode = WeftAboveNode;
493 CurrentNode++; // Need to insert after node (ie before next node)
494 //InsertBinderNode( YarnSection, 0.8, WeftAboveNode, CurrentNode, BinderYarnIndex, -(dBinderOffset + m_dGapSize) );
495 if ( !( iIndex > 0 && PrevCell[iIndex-2] == PATTERN3D_XYARN ) )
496 InsertBinderNode( YarnSection, 0.85, WeftAboveNode, CurrentNode, BinderYarnIndex, -(dBinderOffset + m_dGapSize) );
497 InsertBinderNode( YarnSection, 0.9, WeftAboveNode, CurrentNode, BinderYarnIndex, -(dBinderOffset + m_dGapSize) );
498 InsertBinderNode( YarnSection, 0.95, WeftAboveNode, CurrentNode, BinderYarnIndex, -(dBinderOffset + m_dGapSize) );
499 CurrentNode--;
500 }
501 }
502
503 return CurrentNode;
504}
505
506int CTextileAngleInterlock::FindBinderHeight( const vector<PATTERN3D>& Cell ) const
507{
508 int i = Cell.size() - 1;
509 while( i > 0 )
510 {
511 if ( Cell[i] == PATTERN3D_XYARN )
512 return i;
513 --i;
514 }
515 return i;
516}
#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 NULL
Definition: ShinyConfig.h:50
Bezier interpolation for yarn paths.
Represents a point on the centreline of a yarn.
Definition: Node.h:28
void AssignSectionMesh(const CSectionMesh &SectionMesh)
Assign a mesh to the section.
Definition: Section.cpp:227
Represents a 3D woven textile.
void AddNoYarnLayer()
Add empty layer.
void ReplaceLastNode(int BinderYarnIndex, XYZ &NewNode, XYZ &BinderNode) const
Replace last node with node offset to match node 0.
vector< YARNDATA > m_XYarnData
vector< vector< int > > m_XYarns
int GetYarnIndex(int x, int y, int z) const
void CheckUpVectors(int WarpIndex, bool Yarn=PATTERN3D_XYARN, bool bYarnsIndex=false) const
bool CheckCells() const
Check that all cells are populated.
bool Valid() const
Check that the weave pattern contained in m_Pattern is valid.
double GetHeight() const
Get the height of the unit cell.
CSectionPowerEllipse * GetWeftCrossSection(int WeftYarnIndex) const
Adjust cross section shapes to correct interference.
int FindNextCellIndex(int index) const
Find next cell in y direction which isn't a binder yarn.
bool IsBinderYarn(int index) const
Check if X yarn is binder or warp. Returns true if binder.
vector< YARNDATA > m_YYarnData
void AddBinderLayer()
Add yarns parallel to the X axis in binder yarn positions, no yarns in warp positions.
void AddWarpLayer()
Add yarns parallel to the X axis in warp yarn positions, no yarns in binder positions.
vector< vector< int > > m_YYarns
virtual double GetWidth() const
Get the width of the unit cell.
void AddYLayers(int x, int iNumberLayers)
Add given number of yarns parallel to the Y axis, with given index x.
void InsertBinderNode(CSectionPowerEllipse *YarnSection, double t, XYZ &WeftNode, int &CurrentNode, int BinderYarnIndex, double Offset, bool bInsert=true) const
Calculates a point at given point on power ellipse cross section and inserts into binder yarn.
virtual void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType)
Used for saving data to XML.
const vector< PATTERN3D > & GetCell(int x, int y) const
CObjectContainer< CSectionMesh > m_pSectionMesh
virtual void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType)
Used for saving data to XML.
void ShapeBinderYarns() const
Shape the binder yarns around the adjacent weft yarns.
CTextileAngleInterlock(int iNumXYarns, int iNumYYarns, double dXSpacing, double dYSpacing, double dXHeight, double dYHeight)
Build a weave unit cell of given width, height, number of layers, yarn spacing and fabric thickness.
int FindBinderHeight(const vector< PATTERN3D > &Cell) const
void SetBinderPosition(int z, vector< PATTERN3D > &Cell)
virtual void SetupLayers(int iNumWarpLayers, int iNumWeftLayers, int iNumBinderLayers=1)
Find min and max z values for the textile.
int AddBinderNodes(int CurrentNode, int i, int j) const
Add extra nodes to binder yarns to match shape of adjacent weft yarns.
virtual bool BuildTextile() const
Build the textile.
vector< CYarn > m_Yarns
Vector of yarns contained within this cell.
Definition: Textile.h:323
string GetName() const
Get the name associated with this textile.
Definition: Textile.cpp:355
int AddYarn(const CYarn &Yarn)
Add a Yarn to the textile.
Definition: Textile.cpp:122
bool m_bNeedsBuilding
Variable which keeps track of wether the textile needs building or not.
Definition: Textile.h:330
Represents a yarn consisting of master nodes, section and interpolation function.
Definition: Yarn.h:49
Creates a section which is constant all along the yarn.
Namespace containing a series of customised math operations not found in the standard c++ library.
OUTPUT_TYPE
Definition: Misc.h:105
@ PATTERN3D_NOYARN
@ PATTERN3D_XYARN
@ PATTERN3D_YYARN
Struct for representing points in 2D space.
Definition: mymath.h:103
Struct for representing points in 3D space.
Definition: mymath.h:56