vgl_cubic_spline_2d.h
Go to the documentation of this file.
1 // This is core/vgl/vgl_cubic_spline_2d.h
2 #ifndef vgl_cubic_spline_2d_h_
3 #define vgl_cubic_spline_2d_h_
4 //:
5 // \file
6 // \brief A 3-d cubic spline curve defined by a set of knots (3-d points)
7 // \author J.L. Mundy
8 //
9 // \verbatim
10 // Modifications
11 // Initial version Sept. 25, 2015
12 // \endverbatim
13 // the current algorithm uses the Catmull-Rom spline
14 //
15 // The parameter s is used in estimating the first derivative of the
16 // function at the ends of the interval:
17 // f'(0) = s*(f(1)-f(-1)), f'(1) = s*(f(2)-f(1));
18 // the typical value of s is 0.5
19 //
20 // computations are simple enough so everything is in the .h file
21 //
22 #include <iosfwd>
23 #include <utility>
24 #include <vector>
25 #include <cassert>
26 #ifdef _MSC_VER
27 # include <vcl_msvc_warnings.h>
28 #endif
29 #include <vgl/vgl_point_2d.h>
30 #include <vgl/vgl_vector_2d.h>
31 
32 template <class Type>
34 {
35  bool closed_curve_; // is the curve closed?
36  Type s_; // the parameter defining the first derivative at knots
37  std::vector<vgl_point_2d<Type> > knots_; // the spline knots
38  public:
39  //: Default constructor - does not initialise!
40  vgl_cubic_spline_2d(): closed_curve_(false), s_(Type(0.5)) {}
41 
42  //: Construct from set of knots
44  Type s = Type(0.5),
45  bool closed = false)
46  : closed_curve_(closed), s_(s), knots_(std::move(knots)){}
47 
48  //: accessors
49  bool closed() const {return closed_curve_;}
50  Type s() const {return s_;}
51  std::vector<vgl_point_2d<Type> > knots() const {return knots_;}
52 
53  void set_knots(std::vector<vgl_point_2d<Type> > const& knots, bool closed)
55  void set_s(Type s){s_ = s;}
56 
57  //: maximum value of the spline parameter
58  Type max_t() const {return static_cast<Type>(knots_.size()-1);}
59 
60  //: Equality operator
61  bool operator == (const vgl_cubic_spline_2d<Type> &spl) const;
62 
63  bool operator!=(vgl_cubic_spline_2d<Type>const& spl) const { return !operator==(spl); }
64 
65  //: The next two accessors are useful for interpolating other quantities than position with the same spatial spline, e.g. a vector field
66  // see the implementation of the () operator as an example
67 
68  //: interpolating function (Catmull-Rom). V is the value to be interpolated, specified at four points
69  // A is the resulting set of cubic coefficients, i.e., v(t) = a3 t^3 + a2 t^2 + a1 t + a0.
70  // the interval being interpolated is from v0 to v1
71  //: interpolating function (Catmull-Rom). V is the value to be interpolated, specified at four points
72  // A is the resulting set of cubic coefficients, i.e., v(t) = a3 t^3 + a2 t^2 + a1 t + a0.
73  // the interval being interpolated is from v0 to v1
74  void coefficients(Type vm1, Type v0, Type v1, Type v2, Type& a0, Type& a1, Type& a2, Type& a3) const;
75 
76  //: the indices for the knots bounding the interval containing t, u is the local parameter in the interval 0 -> 1
77  void knot_indices(Type t, unsigned& im1, unsigned& i0, unsigned& i1, unsigned& i2, Type& u) const;
78 
79 
80  //: function value at t, where 0 <= t <= n-1 and n is the number of knots
81  vgl_point_2d<Type> operator ()(Type t) const;
82 
83  vgl_vector_2d<Type> tangent(Type t) const;
84 
85 };
86 // ================= methods and public functions ===================
87 template <class Type>
88 void vgl_cubic_spline_2d<Type>::coefficients(Type vm1, Type v0, Type v1, Type v2,
89  Type& a0, Type& a1, Type& a2, Type& a3) const{
90  a3= (2-s_)*v0+(s_-2)*v1-s_*vm1+s_*v2;
91  a2= (s_-3)*v0 + (3-2*s_)*v1 + 2*s_*vm1-s_*v2;
92  a1= -s_*vm1 + s_*v1;
93  a0= v0;
94 }
95 
96 template <class Type>
97 void vgl_cubic_spline_2d<Type>::knot_indices(Type t, unsigned& im1, unsigned& i0, unsigned& i1, unsigned& i2, Type& u) const{
98  unsigned offset = static_cast<unsigned>(t);
99  // bounding condition for the exact end of the curve
100  if(offset == (static_cast<unsigned>(knots_.size())-1))
101  offset--;
102  i0 = offset; i1 = offset+1;
103  // logic for selecting knots under various boundary conditions
104  // begining of the curve
105  if(offset == 0){
106  if(closed_curve_)
107  im1 = static_cast<unsigned>(knots_.size()-1);
108  else
109  im1 = i0;
110  }else
111  im1 = offset-1;
112  // end of the curve
113  if(offset == static_cast<unsigned>(knots_.size()-2)){
114  if(closed_curve_)
115  i2 = 0;
116  else
117  i2 = i1;
118  }else
119  i2 = offset+2;
120  // the value the parameter within the interval of interest (0<=u<=1)
121  u = t - static_cast<Type>(offset);
122 }
123 
124 template <class Type>
126  if(spl.closed()!=closed_curve_) return false;
127  if(spl.s()!=s_) return false;
128  std::vector<vgl_point_2d<Type> > knots = spl.knots();
129  unsigned n = static_cast<unsigned>(knots.size());
130  if(n!= knots_.size()) return false;
131  for(unsigned i =0; i<n; ++i)
132  if(knots[i] != knots_[i])
133  return false;
134  return true;
135 }
136 
137 template <class Type>
140  if(knots_.size() < 2)
141  return ret;
142  assert(t>=Type(0) && t<=max_t());
143  unsigned im1, i0, i1, i2;
144  Type u;
145  knot_indices(t, im1, i0, i1, i2, u);
146  vgl_point_2d<Type> pm1 = knots_[im1], p0 = knots_[i0];
147  vgl_point_2d<Type> p1 = knots_[i1], p2 = knots_[i2];
148  // monomials
149  Type u2 = u*u, u3 = u2*u;
150  // coefficients
151  Type a0x, a1x, a2x, a3x;
152  Type a0y, a1y, a2y, a3y;
153  coefficients(pm1.x(), p0.x(), p1.x(), p2.x(), a0x, a1x, a2x, a3x);
154  coefficients(pm1.y(), p0.y(), p1.y(), p2.y(), a0y, a1y, a2y, a3y);
155  // interpolate 3-d point on spline
156  Type x = a3x*u3 + a2x*u2 + a1x*u + a0x;
157  Type y = a3y*u3 + a2y*u2 + a1y*u + a0y;
158  ret.set(x, y);
159  return ret;
160 }
161 template <class Type>
163  Type zero = static_cast<Type>(0);
164  Type nm1 = max_t();
165  Type del = static_cast<Type>(0.01);
166  vgl_vector_2d<Type> tang;
167  Type tp, tm;
168  // non-boundary case
169  if(t>zero && t<nm1){
170  tm = t-del;
171  if(tm<zero) tm = t;
172  tp = t+del;
173  if(tp>nm1)
174  tp = nm1-t;
175  vgl_point_2d<Type> pm = (*this)(tm), pp = (*this)(tp);
176  tang = pp-pm;
177  }
178  // Case I t==0
179  if(t==zero){
180  tp = del;
181  if(closed_curve_)
182  tm = nm1-del;
183  else
184  tm = zero;
185  vgl_point_2d<Type> pm = (*this)(tm), pp = (*this)(tp);
186  tang = pp-pm;
187  }
188  if(t==nm1){
189  tm = nm1-del;
190  if(closed_curve_)
191  tp = del;
192  else
193  tp = nm1;
194  vgl_point_2d<Type> pm = (*this)(tm), pp = (*this)(tp);
195  tang = pp-pm;
196  }
197  tang/=tang.length();
198  return tang;
199 }
200 
201 //: stream operators
202 template <class Type>
203 std::ostream& operator<<(std::ostream& ostr, vgl_cubic_spline_2d<Type> const& spl){
204  if(!ostr){
205  std::cout << "Bad ostream in write vgl_cubic_spline_2d to stream\n";
206  return ostr;
207  }
208  int ic = 0;
209  if(spl.closed())
210  ic = 1;
211  Type s = spl.s();
212  ostr << ic << ' ' << s << '\n';
213  std::vector<vgl_point_2d<Type> > knots = spl.knots();
214  for(unsigned i =0; i<static_cast<unsigned>(knots.size()); i++){
215  const vgl_point_2d<Type>& p = knots[i];
216  ostr << p.x() << ',' << p.y() << '\n';
217  }
218  return ostr;
219 }
220 
221 template <class Type>
222 std::istream& operator>>(std::istream& istr, vgl_cubic_spline_2d<Type>& spl){
223  if(!istr){
224  std::cout << "Bad istream in read vgl_cubic_spline_2d from stream\n";
225  return istr;
226  }
227  int ic;
228  Type s;
229  istr >> ic >> s;
230  bool closed = ic!=0;
231  Type x, y;
232  unsigned char c;
233  std::vector<vgl_point_2d<Type> > knots;
234  // this loop termination may look strange
235  // but testing the stream is more reliable
236  // then the state of istr.eof()
237  while(istr >> x >> c){
238  if(c!=','){
239  std::cout << "Bad file format\n";
240  return istr;
241  }
242  istr >> y;
243  vgl_point_2d<Type> p(x,y);
244  knots.push_back(p);
245  }
246  spl = vgl_cubic_spline_2d<Type>(knots, s , closed);
247  return istr;
248 };
249 
250 #endif // vgl_cubic_spline_2d_h_
void knot_indices(Type t, unsigned &im1, unsigned &i0, unsigned &i1, unsigned &i2, Type &u) const
the indices for the knots bounding the interval containing t, u is the local parameter in the interva...
a point in 2D nonhomogeneous space
vgl_cubic_spline_2d(std::vector< vgl_point_2d< Type > > knots, Type s=Type(0.5), bool closed=false)
Construct from set of knots.
std::vector< vgl_point_2d< Type > > knots() const
bool operator!=(vgl_cubic_spline_2d< Type >const &spl) const
void set_knots(std::vector< vgl_point_2d< Type > > const &knots, bool closed)
vgl_cubic_spline_2d()
Default constructor - does not initialise!.
double length() const
Return the length of this vector.
std::ostream & operator<<(std::ostream &s, vgl_orient_box_3d< Type > const &p)
Write box to stream.
void coefficients(Type vm1, Type v0, Type v1, Type v2, Type &a0, Type &a1, Type &a2, Type &a3) const
The next two accessors are useful for interpolating other quantities than position with the same spat...
vgl_point_2d< Type > operator()(Type t) const
function value at t, where 0 <= t <= n-1 and n is the number of knots.
bool operator==(const vgl_cubic_spline_2d< Type > &spl) const
Equality operator.
bool closed() const
accessors.
void set(Type px, Type py)
Set x and y.
Definition: vgl_point_2d.h:79
Type & y()
Definition: vgl_point_2d.h:72
vgl_vector_2d< Type > tangent(Type t) const
direction vector in Euclidean 2D space
std::vector< vgl_point_2d< Type > > knots_
std::istream & operator>>(std::istream &is, vgl_orient_box_3d< Type > &p)
Read box from stream.
Represents a cartesian 2D point.
Definition: vgl_area.h:7
Type max_t() const
maximum value of the spline parameter.
Type & x()
Definition: vgl_point_2d.h:71