TexGen
Section.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 "Section.h"
22#include "TexGen.h"
23#include <limits>
24
25using namespace TexGen;
26CSection::CSection()
27: m_bEquiSpaced(false)
28{
30}
31
33{
34}
35
36CSection::CSection(TiXmlElement &Element)
37{
39 m_bEquiSpaced = valueify<bool>(Element.Attribute("EquiSpaced"));
40 FOR_EACH_TIXMLELEMENT(pEdgePoint, Element, "EdgePoint")
41 {
42 m_EdgePoints.push_back(valueify<XY>(pEdgePoint->Attribute("value")));
43 }
44 TiXmlElement *pSectionMesh = Element.FirstChildElement("SectionMesh");
45 if (pSectionMesh)
46 {
48 }
49}
50
51void CSection::PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType) const
52{
53 Element.SetAttribute("type", GetType());
55 {
56 TiXmlElement SectionMesh("SectionMesh");
57 m_pSectionMesh->PopulateTiXmlElement(SectionMesh, OutputType);
58 Element.InsertEndChild(SectionMesh);
59 }
60 if (OutputType == OUTPUT_FULL)
61 {
62 Element.SetAttribute("EquiSpaced", stringify(m_bEquiSpaced));
63 vector<XY>::const_iterator itPoint;
64 for (itPoint = m_EdgePoints.begin(); itPoint != m_EdgePoints.end(); ++itPoint)
65 {
66 TiXmlElement EdgePoint("EdgePoint");
67 EdgePoint.SetAttribute("value", stringify(*itPoint));
68 Element.InsertEndChild(EdgePoint);
69 }
70 }
71}
72
74{
76}
77
79{
80 const string* pType = Element.Attribute(string("type"));
81 if (pType)
82 {
83 if (*pType == "CSectionBezier")
84 return CSectionBezier(Element);
85 else if (*pType == "CSectionEllipse")
86 return CSectionEllipse(Element);
87 else if (*pType == "CSectionHybrid")
88 return CSectionHybrid(Element);
89 else if (*pType == "CSectionLenticular")
90 return CSectionLenticular(Element);
91 else if (*pType == "CSectionPolygon")
92 return CSectionPolygon(Element);
93 else if (*pType == "CSectionPowerEllipse")
94 return CSectionPowerEllipse(Element);
95 else if (*pType == "CSectionRotated")
96 return CSectionRotated(Element);
97 else if (*pType == "CSectionScaled")
98 return CSectionScaled(Element);
99 else if (*pType == "CSectionRectangle")
100 return CSectionRectangle(Element);
101 }
102 // If the section was not recognised for some reason, revert to using an ellipse
103 // to avoid further problems
104 return CSectionEllipse(1, 1);
105}
106
107const CMesh &CSection::GetMesh(int iNumPoints, bool bEquiSpaced) const
108{
109 if (!m_pSectionMesh)
110 {
111 TGERROR("Unable to get section mesh, section has no mesh assigned to it: " + GetDefaultName());
112 static CMesh EmptyMesh;
113 return EmptyMesh;
114 }
115 const vector<XY> &Section = GetPoints(iNumPoints, bEquiSpaced);
116 return m_pSectionMesh->GetMesh(Section);
117}
118
119const vector<XY> &CSection::GetPoints(int iNumPoints, bool bEquiSpaced) const
120{
121 if (iNumPoints != (int)m_EdgePoints.size() || bEquiSpaced != m_bEquiSpaced)
122 {
123 if (!bEquiSpaced || !CreateEquiSpacedSection(iNumPoints))
124 CreateSection(iNumPoints);
125 }
126 return m_EdgePoints;
127}
128
129void CSection::CreateSection(int iNumPoints) const
130{
131 m_bEquiSpaced = false;
132 m_EdgePoints.clear();
133 XY Point;
134 int i;
135 double t;
136 for (i=0; i<iNumPoints; ++i)
137 {
138 t = (double)i/(double)iNumPoints;
139 m_EdgePoints.push_back(GetPoint(t));
140 }
141}
142
143bool CSection::CreateEquiSpacedSection(int iNumPoints) const
144{
145 m_bEquiSpaced = true;
146 int i, j;
147 int iMaxIterations = 1000;
148 double dStdDevTolerance = 1E-12;
149 double t;
150 double dLength;
151 double dStdDev;
152 double dAvgLength;
153 int IncreaseStdDevCount = 0;
154 double PrevStdDev = 0.0;
155 double MinDouble = std::numeric_limits<double>::min();
156 vector<double> dLengths;
157 dLengths.resize(iNumPoints);
158
159 m_EdgePoints.resize(iNumPoints);
160 // The spacing vector stores the increment in t between nodes.
161 // Initially the increment in t values between all nodes should be equal.
162 // Note that the sum of t increments in the Spacing vector must equal 1.
163 vector<double> Spacing;
164 t = 1/double(iNumPoints);
165 Spacing.resize(iNumPoints, t);
166
167 for (j=0; j<iMaxIterations; ++j)
168 {
169 // Get the section using the spacing vector
170 for (i=0, t=0; i<iNumPoints; t+=Spacing[i], ++i)
171 {
173 }
174 // Find the average distance between section points
175 dAvgLength = 0;
176 for (i=0; i<iNumPoints; ++i)
177 {
178 dLengths[i] = GetLength(m_EdgePoints[i], m_EdgePoints[(i+1)%iNumPoints]);
179 if ( dLengths[i] < MinDouble )
180 //if ( dLengths[i] < 10 * DBL_MIN )
181 {
182 TGERROR("Unable to create equispaced points, Length = " + stringify(dLength) );
183 return false;
184 }
185 dAvgLength += dLengths[i];
186 }
187 dAvgLength /= iNumPoints;
188 // Calculate the standard deviation of distance between nodes
189 // And adjust the spacing vector such that the nodes become
190 // more evenly spaced
191 dStdDev = 0;
192 for (i=0; i<iNumPoints; ++i)
193 {
194 dStdDev += (dLengths[i]-dAvgLength)*(dLengths[i]-dAvgLength);
195 Spacing[i] *= dAvgLength/dLengths[i];
196 }
197 dStdDev /= iNumPoints;
198 if (dStdDev > PrevStdDev )
199 ++IncreaseStdDevCount;
200 PrevStdDev = dStdDev;
201 // If the standard deviation is low enough, our points are evenly spaced enough
202 if (dStdDev < dStdDevTolerance)
203 {
204 return true;
205 }
206 if ( IncreaseStdDevCount > 200 ) // Iteration switched direction too many times - not reaching answer
207 {
208 TGERROR("Unable to create equispaced section points, iteration unstable: " + GetDefaultName());
209 return false;
210 }
211 // Calculate the total value of t in the spacing vector
212 // and adjust all values so that the sum equals 1
213 t = 0;
214 for (i=0; i<iNumPoints; ++i)
215 {
216 t += Spacing[i];
217 }
218 for (i=0; i<iNumPoints; ++i)
219 {
220 Spacing[i] /= t;
221 }
222 }
223 TGERROR("Unable to create equispaced section points, maximum iterations exceeded: " + GetDefaultName());
224 return false;
225}
226
228{
229 m_pSectionMesh = SectionMesh;
230}
231
233{
234 if ( !m_pSectionMesh )
235 return;
236 m_pSectionMesh->SetNumLayers( iNum );
237}
238
240{
241 if ( !m_pSectionMesh )
242 return -1;
243 int iNumLayers = -1;
244
245 string type = m_pSectionMesh->GetType();
246 if ( type == "CSectionMeshRectangular" )
247 {
249 iNumLayers = sectionMesh->GetNumLayers();
250 delete sectionMesh;
251 }
252 else if ( type == "CSectionMeshRectangleSection" )
253 {
255 iNumLayers = sectionMesh->GetNumLayers();
256 delete sectionMesh;
257 }
258 return iNumLayers;
259}
260
261double CSection::GetArea(const vector<XY> &Section)
262{
263 double dArea = 0;
264 int i;
265 for (i=0; i<(int)Section.size(); ++i)
266 {
267 dArea += Section[i].x*Section[(i+1)%Section.size()].y - Section[(i+1)%Section.size()].x*Section[i].y;
268 }
269 dArea /= 2;
270 return dArea;
271}
272
273double CSection::GetCircumference(const vector<XY> &Section)
274{
275 int i;
276 double dCircumference = 0;
277 for (i=0; i<(int)Section.size(); ++i)
278 {
279 dCircumference += ::GetLength(Section[i], Section[(i+1)%Section.size()]);
280 }
281 return dCircumference;
282}
283
284/*
285double CSection::GetCircumference()
286{
287 int i;
288 const int iDivisions = 1000;
289 double t, dCircumference = 0;
290 XY CurPos, PrevPos;
291 PrevPos = GetPoint(0);
292 for (i=0; i<iDivisions; ++i)
293 {
294 t = (double)(i+1)/(double)(iDivisions);
295 CurPos = GetPoint(t);
296 dCircumference += ::GetLength(PrevPos, CurPos);
297 PrevPos = CurPos;
298 }
299 return dCircumference;
300}
301*/
302
303
304
305
306
307
308
#define TGERROR(MESSAGE)
Macros used to report the file name and line number to the TexGenError and TexGenLog functions.
Definition: Logger.h:29
#define FOR_EACH_TIXMLELEMENT(CHILDELEMENT, PARENTELEMENT, ELEMENTNAME)
Macro to enable looping over tinyxml easier.
Definition: Misc.h:45
Defines the nodes and elements of a surface or volume mesh.
Definition: Mesh.h:58
Object container to help handle memory management issues.
Section made up of bezier curves.
Definition: SectionBezier.h:38
Elliptical Section.
virtual void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType) const
Used for saving data to XML.
Definition: Section.cpp:51
vector< XY > m_EdgePoints
List of 2d points creating the outline of the cross-section.
Definition: Section.h:119
void AssignDefaults()
Definition: Section.cpp:73
const CMesh & GetMesh(int iNumPoints, bool bEquiSpaced=true) const
Definition: Section.cpp:107
friend class CSectionRotated
Definition: Section.h:33
static CObjectContainer< CSection > CreateSection(TiXmlElement &Element)
Create a section from TiXmlElement.
Definition: Section.cpp:78
void AssignSectionMesh(const CSectionMesh &SectionMesh)
Assign a mesh to the section.
Definition: Section.cpp:227
bool m_bEquiSpaced
Keep this variable to determine whether the section was created with equidistant points or not.
Definition: Section.h:122
virtual string GetType() const =0
Derived class should return the class name.
void SetSectionMeshLayers(int iNum)
Specify number of layers for associated section mesh.
Definition: Section.cpp:232
static double GetArea(const vector< XY > &Section)
Get the area of a section.
Definition: Section.cpp:261
virtual string GetDefaultName() const =0
Get the default name to assign to a section.
virtual const vector< XY > & GetPoints(int iNumPoints, bool bEquiSpaced=false) const
Get a section with given number of points on the perimeter.
Definition: Section.cpp:119
virtual XY GetPoint(double t) const =0
Get a point lying on the perimeter correspending to parametric value t.
virtual ~CSection(void)
Definition: Section.cpp:32
CObjectContainer< CSectionMesh > m_pSectionMesh
Pointer to a derived class of SectionMesh, this class is in charge of creating the section mesh.
Definition: Section.h:125
friend class CSectionHybrid
Definition: Section.h:32
friend class CSectionScaled
Definition: Section.h:34
bool CreateEquiSpacedSection(int iNumPoints) const
Same as CreateSection except all the points will be spaced the same distance apart.
Definition: Section.cpp:143
static double GetCircumference(const vector< XY > &Section)
Get the circumference of a section.
Definition: Section.cpp:273
int GetSectionMeshLayers()
Get the number of layers for associated section mesh.
Definition: Section.cpp:239
Abstract base class to create a 2D mesh of a section.
Definition: SectionMesh.h:33
static CObjectContainer< CSectionMesh > CreateSectionMesh(TiXmlElement &Element)
Create a section from TiXmlElement.
Definition: SectionMesh.cpp:52
Create a rectangular mesh, the number of layers can be specified or set as -1 for automatic determina...
Create a rectangular mesh, the number of layers can be specified or set as -1 for automatic determina...
Creates a polygonal section, where a list of points are given to form the closed polygon.
Namespace containing a series of customised math operations not found in the standard c++ library.
OUTPUT_TYPE
Definition: Misc.h:105
@ OUTPUT_FULL
Definition: Misc.h:108
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
Struct for representing points in 2D space.
Definition: mymath.h:103