31CShearedTextileWeave2D::CShearedTextileWeave2D(
int iWidth,
int iHeight,
double dSpacing,
double dThickness,
double ShearAngle,
bool bRefine,
bool bInPlaneTangents )
32:
CTextileWeave2D(iWidth, iHeight, dSpacing, dThickness, bRefine, bInPlaneTangents )
33, m_ShearAngle(ShearAngle)
34, m_bShearedDomain(false)
87 for (k=0; k<(int)Cell.size(); ++k)
98 for (k=0; k<(int)Cell.size(); ++k)
126 for (k=0; k<(int)Cell.size(); ++k)
137 for (k=0; k<(int)Cell.size(); ++k)
157 vector<int>::iterator itpYarn;
158 double dWidth, dHeight;
166 for (itpYarn =
m_XYarns[i].begin(); itpYarn !=
m_XYarns[i].end(); ++itpYarn)
179 for (itpYarn =
m_YYarns[i].begin(); itpYarn !=
m_YYarns[i].end(); ++itpYarn)
192 vector<CYarn>::iterator itYarn;
196 itYarn->AddRepeat(
XYZ(dWidth, 0, 0));
197 itYarn->AddRepeat(
XYZ(Repeat.
x, Repeat.
y, 0));
222 if ( bAddedDomainHeight )
272 vector<XY>::iterator itYSpacings;
276 YRepeat += *itYSpacings;
284 timer.
start(
"Timing Refine");
294 TGERROR(
"Cannot adjust sections - no domain specified");
296 timer.
check(
"End of Refine");
303 vector<vector<int> > *pTransverseYarns;
304 vector<vector<int> > *pLongitudinalYarns;
305 vector<YARNDATA> *pTransverseData;
306 vector<YARNDATA> *pLongitudinalData;
308 int iLongitudinalNum;
309 bool iTransversePattern;
310 bool iLongitudinalPattern;
314 double dTransWidth, dTransHeight;
315 int iPrevTransYarnInd;
316 int iNextTransYarnInd, iNextLongYarnInd;
318 for (
int iDir=0; iDir<2; ++iDir)
344 for ( i = 0; i < iTransverseNum; ++i )
346 iPrevTransYarnInd = i-1;
347 if (iPrevTransYarnInd < 0)
348 iPrevTransYarnInd += iTransverseNum;
349 iNextTransYarnInd = (i+1)%iTransverseNum;
352 dTransWidth = (*pTransverseData)[i].dWidth;
353 dTransHeight = (*pTransverseData)[i].dHeight;
355 pYarn = &
m_Yarns[(*pTransverseYarns)[i][0]];
365 for (j=0; j<iLongitudinalNum; ++j)
367 iNextLongYarnInd = (j+1)%iLongitudinalNum;
370 double dLongWidth = (*pLongitudinalData)[j].dWidth;
371 double dLongHeight = (*pLongitudinalData)[j].dHeight;
373 double dNextLongWidth = (*pLongitudinalData)[iNextLongYarnInd].dWidth;
374 double dNextLongHeight = (*pLongitudinalData)[iNextLongYarnInd].dHeight;
375 double dDistToLongYarnEdge = 0.5 * dLongWidth / cos(
m_ShearAngle);
383 double dDistToNextLongYarnEdge = 0.5 * dNextLongWidth / cos(
m_ShearAngle);
386 double RCalc = 1.0 / sqrt( 1.0 - 1.0/((dLongWidth/dLongHeight)*(dLongWidth/dLongHeight)) );
387 double RMax = 0.25 * ( 1.0 + 0.2*sin(
m_ShearAngle) + RCalc );
392 RCalc = 1.0 / sqrt( 1.0 - 1.0/((dNextLongWidth/dNextLongHeight)*(dNextLongWidth/dNextLongHeight)) );
393 double RMin = 0.25 * ( 1.0 - 0.2*sin(
m_ShearAngle) - RCalc );
411 dAngle = asin(
CalcSinAngle( R, dTransWidth, dTransHeight ));
412 if (
GetCellDir(i,j, iDir)[0] == iTransversePattern )
414 if (
GetCellDir( i, iNextLongYarnInd, iDir )[1] == iTransversePattern &&
GetCellDir(iNextTransYarnInd,j, iDir)[0] == iLongitudinalPattern )
424 if (
GetCellDir( i, iNextLongYarnInd, iDir)[0] == iTransversePattern &&
GetCellDir(iNextTransYarnInd, j, iDir)[1] == iLongitudinalPattern )
433 dist = (R - 0.25) * (4.0 * dDistToLongYarnEdge);
434 u = dist/dDistBetweenNodes;
463 dAngle = asin(
CalcSinAngle( R, dTransWidth, dTransHeight ));
465 if (
GetCellDir(i, iNextLongYarnInd, iDir)[0] == iTransversePattern )
467 if (
GetCellDir( i, j, iDir )[1] == iTransversePattern &&
GetCellDir(iPrevTransYarnInd,iNextLongYarnInd, iDir)[0] == iLongitudinalPattern )
477 if (
GetCellDir( i, j, iDir )[0] == iTransversePattern &&
GetCellDir( iPrevTransYarnInd, iNextLongYarnInd, iDir )[1] == iLongitudinalPattern )
486 dist = dDistBetweenNodes - (0.25 - R) * ( 4.0 * dDistToNextLongYarnEdge );
487 u = dist/dDistBetweenNodes;
513 double WidthHeight = (Width/Height);
514 WidthHeight *= WidthHeight;
531 denom = 1 + WidthHeight*denom;
542 vector<vector<int> > *pTransverseYarns;
543 vector<vector<int> > *pLongitudinalYarns;
544 vector<YARNDATA> *pTransverseData;
546 int iLongitudinalNum;
549 CMesh TransverseYarnsMesh;
550 CMesh NextTransverseYarnsMesh;
551 vector<int>::iterator itpYarn;
552 vector<pair<int, int> > RepeatLimits;
553 vector<pair<double, XYZ> > Intersections;
561 RepeatLimits.resize(2, pair<int, int>(-1, 1));
562 vector<double> Modifiers;
563 vector<vector<vector<double> > > YarnSectionModifiers;
564 YarnSectionModifiers.resize(
m_Yarns.size());
567 for (iDir=0; iDir<2; ++iDir)
586 for (i=0; i<iTransverseNum; ++i)
588 TransverseYarnsMesh.
Clear();
591 for (itpYarn = (*pTransverseYarns)[i].begin(); itpYarn != (*pTransverseYarns)[i].end(); ++itpYarn)
593 m_Yarns[*itpYarn].AddSurfaceToMesh(TransverseYarnsMesh, RepeatLimits);
600 TransverseYarnsMesh = NextTransverseYarnsMesh;
603 NextTransverseYarnsMesh.
Clear();
604 for (itpYarn = (*pTransverseYarns)[(i+1)%iTransverseNum].begin(); itpYarn != (*pTransverseYarns)[(i+1)%iTransverseNum].end(); ++itpYarn)
606 m_Yarns[*itpYarn].AddSurfaceToMesh(NextTransverseYarnsMesh, RepeatLimits);
611 for (j=0; j<iLongitudinalNum; ++j)
613 for (itpYarn = (*pLongitudinalYarns)[j].begin(); itpYarn != (*pLongitudinalYarns)[j].end(); ++itpYarn)
619 XYZ Node =
m_Yarns[*itpYarn].GetNode(j)->GetPosition();
620 XYZ NextNode =
m_Yarns[*itpYarn].GetNode((j+1)%iLongitudinalNum)->GetPosition();
624 pInterpolation =
m_Yarns[*itpYarn].GetInterpolation();
626 CalculateModifiers( pInterpolation, *itpYarn, YarnPosInfo, TransverseYarnsMesh, YarnSectionModifiers, bMaxCorrection );
629 double DistToEdgeU = (0.5 * (*pTransverseData)[i].dWidth / cos(
m_ShearAngle) )/ dDistBetweenNodes;
635 for (
int k = 0; k < iMidSize; ++k )
639 CalculateModifiers( pInterpolation, *itpYarn, YarnPosInfo, TransverseYarnsMesh, YarnSectionModifiers, bMaxCorrection );
641 CalculateModifiers( pInterpolation, *itpYarn, YarnPosInfo, NextTransverseYarnsMesh, YarnSectionModifiers, bMaxCorrection );
643 delete pYarnSections;
651 for (i=0; i<(int)
m_Yarns.size(); ++i)
658 for (j=0; j<(int)YarnSectionModifiers[i].size(); )
664 ModifySection(pYarnSection, YarnPosInfo, YarnSectionModifiers[i][j], iNodeIndex);
669 for (
int iMidIndex = 0; iMidIndex < iMidSize; ++iMidIndex )
673 ModifySection(pYarnSection, YarnPosInfo, YarnSectionModifiers[i][j], iNodeIndex, iMidIndex);
681 m_Yarns[i].AssignSection(*pYarnSection);
693 vector<double> Modifiers;
700 pYarnSection =
m_Yarns[Yarn].GetYarnSection();
701 vector<XY> Points = pYarnSection->
GetSection(YarnPosInfo,
m_Yarns[Yarn].GetNumSectionPoints());
704 vector<XY>::iterator itPoint;
706 for (itPoint = Points.begin(); itPoint != Points.end(); ++itPoint)
708 XYZ P = itPoint->
x * Side + itPoint->
y * Up + Centre;
709 vector<pair<double, XYZ> > Intersections;
710 if (Mesh.
IntersectLine(Centre, P, Intersections, make_pair(
true,
false)))
712 double dU = Intersections[0].first;
713 if ( !bMaxCorrection && dU > 0 && dU < 1 )
715 XYZ Normal = Intersections[0].second;
717 dU -= 0.5 * dProjectedGap;
722 Modifiers.push_back(dU);
725 Modifiers.push_back(1);
727 YarnSectionModifiers[Yarn].push_back(Modifiers);
733 Points = pYarnSection->
GetSection(YarnPosInfo, (
int)Modifiers.size());
734 for (
int k=0; k<(int)Points.size(); ++k)
736 Points[k] *= Modifiers[k];
741 if ( iMidIndex == -1 )
750 vector<double> YarnSectionModifiers;
753 CMesh TopMesh, BottomMesh;
761 pInterpolation =
m_Yarns[YarnInd].GetInterpolation();
768 YarnSectionModifiers.clear();
776 const vector<PATTERN2D> &Cell =
GetCell(i,j);
778 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, BottomMesh, YarnSectionModifiers );
780 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, TopMesh, YarnSectionModifiers );
791 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, BottomMesh, YarnSectionModifiers );
793 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, TopMesh, YarnSectionModifiers );
799 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, BottomMesh, YarnSectionModifiers );
801 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, TopMesh, YarnSectionModifiers );
808 m_Yarns[YarnInd].AssignSection( *pYarnSections );
809 delete pYarnSections;
817 pInterpolation =
m_Yarns[YarnInd].GetInterpolation();
824 YarnSectionModifiers.clear();
832 const vector<PATTERN2D> &Cell =
GetCell(i,j);
834 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, BottomMesh, YarnSectionModifiers );
836 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, TopMesh, YarnSectionModifiers );
847 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, BottomMesh, YarnSectionModifiers );
849 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, TopMesh, YarnSectionModifiers );
855 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, BottomMesh, YarnSectionModifiers );
857 CalculateModifiers( pInterpolation, YarnInd, YarnPosInfo, TopMesh, YarnSectionModifiers );
864 m_Yarns[YarnInd].AssignSection( *pYarnSections );
865 delete pYarnSections;
872 double sizex = AABB.second.x - AABB.first.x;
873 double sizey = AABB.second.y - AABB.first.y;
874 double minx = AABB.first.x - sizex;
875 double maxx = AABB.second + sizex;
876 double miny = AABB.first.y - sizey;
877 double maxy = AABB.second.y + sizey;
900 Indices.push_back(0);
901 Indices.push_back(1);
902 Indices.push_back(3);
906 Indices.push_back(1);
907 Indices.push_back(2);
908 Indices.push_back(3);
926 int numPoints =
m_Yarns[Yarn].GetNumSectionPoints();
927 vector<XY> Points = pYarnSection->
GetSection(YarnPosInfo, numPoints);
929 vector<XY>::iterator itPoint;
930 double angle = atan2( Points[0].y, Points[0].x );
933 YarnSectionModifiers.clear();
934 for (itPoint = Points.begin(); itPoint != Points.end(); ++itPoint, ++i)
936 if ( i == 0 || i == numPoints/2 )
938 YarnSectionModifiers.push_back(1);
941 XYZ P = itPoint->
x * Side + itPoint->
y * Up + Centre;
943 XYZ RefPoint = RefPoint2D.
x * Side + RefPoint2D.
y * Up + Centre;
945 vector<pair<double, XYZ> > Intersections;
946 if (Mesh.
IntersectLine(RefPoint, P, Intersections, make_pair(
true,
false)))
948 double dU = Intersections[0].first;
952 YarnSectionModifiers.push_back(dU);
955 YarnSectionModifiers.push_back(1);
965 XY RotRefPoint(RotatedPoint.
x, 0.0);
975 vector<XY>::iterator itPoints;
977 Points = pYarnSection->
GetSection(YarnPosInfo, (
int)Modifiers.size());
978 double dAngle = atan2( Points[0].y, Points[0].x );
979 for ( itPoints = Points.begin(); itPoints != Points.end(); ++itPoints )
988 vector<XY> MaxHeight;
992 for ( itPoints = Points.begin(), k=0; itPoints != Points.end(); ++itPoints, ++k )
994 if ( Modifiers[k] < 1.0 )
996 itPoints->y = itPoints->y * Modifiers[k];
1000 else if ( Modifiers[k] == 1.0 )
1007 miny = maxy = itPoints->y;
1011 if ( itPoints->y < miny )
1013 if ( itPoints->y > maxy )
1018 XY Point( itPoints->x, itPoints->y );
1019 Point.
y = itPoints->y * Modifiers[k];
1020 MaxHeight.push_back( Point );
1021 if ( fabs(Point.
y - itPoints->y) > maxdy )
1022 maxdy = fabs(Point.
y - itPoints->y);
1025 double dArea =
GetArea( MaxHeight );
1026 if ( dArea < dTargetArea )
1029 TGERROR(
"Modify Section: all points increased to max value. Unable to achieve original section area");
1031 ReplaceSection( MaxHeight, pYarnSection, iNodeIndex, iMidIndex );
1035 dHeight = maxy - miny;
1037 double dy = dOriginalHeight - dHeight;
1041 int iNumPoints = (int)Points.size();
1042 vector<XY> NewPoints;
1044 int iCount =
ModifyPoints( Points, Modifiers, MaxHeight, iModCount, dy, NewPoints );
1048 while ( fabs( dArea - dTargetArea ) >
TOL )
1050 if ( dArea > dTargetArea )
1056 if ( iCount == iNumPoints )
1058 TGERROR(
"Modify Section: all points increased to max value. Unable to achieve original section area");
1063 dy = (maxdy + mindy)/2.0;
1065 iCount =
ModifyPoints( Points, Modifiers, MaxHeight, iModCount, dy, NewPoints );
1070 for ( itPoints = NewPoints.begin(); itPoints != NewPoints.end(); ++itPoints )
1075 ReplaceSection( NewPoints, pYarnSection, iNodeIndex, iMidIndex );
1081 RotatedPoint.
x = Point.
x*cos(dAngle) - Point.
y*sin(dAngle);
1082 RotatedPoint.
y = Point.
x*sin(dAngle) + Point.
y*cos(dAngle);
1083 return RotatedPoint;
1097 if ( iMidIndex == -1 )
1112 int iCount = iModCount;
1113 vector<XY>::iterator itPoints;
1117 for ( itPoints = Points.begin(), k = 0; itPoints != Points.end(); ++itPoints, ++k )
1119 XY Point( itPoints->x, itPoints->y );
1120 if ( Modifiers[k] > 1.0 )
1122 if ( itPoints->y > 0.0 && (itPoints->y + dy) < MaxHeight[k].y )
1123 Point.
y = itPoints->y + dy;
1124 else if ( itPoints->y < 0.0 && (itPoints->y - dy) > MaxHeight[k].y )
1125 Point.
y = itPoints->y - dy;
1128 Point.
y = MaxHeight[k].y;
1132 NewPoints.push_back( Point );
#define TGLOGINDENT(MESSAGE)
Combines the TGLOG macro and TGLOGAUTOINDENT macro in one.
#define TGERROR(MESSAGE)
Macros used to report the file name and line number to the TexGenError and TexGenLog functions.
const CMesh & GetMesh() const
Get the mesh representing the domain as a surface mesh.
Domain implementation described using planes, the simplest of which would be a box.
void AddPlane(const PLANE &Plane)
Bezier interpolation for yarn paths.
Cubic spline interpolation for yarn paths.
Abstract base class for describing the yarn path interpolations.
virtual CSlaveNode GetNode(const vector< CNode > &MasterNodes, int iIndex, double t) const =0
Get a node from parametric function. Initialise should be called first.
Defines the nodes and elements of a surface or volume mesh.
bool AddElement(ELEMENT_TYPE Type, const vector< int > &Indices)
Add an element to the mesh of given type with node number checking.
void ConvertQuadstoTriangles(bool bQuality=true)
Convert the quad elements to triangles.
const int AddNode(XYZ Node)
Append a node to the list of nodes, the integer returns the index of the node
pair< XYZ, XYZ > GetAABB(double dGrowDistance=0) const
Get an axis aligned bounding box for the mesh.
void Clear()
Empty mesh nodes and indices.
int IntersectLine(const XYZ &P1, const XYZ &P2, vector< pair< double, XYZ > > &IntersectionPoints, pair< bool, bool > TrimResults=make_pair(false, false), bool bForceFind=false) const
Find the points where a line intersects the mesh.
Represents a point on the centreline of a yarn.
void AssignSectionMesh(const CSectionMesh &SectionMesh)
Assign a mesh to the section.
static double GetArea(const vector< XY > &Section)
Get the area of a section.
virtual const vector< XY > & GetPoints(int iNumPoints, bool bEquiSpaced=false) const
Get a section with given number of points on the perimeter.
Creates a polygonal section, where a list of points are given to form the closed polygon.
Section which represents a rotation of another section angle given in radians.
CDomainPlanes GetDefaultDomain(bool bSheared=false, bool bAddedDomainHeight=true)
void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType)
Used for saving data to XML.
double CalcSinAngle(double R, double Width, double Height) const
void ModifySection(CYarnSectionInterpNode *pYarnSection, YARN_POSITION_INFORMATION &YarnPosInfo, vector< double > &Modifiers, int iNodeIndex, int iMidIndex=-1) const
int ModifyPoints(vector< XY > &Points, vector< double > &Modifiers, vector< XY > &MaxHeight, int iModCount, double dy, vector< XY > &NewPoints) const
vector< XY > m_YSpacing
Vector containing the dx and dy components for spacings along y yarns.
void CalculateModifiers(const CInterpolation *pInterpolation, int Yarn, YARN_POSITION_INFORMATION YarnPosInfo, CMesh &Mesh, vector< vector< vector< double > > > &YarnSectionModifiers, bool bMaxCorrection) const
const vector< PATTERN2D > & GetCellDir(int x, int y, int iDir) const
Swap x and y in GetCell call if transverse yarn is x yarn.
double GetArea(vector< XY > &Points) const
XY Get2DRefPoint(XY &Point, double dAngle) const
void CreateTopAndBottomMeshes(CMesh &TopMesh, CMesh &BottomMesh) const
Create meshes for top and bottom surfaces of domain.
void ReplaceSection(vector< XY > &Points, CYarnSectionInterpNode *pYarnSection, int iNodeIndex, int iMidIndex) const
bool BuildTextile() const
Build the textile.
bool AdjustSectionsForRotation() const
CShearedTextileWeave2D(int iWidth, int iHeight, double dSpacing, double dThickness, double ShearAngle, bool bRefine=true, bool bInPlaneTangents=true)
Build a 2d weave unit cell of given width, height, yarn spacing and fabric thickness.
XY RotatePoint(XY &Point, double dAngle) const
void GetYSpacings() const
Get the x and y components of spacings along y yarns.
XY GetYRepeat() const
Sums all y components of spacings to get y repeat.
void AdjustSections() const
~CShearedTextileWeave2D(void)
A derivation of the CNode class which contains data specific to slave nodes such as sections.
const CDomain * GetDomain() const
vector< CYarn > m_Yarns
Vector of yarns contained within this cell.
bool ConvertToInterpNodes() const
string GetName() const
Get the name associated with this textile.
int AddYarn(const CYarn &Yarn)
Add a Yarn to the textile.
Respresents a 2d woven textile.
void SetInPlaneTangents(bool bInPlaneTangents=true) const
Function to set interpolation so that in-plane tangents are forced at master nodes.
void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType)
Used for saving data to XML.
void AdjustTangents() const
virtual void CorrectInterference() const
Adjust cross section shapes to correct interference.
double m_dFabricThickness
bool Valid() const
Check that the weave pattern contained in m_Pattern is valid.
CObjectContainer< CSectionMesh > m_pSectionMesh
const vector< PATTERN2D > & GetCell(int x, int y) const
vector< vector< int > > m_XYarns
vector< vector< int > > m_YYarns
vector< YARNDATA > m_XYarnData
double GetWidth() const
Get the width of the unit cell.
vector< YARNDATA > m_YYarnData
Class used to meaure the amount of time it takes to perform a certain task.
void stop(const char *msg=0)
Stop the timer and print an optional message.
void check(const char *msg=0)
void start(const char *msg=0)
Represents a yarn consisting of master nodes, section and interpolation function.
const CNode * GetNode(int iIndex) const
Get a master node by index.
void AssignSection(const CYarnSection &YarnSection)
Assign a section to the yarn.
const CYarnSection * GetYarnSection() const
Creates a section which is constant all along the yarn.
Abstract base class used to define the sections along the length of a yarn.
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.
virtual vector< XY > GetSection(const YARN_POSITION_INFORMATION PositionInfo, int iNumPoints, bool bEquiSpaced=false) const =0
This function must be implemented by derived classes.
Creates a section which is linearly interpolated between sections defined at the nodes.
void ReplaceMidSection(int iNodeIndex, int iIndex, const CSection &Section)
Replace a mid node section.
double GetMidNodeSectionPos(int iNodeIndex, int iIndex) const
void ReplaceSection(int iIndex, const CSection &Section)
Replace a section at a node.
const CSection & GetNodeSection(int iIndex) const
void InsertSection(int iIndex, const CSection &Section)
Insert a section at a node.
vector< XY > GetSection(const YARN_POSITION_INFORMATION PositionInfo, int iNumPoints, bool bEquiSpaced=false) const
This function must be implemented by derived classes.
int GetNumNodeSections() const
int GetNumMidNodeSections(int iIndex) const
Namespace containing a series of customised math operations not found in the standard c++ library.
double Max(XYZ &Vector)
Get maximum element of vector and return it.
XY Convert(const XYZ &Val)
double GetLength(const XYZ &Point1, const XYZ &Point2)
Get the length between two points.
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.
XYZ Min(const XYZ &P1, const XYZ &P2)
Given two points, return a new point who's coordinates are the smaller of the two.
double DotProduct(const XYZ &left, const XYZ &right)
Get the dot product of two vectors.
XYZ CrossProduct(const XYZ &left, const XYZ &right)
Get the cross product of two vectors.
Struct for representing a Plane.
Struct for representing points in 2D space.
Struct for representing points in 3D space.
Structure used to represent the position along the length of a yarn.
double dSectionPosition
This variables varies linearly with distance from 0 to 1 from the start to the end of the current lin...
int iSection
This variable represents the index of the current section (where a section is defined as the part bet...
vector< double > SectionLengths
This contains a list of lengths representing the length of each section.