GteParametricCurve.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
10 #include <Mathematics/GteVector.h>
13 #include <algorithm>
14 #include <vector>
15 
16 namespace gte
17 {
18 
19 template <int N, typename Real>
21 {
22 protected:
23  // Abstract base class for a parameterized curve X(t), where t is the
24  // parameter in [tmin,tmax] and X is an N-tuple position. The first
25  // constructor is for single-segment curves. The second constructor is
26  // for multiple-segment curves. The times must be strictly increasing.
27  ParametricCurve(Real tmin, Real tmax);
28  ParametricCurve(int numSegments, Real const* times);
29 public:
30  virtual ~ParametricCurve();
31 
32  // To validate construction, create an object as shown:
33  // DerivedClassCurve<N, Real> curve(parameters);
34  // if (!curve) { <constructor failed, handle accordingly>; }
35  inline operator bool() const;
36 
37  // Member access.
38  inline Real GetTMin() const;
39  inline Real GetTMax() const;
40  inline int GetNumSegments() const;
41  Real const* GetTimes() const;
42 
43  // This function applies only when the first constructor is used (two
44  // times rather than a sequence of three or more times).
45  void SetTimeInterval(Real tmin, Real tmax);
46 
47  // Parameters used in GetLength(...), GetTotalLength(), and GetTime(...).
48  void SetRombergOrder(int order); // default = 8
49  void SetMaxBisections(unsigned int maxBisections); // default = 1024
50 
51  // Evaluation of the curve. The function supports derivative calculation
52  // through order 3; that is, maxOrder <= 3 is required. If you want
53  // only the position, pass in maxOrder of 0. If you want the position and
54  // first derivative, pass in maxOrder of 1, and so on. The output
55  // 'values' are ordered as: position, first derivative, second derivative,
56  // third derivative.
57  virtual void Evaluate(Real t, unsigned int maxOrder,
58  Vector<N, Real> values[4]) const = 0;
59 
60  // Differential geometric quantities.
61  Vector<N, Real> GetPosition(Real t) const;
62  Vector<N, Real> GetTangent(Real t) const;
63  Real GetSpeed(Real t) const;
64  Real GetLength(Real t0, Real t1) const;
65  Real GetTotalLength() const;
66 
67  // Inverse mapping of s = Length(t) given by t = Length^{-1}(s). The
68  // inverse length function is generally a function that cannot be written
69  // in closed form, in which case it is not directly computable. Instead,
70  // we can specify s and estimate the root t for F(t) = Length(t) - s. The
71  // derivative is F'(t) = Speed(t) >= 0, so F(t) is nondecreasing. To be
72  // robust, we use bisection to locate the root, although it is possible to
73  // use a hybrid of Newton's method and bisection.
74  Real GetTime(Real length) const;
75 
76  // Compute a subset of curve points according to the specified attribute.
77  // The input 'numPoints' must be two or larger.
78  void SubdivideByTime(int numPoints, Vector<N, Real>* points) const;
79  void SubdivideByLength(int numPoints, Vector<N, Real>* points) const;
80 
81 protected:
82  enum
83  {
86  };
87 
88  std::vector<Real> mTime;
89  mutable std::vector<Real> mSegmentLength;
90  mutable std::vector<Real> mAccumulatedLength;
92  unsigned int mMaxBisections;
93 
95 };
96 
97 
98 template <int N, typename Real>
100  :
101  mTime(2),
102  mSegmentLength(1),
106  mConstructed(false)
107 {
108  mTime[0] = tmin;
109  mTime[1] = tmax;
110  mSegmentLength[0] = (Real)0;
111  mAccumulatedLength[0] = (Real)0;
112 }
113 
114 template <int N, typename Real>
116  :
117  mTime(numSegments + 1),
118  mSegmentLength(numSegments),
119  mAccumulatedLength(numSegments),
122  mConstructed(false)
123 {
124  std::copy(times, times + numSegments + 1, mTime.begin());
125  mSegmentLength[0] = (Real)0;
126  mAccumulatedLength[0] = (Real)0;
127 }
128 
129 template <int N, typename Real>
131 {
132 }
133 
134 template <int N, typename Real> inline
136 {
137  return mConstructed;
138 }
139 
140 template <int N, typename Real> inline
142 {
143  return mTime.front();
144 }
145 
146 template <int N, typename Real> inline
148 {
149  return mTime.back();
150 }
151 
152 template <int N, typename Real> inline
154 {
155  return static_cast<int>(mSegmentLength.size());
156 }
157 
158 template <int N, typename Real> inline
160 {
161  return &mTime[0];
162 }
163 
164 template <int N, typename Real>
166 {
167  if (mTime.size() == 2)
168  {
169  mTime[0] = tmin;
170  mTime[1] = tmax;
171  }
172 }
173 
174 template <int N, typename Real>
176 {
177  mRombergOrder = std::max(order, 1);
178 }
179 
180 template <int N, typename Real>
181 void ParametricCurve<N, Real>::SetMaxBisections(unsigned int maxBisections)
182 {
183  mMaxBisections = std::max(maxBisections, 1u);
184 }
185 
186 template <int N, typename Real>
188 {
190  Evaluate(t, 0, values);
191  return values[0];
192 }
193 
194 template <int N, typename Real>
196 {
198  Evaluate(t, 1, values);
199  Normalize(values[1]);
200  return values[1];
201 }
202 
203 template <int N, typename Real>
205 {
207  Evaluate(t, 1, values);
208  return Length(values[1]);
209 }
210 
211 template <int N, typename Real>
213 {
214  std::function<Real(Real)> speed = [this](Real t)
215  {
216  return GetSpeed(t);
217  };
218 
219  if (mSegmentLength[0] == (Real)0)
220  {
221  // Lazy initialization of lengths of segments.
222  int const numSegments = static_cast<int>(mSegmentLength.size());
223  Real accumulated = (Real)0;
224  for (int i = 0; i < numSegments; ++i)
225  {
227  mTime[i], mTime[i + 1], speed);
228  accumulated += mSegmentLength[i];
229  mAccumulatedLength[i] = accumulated;
230  }
231  }
232 
233  t0 = std::max(t0, GetTMin());
234  t1 = std::min(t1, GetTMax());
235  auto iter0 = std::lower_bound(mTime.begin(), mTime.end(), t0);
236  int index0 = static_cast<int>(iter0 - mTime.begin());
237  auto iter1 = std::lower_bound(mTime.begin(), mTime.end(), t1);
238  int index1 = static_cast<int>(iter1 - mTime.begin());
239 
240  Real length;
241  if (index0 < index1)
242  {
243  length = (Real)0;
244  if (t0 < *iter0)
245  {
247  mTime[index0], speed);
248  }
249 
250  int isup;
251  if (t1 < *iter1)
252  {
254  mTime[index1 - 1], t1, speed);
255  isup = index1 - 1;
256  }
257  else
258  {
259  isup = index1;
260  }
261  for (int i = index0; i < isup; ++i)
262  {
263  length += mSegmentLength[i];
264  }
265  }
266  else
267  {
268  length = Integration<Real>::Romberg(mRombergOrder, t0, t1, speed);
269  }
270  return length;
271 }
272 
273 template <int N, typename Real>
275 {
276  if (mAccumulatedLength.back() == (Real)0)
277  {
278  // Lazy evaluation of the accumulated length array.
279  return GetLength(mTime.front(), mTime.back());
280  }
281 
282  return mAccumulatedLength.back();
283 }
284 
285 template <int N, typename Real>
287 {
288  if (length > (Real)0)
289  {
290  if (length < GetTotalLength())
291  {
292  std::function<Real(Real)> F = [this, &length](Real t)
293  {
295  mTime.front(), t, [this](Real z){ return GetSpeed(z); })
296  - length;
297  };
298 
299  // We know that F(tmin) < 0 and F(tmax) > 0, which allows us to
300  // use bisection. Rather than bisect the entire interval, let's
301  // narrow it down with a reasonable initial guess.
302  Real ratio = length / GetTotalLength();
303  Real omratio = (Real)1 - ratio;
304  Real tmid = omratio * mTime.front() + ratio * mTime.back();
305  Real fmid = F(tmid);
306  if (fmid > (Real)0)
307  {
308  RootsBisection<Real>::Find(F, mTime.front(), tmid, (Real)-1,
309  (Real)1, mMaxBisections, tmid);
310  }
311  else if (fmid < (Real)0)
312  {
313  RootsBisection<Real>::Find(F, tmid, mTime.back(), (Real)-1,
314  (Real)1, mMaxBisections, tmid);
315  }
316  return tmid;
317  }
318  else
319  {
320  return mTime.back();
321  }
322  }
323  else
324  {
325  return mTime.front();
326  }
327 }
328 
329 template <int N, typename Real>
331  Vector<N, Real>* points) const
332 {
333  Real delta = (mTime.back() - mTime.front()) / (Real)(numPoints - 1);
334  for (int i = 0; i < numPoints; ++i)
335  {
336  Real t = mTime.front() + delta * i;
337  points[i] = GetPosition(t);
338  }
339 }
340 
341 template <int N, typename Real>
343  Vector<N, Real>* points) const
344 {
345  Real delta = GetTotalLength() / (Real)(numPoints - 1);
346  for (int i = 0; i < numPoints; ++i)
347  {
348  Real length = delta * i;
349  Real t = GetTime(length);
350  points[i] = GetPosition(t);
351  }
352 }
353 
354 
355 }
void SubdivideByLength(int numPoints, Vector< N, Real > *points) const
Real GetTotalLength() const
GLfixed GLfixed GLint GLint order
Definition: glext.h:4927
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition: glext.h:9013
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition: glext.h:9013
virtual void Evaluate(Real t, unsigned int maxOrder, Vector< N, Real > values[4]) const =0
std::vector< Real > mTime
Vector< N, Real > GetTangent(Real t) const
void SetTimeInterval(Real tmin, Real tmax)
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:1597
Real GetLength(Real t0, Real t1) const
Vector< N, Real > GetPosition(Real t) const
std::vector< Real > mSegmentLength
void SubdivideByTime(int numPoints, Vector< N, Real > *points) const
GLfixed GLfixed GLint GLint GLfixed points
Definition: glext.h:4927
void SetRombergOrder(int order)
Real GetSpeed(Real t) const
std::vector< Real > mAccumulatedLength
void SetMaxBisections(unsigned int maxBisections)
Real Normalize(GVector< Real > &v, bool robust=false)
Definition: GteGVector.h:454
GLdouble GLdouble t
Definition: glext.h:239
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:790
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:843
ParametricCurve(Real tmin, Real tmax)
Real GetTime(Real length) const
DualQuaternion< Real > Length(DualQuaternion< Real > const &d, bool robust=false)
GLsizei GLsizei numSegments
Definition: glext.h:9703
Real const * GetTimes() const
static Real Romberg(int order, Real a, Real b, std::function< Real(Real)> const &integrand)
static unsigned int Find(std::function< Real(Real)> const &F, Real t0, Real t1, unsigned int maxIterations, Real &root)


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:01