vgl_cubic_spline_3d.h
Go to the documentation of this file.
1 // This is core/vgl/vgl_cubic_spline_3d.h
2 #ifndef vgl_cubic_spline_3d_h_
3 #define vgl_cubic_spline_3d_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 August 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 any segment 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 
23 #include <iostream>
24 #include <utility>
25 #include <vector>
26 #include <cassert>
27 #ifdef _MSC_VER
28 # include <vcl_msvc_warnings.h>
29 #endif
30 #include <vgl/vgl_plane_3d.h>
31 #include <vgl/vgl_point_3d.h>
32 #include <vgl/vgl_vector_3d.h>
33 
34 template <class Type>
36 {
37  //: members
38  bool closed_curve_; // is the curve closed?
39  Type s_; // the parameter defining the first derivative at knots
40  std::vector<vgl_point_3d<Type> > knots_; // the spline knots
41 
42  public:
43  //: Default constructor
44  vgl_cubic_spline_3d(): closed_curve_(false), s_(Type(0.5)) {}
45 
46  //: Construct from set of knots
48  Type s = Type(0.5),
49  bool closed = false)
50  : closed_curve_(closed), s_(s), knots_(std::move(knots)){}
51 
52  //: accessors
53  bool closed() const {return closed_curve_;}
54  Type s() const {return s_;}
55  unsigned n_knots() const {return static_cast<unsigned>(knots_.size());}
56 
57  std::vector<vgl_point_3d<Type> > knots() const {return knots_;}
58  std::vector<vgl_point_3d<Type> > const & const_knots() const {return knots_;}
59 
60  void set_knots(std::vector<vgl_point_3d<Type> > const& knots, bool closed)
62  void set_s(Type s){s_ = s;}
63 
64 
65  //: maximum value of the spline parameter
66  Type max_t() const {return static_cast<Type>(knots_.size()-1);}
67 
68  //: Equality operator
69  bool operator==(const vgl_cubic_spline_3d<Type> &spl) const;
70 
71  bool operator!=(vgl_cubic_spline_3d<Type>const& spl) const { return !operator==(spl); }
72 
73  //: The next two accessors are useful for interpolating other quantities than position with the same spatial spline, e.g. a vector field
74  // see the implementation of the () operator as an example of their use
75 
76  //: interpolating function (Catmull-Rom). V is the value to be interpolated, specified at four points
77  // A is the resulting set of cubic coefficients, i.e., v(t) = a3 t^3 + a2 t^2 + a1 t + a0.
78  // the interval being interpolated is from v0 to v1
79  void coefficients(Type vm1, Type v0, Type v1, Type v2, Type& a0, Type& a1, Type& a2, Type& a3) const;
80 
81  //: the indices for the knots bounding the interval containing t, u is the local parameter in the interval 0 -> 1
82  void knot_indices(Type t, unsigned& im1, unsigned& i0, unsigned& i1, unsigned& i2, Type& u) const;
83 
84  //: function value at t, where 0 <= t < n-1 and n is the number of knots
85  vgl_point_3d<Type> operator ()(Type t) const;
86 
87  //: tangent to the curve at parameter t
88  vgl_vector_3d<Type> tangent(Type t) const;
89 
90  //: normal plane to the curve at parameter t
92  vgl_point_3d<Type> p = (*this)(t);
93  vgl_vector_3d<Type> n = this->tangent(t);
94  return vgl_plane_3d<Type>(n,p);
95  }
96 };
97 // ================= methods and public functions ===================
98 template <class Type>
99 void vgl_cubic_spline_3d<Type>::coefficients(Type vm1, Type v0, Type v1, Type v2,
100  Type& a0, Type& a1, Type& a2, Type& a3) const{
101  a3= (2-s_)*v0+(s_-2)*v1-s_*vm1+s_*v2;
102  a2= (s_-3)*v0 + (3-2*s_)*v1 + 2*s_*vm1-s_*v2;
103  a1= -s_*vm1 + s_*v1;
104  a0= v0;
105 }
106 
107 template <class Type>
108 void vgl_cubic_spline_3d<Type>::knot_indices(Type t, unsigned& im1, unsigned& i0, unsigned& i1, unsigned& i2, Type& u) const{
109  unsigned offset = static_cast<unsigned>(t);
110  // bounding condition for the exact end of the curve
111  if(offset == (static_cast<unsigned>(knots_.size())-1))
112  offset--;
113  i0 = offset; i1 = offset+1;
114  // logic for selecting knots under various boundary conditions
115  // begining of the curve
116  if(offset == 0){
117  if(closed_curve_)
118  im1 = static_cast<unsigned>(knots_.size()-1);
119  else
120  im1 = i0;
121  }else
122  im1 = offset-1;
123  // end of the curve
124  if(offset == static_cast<unsigned>(knots_.size()-2)){
125  if(closed_curve_)
126  i2 = 0;
127  else
128  i2 = i1;
129  }else
130  i2 = offset+2;
131  // the value the parameter within the interval of interest (0<=u<=1)
132  u = t - static_cast<Type>(offset);
133 }
134 
135 template <class Type>
137  if(spl.closed()!=closed_curve_) return false;
138  if(spl.s()!=s_) return false;
139  std::vector<vgl_point_3d<Type> > knots = spl.knots();
140  unsigned n = static_cast<unsigned>(knots.size());
141  if(n!= static_cast<unsigned>(knots_.size())) return false;
142  for(unsigned i =0; i<n; ++i)
143  if(knots[i] != knots_[i])
144  return false;
145  return true;
146 }
147 template <class Type>
149  vgl_point_3d<Type> ret;
150  if(knots_.size() < 2)
151  return ret;
152  assert(t>=Type(0) && t<=max_t());
153  unsigned im1, i0, i1, i2;
154  Type u;
155  knot_indices(t, im1, i0, i1, i2, u);
156  vgl_point_3d<Type> pm1 = knots_[im1], p0 = knots_[i0];
157  vgl_point_3d<Type> p1 = knots_[i1], p2 = knots_[i2];
158  // monomials
159  Type u2 = u*u, u3 = u2*u;
160  // coefficients
161  Type a0x, a1x, a2x, a3x;
162  Type a0y, a1y, a2y, a3y;
163  Type a0z, a1z, a2z, a3z;
164  coefficients(pm1.x(), p0.x(), p1.x(), p2.x(), a0x, a1x, a2x, a3x);
165  coefficients(pm1.y(), p0.y(), p1.y(), p2.y(), a0y, a1y, a2y, a3y);
166  coefficients(pm1.z(), p0.z(), p1.z(), p2.z(), a0z, a1z, a2z, a3z);
167  // interpolate 3-d point on spline
168  Type x = a3x*u3 + a2x*u2 + a1x*u + a0x;
169  Type y = a3y*u3 + a2y*u2 + a1y*u + a0y;
170  Type z = a3z*u3 + a2z*u2 + a1z*u + a0z;
171  ret.set(x, y, z);
172  return ret;
173 }
174 
175 template <class Type>
177  Type zero = static_cast<Type>(0);
178  Type nm1 = max_t();
179  Type del = static_cast<Type>(0.01);
180  vgl_vector_3d<Type> tang;
181  Type tp, tm;
182  // non-boundary case
183  if(t>zero && t<nm1){
184  tm = t-del;
185  if(tm<zero) tm = t;
186  tp = t+del;
187  if(tp>nm1)
188  tp = nm1-t;
189  vgl_point_3d<Type> pm = (*this)(tm), pp = (*this)(tp);
190  tang = pp-pm;
191  }
192  // Case I t==0
193  if(t==zero){
194  tp = del;
195  if(closed_curve_)
196  tm = nm1-del;
197  else
198  tm = zero;
199  vgl_point_3d<Type> pm = (*this)(tm), pp = (*this)(tp);
200  tang = pp-pm;
201  }
202  if(t==nm1){
203  tm = nm1-del;
204  if(closed_curve_)
205  tp = del;
206  else
207  tp = nm1;
208  vgl_point_3d<Type> pm = (*this)(tm), pp = (*this)(tp);
209  tang = pp-pm;
210  }
211  tang/=tang.length();
212  return tang;
213 }
214 
215 
216 template <class Type>
217 std::ostream& operator<<(std::ostream& ostr, vgl_cubic_spline_3d<Type> const& spl){
218  if(!ostr){
219  std::cout << "Bad ostream in write vgl_cubic_spline_3d to stream\n";
220  return ostr;
221  }
222  int ic = 0;
223  if(spl.closed())
224  ic = 1;
225  Type s = spl.s();
226  ostr << ic << ' ' << s << '\n';
227  std::vector<vgl_point_3d<Type> > knots = spl.knots();
228  for(unsigned i =0; i<static_cast<unsigned>(knots.size()); i++){
229  const vgl_point_3d<Type>& p = knots[i];
230  ostr << p.x() << ',' << p.y() << ',' << p.z() << '\n';
231  }
232  return ostr;
233 }
234 
235 template <class Type>
236 std::istream& operator>>(std::istream& istr, vgl_cubic_spline_3d<Type>& spl){
237  if(!istr){
238  std::cout << "Bad istream in read vgl_cubic_spline_3d from stream\n";
239  return istr;
240  }
241  int ic;
242  Type s;
243  istr >> ic >> s;
244  bool closed = ic!=0;
245  Type x, y, z;
246  unsigned char c;
247  std::vector<vgl_point_3d<Type> > knots;
248  // this loop termination may look strange
249  // but testing the stream is more reliable
250  // then the state of istr.eof()
251  while(istr >> x >> c){
252  if(c!=','){
253  std::cout << "Bad file format\n";
254  return istr;
255  }
256 
257  istr >> y >> c;
258  if(c!=','){
259  std::cout << "Bad file format\n";
260  return istr;
261  }
262  istr >> z ;
263  vgl_point_3d<Type> p(x,y,z);
264  knots.push_back(p);
265  }
266  spl = vgl_cubic_spline_3d<Type>(knots, s , closed);
267  return istr;
268 };
269 
270 #endif // vgl_cubic_spline_3d_h_
Type max_t() const
maximum value of the spline parameter.
vgl_vector_3d< Type > tangent(Type t) const
tangent to the curve at parameter t.
std::vector< vgl_point_3d< Type > > const & const_knots() const
vgl_cubic_spline_3d()
Default constructor.
direction vector in Euclidean 3D space
Represents a cartesian 3D point.
Definition: vgl_fwd.h:11
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...
std::ostream & operator<<(std::ostream &s, vgl_orient_box_3d< Type > const &p)
Write box to stream.
vgl_point_3d< Type > operator()(Type t) const
function value at t, where 0 <= t < n-1 and n is the number of knots.
Type & z()
Definition: vgl_point_3d.h:73
bool operator==(const vgl_cubic_spline_3d< Type > &spl) const
Equality operator.
unsigned n_knots() const
a point in 3D nonhomogeneous space
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...
bool closed() const
accessors.
std::vector< vgl_point_3d< Type > > knots_
double length() const
Return the length of this vector.
Represents a Euclidean 3D plane.
Definition: vgl_fwd.h:23
std::vector< vgl_point_3d< Type > > knots() const
Type & x()
Definition: vgl_point_3d.h:71
std::istream & operator>>(std::istream &is, vgl_orient_box_3d< Type > &p)
Read box from stream.
vgl_cubic_spline_3d(std::vector< vgl_point_3d< Type > > knots, Type s=Type(0.5), bool closed=false)
Construct from set of knots.
void set(Type px, Type py, Type pz)
Set x, y and z.
Definition: vgl_point_3d.h:81
a plane in 3D nonhomogeneous space
vgl_plane_3d< Type > normal_plane(Type t)
normal plane to the curve at parameter t.
bool operator!=(vgl_cubic_spline_3d< Type >const &spl) const
Type & y()
Definition: vgl_point_3d.h:72
void set_knots(std::vector< vgl_point_3d< Type > > const &knots, bool closed)