Fawkes API  Fawkes Development Version
spline.cpp
1 
2 /***************************************************************************
3  * spline.cpp - Cubic spline curve
4  *
5  * Created: Tue Oct 07 19:03:51 2008
6  * Copyright 2008 Daniel Beck
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <geometry/spline.h>
25 #include <geometry/hom_vector.h>
26 #include <cmath>
27 
28 using namespace std;
29 
30 namespace fawkes {
31 
32 /** @class fawkes::Spline <geometry/spline.h>
33  * A spline made up of cubic Bezier curves.
34  * @author Daniel Beck
35  */
36 
37 /** Constructor. */
38 Spline::Spline()
39 {
40  m_num_subdivisions = 0;
41 }
42 
43 /** Constructor.
44  * @param control_points the control points of the spline
45  */
46 Spline::Spline(const vector<HomPoint>& control_points)
47  : m_control_points(control_points)
48 {
49  m_num_subdivisions = 0;
50 
52  construct_bezier_curves();
53 }
54 
55 /** Destructor. */
57 {
58 }
59 
60 /** Set the control points.
61  * @param control_points the new control points
62  */
63 void
64 Spline::set_control_points(const vector<HomPoint>& control_points)
65 {
66  m_control_points = control_points;
67 
70  construct_bezier_curves();
71 }
72 
73 /** Set a specific control point.
74  * @param i the index of the control point
75  * @param point the replacement control point
76  */
77 void
78 Spline::set_control_point(unsigned int i, const HomPoint& point)
79 {
80  m_control_points[i] = point;
81 
84  construct_bezier_curves();
85 }
86 
87 /** Get the control points.
88  * @return const reference to the current control points
89  */
90 const vector<HomPoint>&
92 {
93  return m_control_points;
94 }
95 
96 /** Get the Bezier curves.
97  * @return const reference to the current Bezier curves
98  */
99 const vector<Bezier>&
101 {
102  return m_bezier_curves;
103 }
104 
105 /** Get a point on the curve for a specified segment and value t.
106  * @param bezier_index the index of the curve
107  * @param t a value between 0.0 and 1.0
108  * @return a point on the i-th curve for the parameter t
109  */
110 HomPoint
111 Spline::eval(unsigned int bezier_index, float t)
112 {
113  return m_bezier_curves[bezier_index].eval(t);
114 }
115 
116 /** Compute the tangent vector at position t of the i-th Bezier curve.
117  * @param bezier_index the index of the Bezier patch
118  * @param t the curve parameter t
119  * @return the tangent vector
120  */
121 HomVector
122 Spline::tangent(unsigned int bezier_index, float t)
123 {
124  return m_bezier_curves[bezier_index].tangent_at_t(t);
125 }
126 
127 /** Compute the tangent vector at the specified approximation point.
128  * The range of the index is determined by number of subidivisions
129  * that have been performed during the last approximation.
130  * @param point_index index of the approximation point
131  * @return tangent vector
132  */
133 HomVector
134 Spline::tangent(unsigned int point_index)
135 {
136  unsigned int points_per_bezier = (unsigned int) rint( powf(2.0, m_num_subdivisions) ) * 3;
137  unsigned int points_total = m_bezier_curves.size() * (points_per_bezier - 1) + 1;
138 
139  if (point_index >= points_total)
140  { return m_bezier_curves.back().tangent_at_t(1.0); }
141  else
142  {
143  unsigned int bezier_index = point_index / points_per_bezier;
144  unsigned int index = point_index - bezier_index * points_per_bezier;
145 
146  return m_bezier_curves[bezier_index].tangent_at_t( index / (float) points_per_bezier );
147  }
148 }
149 
150 /** Get linear approximation of the curve.
151  * Instead of evaluating the Bezier polynoms at constant intervals the
152  * Bezier curves are subdivided and the control points are taken as an
153  * approximation. This is more efficient and yields better
154  * results. The control points converge to the curve quadratically in
155  * the number of subdivisions.
156  * @param num_subdivisions the number of subdivision that shall be
157  * performed.
158  * @return points approximating the curve
159  */
160 vector<HomPoint>
161 Spline::approximate(unsigned int num_subdivisions)
162 {
163  vector<HomPoint> approximation;
164 
165  for ( vector<Bezier>::iterator bit = m_bezier_curves.begin();
166  bit != m_bezier_curves.end();
167  ++bit )
168  {
169  vector<HomPoint> points = bit->approximate(num_subdivisions);
170  vector<HomPoint>::iterator pit = points.begin();
171 
172  if ( bit != m_bezier_curves.begin() )
173  // skip first control point for all Bezier curves except for
174  // the first one
175  { ++pit; }
176 
177  for ( vector<HomPoint>::iterator iter = pit;
178  iter != points.end();
179  ++iter )
180  {
181  approximation.push_back( *iter );
182  }
183  }
184 
185  m_num_subdivisions = num_subdivisions;
186 
187  return approximation;
188 }
189 
190 void
192 {
193  vector<HomPoint>::iterator iter;
194  for ( iter = m_control_points.begin();
195  iter != m_control_points.end();
196  ++iter )
197  {
198  HomCoord& c = *iter;
199  add_primitive( &c );
200  }
201 }
202 
203 void
205 {
206  construct_bezier_curves();
207 }
208 
209 void
210 Spline::construct_bezier_curves()
211 {
212  m_bezier_curves.clear();
213 
214  if ( 0 == m_control_points.size() )
215  { return; }
216 
217  vector<HomPoint>::iterator i = m_control_points.begin();
218  vector<HomPoint>::iterator prev = i;
219  vector<HomPoint>::iterator cur = ++i;
220  vector<HomPoint>::iterator next = ++i;
221 
222  HomPoint cp1 = (*prev);
223 
224  while ( cur != m_control_points.end() )
225  {
226  HomPoint cp2;
227  HomPoint cp3;
228  HomPoint cp4;
229 
230  HomVector v;
231 
232  v = (*cur) - (*prev);
233 
234  cp2 = (*prev) + v * (1.0 / 3.0);
235  cp3 = (*prev) + v * (2.0 / 3.0);
236 
237  if ( next == m_control_points.end() )
238  { cp4 = *cur; }
239  else
240  {
241  HomPoint t;
242 
243  v = (*next) - (*cur);
244  t = (*cur) + v * (1.0 / 3.0);
245  cp4 = cp3 + (t - cp3) * 0.5;
246  }
247 
248  vector<HomPoint> control_points;
249  control_points.push_back(cp1);
250  control_points.push_back(cp2);
251  control_points.push_back(cp3);
252  control_points.push_back(cp4);
253 
254  m_bezier_curves.push_back( Bezier(control_points) );
255 
256  cp1 = cp4;
257  ++prev;
258  ++cur;
259  ++next;
260  }
261 }
262 
263 } // end namespace fawkes
void clear_primitives()
Clear the list of primitives.
void set_control_point(unsigned int i, const HomPoint &p)
Set a specific control point.
Definition: spline.cpp:78
HomPoint eval(unsigned int bezier_index, float t)
Get a point on the curve for a specified segment and value t.
Definition: spline.cpp:111
Fawkes library namespace.
std::vector< HomPoint > approximate(unsigned int num_subdivisions=4)
Get linear approximation of the curve.
Definition: spline.cpp:161
STL namespace.
void set_control_points(const std::vector< HomPoint > &control_points)
Set the control points.
Definition: spline.cpp:64
virtual ~Spline()
Destructor.
Definition: spline.cpp:56
const std::vector< Bezier > & get_bezier_curves() const
Get the Bezier curves.
Definition: spline.cpp:100
A homogeneous point.
Definition: hom_point.h:33
virtual void register_primitives()
Here, a derived class should register its primitives (HomPoints and HomVectors) by calling add_primit...
Definition: spline.cpp:191
HomVector tangent(unsigned int bezier_index, float t)
Compute the tangent vector at position t of the i-th Bezier curve.
Definition: spline.cpp:122
Base class for homogeneous primitives (vector and point).
Definition: hom_coord.h:34
A homogeneous vector.
Definition: hom_vector.h:31
void add_primitive(HomCoord *c)
Add a primitive to the list of primitives that is transformed.
virtual void post_transform()
This method is called after the primitives are transformed.
Definition: spline.cpp:204
const std::vector< HomPoint > & get_control_points() const
Get the control points.
Definition: spline.cpp:91