TexGen
Interpolation.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 "Interpolation.h"
22#include "InterpolationBezier.h"
23#include "InterpolationCubic.h"
25#include "InterpolationLinear.h"
26
27using namespace TexGen;
28
29CInterpolation::CInterpolation(bool bPeriodic, bool bForceInPlaneTangent, bool bForceMasterNodeTangent)
30: m_bPeriodic(bPeriodic)
31, m_bForceInPlaneTangent(bForceInPlaneTangent)
32, m_bForceMasterNodeTangent(bForceMasterNodeTangent)
33{
34}
35
37{
38}
39
40CInterpolation::CInterpolation(TiXmlElement &Element)
41: m_bPeriodic(true)
42, m_bForceInPlaneTangent(false)
43, m_bForceMasterNodeTangent(false)
44{
45 const string* pPeriodic = Element.Attribute(string("Periodic"));
46 if (pPeriodic)
47 m_bPeriodic = valueify<bool>(*pPeriodic);
48 const string* pForceInPlaneTangent = Element.Attribute(string("ForceInPlaneTangent"));
49 if (pForceInPlaneTangent)
50 m_bForceInPlaneTangent = valueify<bool>(*pForceInPlaneTangent);
51 const string* pForceMasterNodeTangent = Element.Attribute(string("ForceMasterNodeTangent"));
52 if (pForceMasterNodeTangent)
53 m_bForceMasterNodeTangent = valueify<bool>(*pForceMasterNodeTangent);
54}
55
56void CInterpolation::PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType) const
57{
58 Element.SetAttribute("Periodic", m_bPeriodic);
59 Element.SetAttribute("ForceInPlaneTangent", m_bForceInPlaneTangent);
60 Element.SetAttribute("ForceMasterNodeTangent", m_bForceMasterNodeTangent);
61 Element.SetAttribute("type", GetType());
62}
63
65{
66 const string* pType = Element.Attribute(string("type"));
67 if (pType)
68 {
69 if (*pType == "CInterpolationBezier")
70 return CInterpolationBezier(Element);
71 else if (*pType == "CInterpolationCubic")
72 return CInterpolationCubic(Element);
73 else if (*pType == "CInterpolationAdjusted")
74 return CInterpolationAdjusted(Element);
75 else if (*pType == "CInterpolationLinear")
76 return CInterpolationLinear(Element);
77 }
78 // If the interpolation was not recognised for some reason, revert to using bezier
79 // interpolation to avoid further problems
80 return CInterpolationBezier();
81}
82
83void CInterpolation::InterpolateUp(const CNode &Node1, const CNode &Node2, CSlaveNode &SlaveNode, double t)
84{
85 XYZ U1, U2, SlaveUp;
86 U1 = Node1.GetUp();
87 U2 = Node2.GetUp();
88 if (!U1)
89 U1.z = 1;
90 if (!U2)
91 U2.z = 1;
92 SlaveUp = U1 + (U2-U1) * t;
93 Normalise(SlaveUp);
94 SlaveNode.SetUp(SlaveUp);
95 SlaveNode.ProjectUp();
96}
97
98void CInterpolation::InterpolateAngle(const CNode &Node1, const CNode &Node2, CSlaveNode &SlaveNode, double t)
99{
100 double A1, A2, SlaveA;
101 A1 = Node1.GetAngle();
102 A2 = Node2.GetAngle();
103 if ( A1 == 0.0 && A2 == 0.0 )
104 return;
105
106 SlaveA = A1 + (A2-A1) * t;
107 SlaveNode.SetAngle(SlaveA);
108}
109
110
111/*
112double CInterpolation::GetLength(vector<CNode> &MasterNodes)
113{
114 int i, j;
115 const int iDivisions = 1000;
116 double t, dLength = 0;
117 CSlaveNode CurNode, PrevNode;
118 PrevNode = GetNode(MasterNodes, 0, 0);
119 for (i=0; i<(int)MasterNodes.size()-1; ++i)
120 {
121 for (j=0; j<iDivisions; ++j)
122 {
123 t = (double)(j+1)/(double)(iDivisions);
124 CurNode = GetNode(MasterNodes, i, t);
125 dLength += ::GetLength(PrevNode.GetPosition(), CurNode.GetPosition());
126 PrevNode = CurNode;
127 }
128 }
129 return dLength;
130}
131*/
132CSlaveNode CInterpolation::GetNode(const vector<CNode> &MasterNodes, double t) const
133{
134 int iNumSections = (int)MasterNodes.size()-1;
135 t *= iNumSections;
136 int iIndex = int(t);
137 t -= iIndex;
138 if (iIndex >= iNumSections)
139 {
140 iIndex = iNumSections-1;
141 t = 1;
142 }
143 return GetNode(MasterNodes, iIndex, t);
144}
145
146vector<CSlaveNode> CInterpolation::GetSlaveNodes(const vector<CNode> &MasterNodes, int iNumPoints, bool bEquiSpaced) const
147{
148 vector<CSlaveNode> SlaveNodes;
149 Initialise(MasterNodes);
150 if (!bEquiSpaced || !CreateEquiSpacedSlaveNodes(SlaveNodes, MasterNodes, iNumPoints))
151 CreateSlaveNodes(SlaveNodes, MasterNodes, iNumPoints);
152 return SlaveNodes;
153}
154
155void CInterpolation::CreateSlaveNodes(vector<CSlaveNode> &SlaveNodes, const vector<CNode> &MasterNodes, int iNumPoints) const
156{
157 double t;
158 int i;
159 SlaveNodes.clear();
160 for (i=0; i<iNumPoints; ++i)
161 {
162 t = double(i)/double(iNumPoints-1);
163 SlaveNodes.push_back(GetNode(MasterNodes, t));
164 }
165}
166
167bool CInterpolation::CreateEquiSpacedSlaveNodes(vector<CSlaveNode> &SlaveNodes, const vector<CNode> &MasterNodes, int iNumPoints) const
168{
169 if (iNumPoints <= 1)
170 {
171 TGERROR("Unable to create equispaced slave nodes, not enough points: " << iNumPoints);
172 assert(false);
173 return false;
174 }
175
176 // Approximate the total length of the yarn and length of yarn sections
177 // from master nodes assuming linear interpolation
178 vector<double> SectionLengths;
179 int i, j;
180 int iNumNodes = (int)MasterNodes.size();
181 double dLength;
182 for (i=0; i<iNumNodes-1; ++i)
183 {
184 dLength = GetLength(MasterNodes[i+1].GetPosition() - MasterNodes[i].GetPosition());
185 SectionLengths.push_back(dLength);
186 }
187 double dTotalLength = accumulate(SectionLengths.begin(), SectionLengths.end(), 0.0);
188
189 // For each master node store the T value and L values
190 // The T value varies from 0 to 1 across the master nodes at
191 // constant intervals, whereas the L value represent the
192 // length along the yarn of the master node
193 vector<double> LValues;
194 vector<double> TValues;
195 double t, L;
196
197 double dt = 1/double(iNumNodes-1);
198 for (i=0, t=0, L=0; i<iNumNodes; ++i, t+=dt)
199 {
200 TValues.push_back(t);
201 LValues.push_back(L);
202 if (i<iNumNodes-1)
203 L+=SectionLengths[i];
204 }
205
206 // We want the slave nodes to be equispaced with length along the yarn
207 // so calculate an L value for each slave node then convert it to the T value
208 double dl = dTotalLength/double(iNumPoints-1);
209 SlaveNodes.clear();
210 SlaveNodes = CalcSlaveNodePositions( MasterNodes, LValues, TValues, dl, iNumNodes, iNumPoints );
211
212
213 // If there is a high curvature in the yarn the initial estimate of length will be too small
214 // leading to uneven distances between points when the t values are calculated for the actual curved lines
215 // Calculate the new section length by summing the distances between the two master nodes
216 // on each end and all the slave nodes in between.
217 SectionLengths.clear();
218 SectionLengths.resize(iNumNodes-1);
219 XYZ PrevPos;
220
221 for (i=0; i<iNumNodes-1; ++i)
222 {
223 SectionLengths[i] = 0;
224 PrevPos = MasterNodes[i].GetPosition();
225 for (j=0; j<int(SlaveNodes.size()); ++j)
226 {
227 if (SlaveNodes[j].GetIndex() == i)
228 {
229 SectionLengths[i] += GetLength(PrevPos, SlaveNodes[j].GetPosition());
230 PrevPos = SlaveNodes[j].GetPosition();
231 }
232 }
233 SectionLengths[i] += GetLength(PrevPos, MasterNodes[i+1].GetPosition());
234 }
235 double dNewTotalLength = accumulate(SectionLengths.begin(), SectionLengths.end(), 0.0);
236
237 // If more than 5% difference between original length estimate and length using slave nodes, recalculate t values
238 if ( fabs( (dNewTotalLength - dTotalLength)/dTotalLength ) > 0.05 )
239 {
240 LValues.clear();
241 TValues.clear();
242
243 for (i=0, t=0, L=0; i<iNumNodes; ++i, t+=dt)
244 {
245 TValues.push_back(t);
246 LValues.push_back(L);
247 if (i<iNumNodes-1)
248 L+=SectionLengths[i];
249 }
250
251 // We want the slave nodes to be equispaced with length along the yarn
252 // so calculate an L value for each slave node then convert it to the T value
253 double dl = dNewTotalLength/double(iNumPoints-1);
254 SlaveNodes.clear();
255 SlaveNodes = CalcSlaveNodePositions( MasterNodes, LValues, TValues, dl, iNumNodes, iNumPoints );
256 }
257
258 return true;
259}
260
261void CInterpolation::CalculateNodeCoordinateSystem(const vector<CNode> &MasterNodes, vector<XYZ> &Tangents) const
262{
263 int i, iNumNodes = (int)MasterNodes.size();
264 Tangents.resize(iNumNodes, XYZ());
265 if (iNumNodes <= 1)
266 {
267 // We need at least 2 nodes to calculate tangents
268 TGERROR("Unable to calculate node coordinate system, not enough master nodes specified");
269 assert(false);
270 return;
271 }
272 XYZ YarnRepeat;
273 XYZ PrevPos, NextPos;
274 XYZ Tangent, Up;
275 YarnRepeat = MasterNodes[iNumNodes-1].GetPosition() - MasterNodes[0].GetPosition();
276 for (i=0; i<iNumNodes; ++i)
277 {
278 // Get the position of the previous node in the list of parent nodes
279 // if the previous node is non-existant then use equivalent repeated node position - yarn repeat
280 if (i==0)
281 {
282 if (m_bPeriodic)
283 PrevPos = MasterNodes[iNumNodes-2].GetPosition() - YarnRepeat;
284 else
285 PrevPos = MasterNodes[0].GetPosition();
286 }
287 else
288 PrevPos = MasterNodes[i-1].GetPosition();
289 // Get the position of the next node in the list of parent nodes
290 // if the next node is non-existent then use the equivalent repeated node position + yarn repeat
291 if (i==iNumNodes-1)
292 {
293 if (m_bPeriodic)
294 NextPos = MasterNodes[1].GetPosition() + YarnRepeat;
295 else
296 NextPos = MasterNodes[iNumNodes-1].GetPosition();
297 }
298 else
299 NextPos = MasterNodes[i+1].GetPosition();
300
301 // The tangent is calculated as the normalisation of the next parent node position - the previous
302 Tangent = NextPos - PrevPos;
303 assert(::GetLength(Tangent) != 0);
304 Normalise(Tangent);
305
306 if (MasterNodes[i].GetTangent())
307 Tangents[i] = MasterNodes[i].GetTangent();
308 else
309 Tangents[i] = Tangent;
310 if ( m_bForceMasterNodeTangent ) // Force master node tangents to be in-plane
311 Tangents[i].z = 0;
312 }
313}
314
315vector<CSlaveNode> CInterpolation::CalcSlaveNodePositions( const vector<CNode> &MasterNodes, vector<double> &LValues, vector<double> &TValues, double dL, int iNumNodes, int iNumPoints ) const
316{
317
318 vector<CSlaveNode> SlaveNodes;
319 int j = 0, i;
320 double t, u, L;
321 for (i=0, L=0.0; i<iNumPoints; ++i, L += dL)
322 {
323 // Convert L value to t value
324 if (L < LValues[0])
325 {
326 t = 0;
327 }
328 else if (L > LValues[iNumNodes-1])
329 {
330 t = 1;
331 }
332 else
333 {
334 while ( j < iNumNodes-1 )
335 {
336 if (LValues[j] <= L && L <= LValues[j+1])
337 {
338 u = (L-LValues[j])/(LValues[j+1]-LValues[j]);
339 t = TValues[j] + u*(TValues[j+1]-TValues[j]);
340 break;
341 }
342 j++;
343 }
344 }
345 CSlaveNode SlaveNode = GetNode(MasterNodes, t);
346 SlaveNodes.push_back(SlaveNode);
347 }
348 return SlaveNodes;
349}
350
351
352
353
354
#define TGERROR(MESSAGE)
Macros used to report the file name and line number to the TexGenError and TexGenLog functions.
Definition: Logger.h:29
Bezier interpolation for yarn paths.
Bezier interpolation for yarn paths.
Cubic spline interpolation for yarn paths.
virtual string GetType() const =0
Derived class should return the class name.
static void InterpolateUp(const CNode &Node1, const CNode &Node2, CSlaveNode &SlaveNode, double t)
void CreateSlaveNodes(vector< CSlaveNode > &SlaveNodes, const vector< CNode > &MasterNodes, int iNumPoints) const
Create slave nodes with specified number of points between master nodes.
virtual void PopulateTiXmlElement(TiXmlElement &Element, OUTPUT_TYPE OutputType) const
Used for saving data to XML.
virtual void Initialise(const vector< CNode > &MasterNodes) const
Definition: Interpolation.h:60
virtual CSlaveNode GetNode(const vector< CNode > &MasterNodes, int iIndex, double t) const =0
Get a node from parametric function. Initialise should be called first.
static void InterpolateAngle(const CNode &Node1, const CNode &Node2, CSlaveNode &SlaveNode, double t)
vector< CSlaveNode > GetSlaveNodes(const vector< CNode > &MasterNodes, int iNumPoints, bool bEquiSpaced=true) const
Get a list of nodes along the centre line of the yarn.
virtual ~CInterpolation(void)
bool CreateEquiSpacedSlaveNodes(vector< CSlaveNode > &SlaveNodes, const vector< CNode > &MasterNodes, int iNumPoints) const
Create slave nodes equispaced with total specified number of points.
vector< CSlaveNode > CalcSlaveNodePositions(const vector< CNode > &MasterNodes, vector< double > &LValues, vector< double > &TValues, double dL, int iNumNodes, int iNumPoints) const
void CalculateNodeCoordinateSystem(const vector< CNode > &MasterNodes, vector< XYZ > &Tangents) const
static CObjectContainer< CInterpolation > CreateInterpolation(TiXmlElement &Element)
Create an interpolation from TiXmlElement.
CInterpolation(bool bPeriodic, bool bForceInPlaneTangent, bool bForceMasterNodeTangent)
Bezier interpolation for yarn paths.
Represents a point on the centreline of a yarn.
Definition: Node.h:28
void ProjectUp()
Project the Up vector such that it is perpendicular to the tangent.
Definition: Node.cpp:71
XYZ GetUp() const
Definition: Node.h:59
void SetAngle(double Angle)
Definition: Node.h:65
void SetUp(XYZ Up)
Definition: Node.h:64
double GetAngle() const
Definition: Node.h:60
Object container to help handle memory management issues.
A derivation of the CNode class which contains data specific to slave nodes such as sections.
Definition: SlaveNode.h:30
Namespace containing a series of customised math operations not found in the standard c++ library.
OUTPUT_TYPE
Definition: Misc.h:105
double GetLength(const XYZ &Point1, const XYZ &Point2)
Get the length between two points.
Definition: mymath.h:540
WXYZ & Normalise(WXYZ &Quaternion)
Normalise the quaternion and return it.
Definition: mymath.h:609
Struct for representing points in 3D space.
Definition: mymath.h:56
double z
Definition: mymath.h:57