ETL  0.04.19
_bspline.h
Go to the documentation of this file.
1 
26 /* === S T A R T =========================================================== */
27 
28 #ifndef __ETL__BSPLINE_H
29 #define __ETL__BSPLINE_H
30 
31 /* === H E A D E R S ======================================================= */
32 
33 #include <vector>
34 #include <functional>
35 #include "_curve_func.h"
36 
37 /* === M A C R O S ========================================================= */
38 
39 /* === T Y P E D E F S ===================================================== */
40 
41 /* === C L A S S E S & S T R U C T S ======================================= */
42 
44 
45 template <class T, class K=float, class C=affine_combo<T,K>, class D=distance_func<T> >
46 class bspline : public std::unary_function<K,T>
47 {
48 public:
49  typedef T value_type;
50  typedef K knot_type;
51  typedef std::vector<knot_type> knot_container;
52  typedef std::vector<value_type> cpoint_container;
53  typedef typename knot_container::iterator knot_iterator;
54  typedef typename cpoint_container::iterator cpoint_iterator;
55 
56  typedef C affine_func_type;
57  typedef D distance_func_type;
58 
59 protected:
62 
63 private:
64  int m;
67  bool _loop;
68 
69 public:
70  bspline():m(2),_loop(false) { }
71 
72  int get_m()const { return m-1; };
73  int set_m(int new_m) { m=new_m+1; return m-1; };
74 
75  bool set_loop(bool x) { _loop=x; reset_knots(); return _loop; }
76 
77  knot_container & knots() { return _knots; };
79 
80  const knot_container & knots()const { return _knots; };
81  const cpoint_container & cpoints()const { return _cpoints; };
82 
83  void reset_knots()
84  {
85  int i;
86 
87  if(!_loop)
88  {
89  _knots.clear();
90  if(!_cpoints.size())
91  return;
92  while(m>(signed)_cpoints.size())
93  m--;
94  for(i=0;i<m;i++)
95  _knots.insert(_knots.end(), 0);
96  for(i=1;i<(signed)_cpoints.size()-m+1;i++)
97  _knots.insert(_knots.end(), i);
98  for(i=0;i<m;i++)
99  _knots.insert(_knots.end(), _cpoints.size()-m+1);
100  }
101  else
102  {
103  _knots.clear();
104  if(!_cpoints.size())
105  return;
106  while(m>(signed)_cpoints.size())
107  m--;
108  for(i=0;i<=(signed)_cpoints.size()-m+1;i++)
109  _knots.insert(_knots.end(), i);
110  }
111  }
112 
114  {
115  int k;
116  if(t<0)
117  t=0;
118  if(t>=_knots.back())
119  t=_knots.back()-0.0001;
120  for(k=0;_knots[k]>t || _knots[k+1]<=t;k++)
121  ;
122 
123  return k;
124  }
125 
127  {
128  if(i+1<m)
129  {
130  knot_container ret(_knots.begin(),_knots.begin()+i+m+1);
131 
132  return ret;
133  }
134  if(i+1>=(signed)_knots.size())
135  {
136  knot_container ret(_knots.begin()+i-m+1,_knots.end());
137  return ret;
138  }
139  return knot_container(_knots.begin()+i-m+1, _knots.begin()+i+m);
140  }
141 
143  {
144  if(i+1<m)
145  {
146  return cpoint_container();
147  }
148  if(i+1>=(signed)_knots.size())
149  {
150  return cpoint_container();
151  }
152  return cpoint_container(_cpoints.begin()+i-m+1, _cpoints.begin()+i+1);
153  }
154 
156  {
157  int
158  i=calc_curve_segment(t),
159  j,k;
160 
162 
164 
165  if(!d.size())
166  return cpoint_container();
167 
168  for(j=0;d.size()>1 && j<level;d.pop_back(),j++)
169  {
170  for(k=0;k<d.size()-1;k++)
171  {
172  d[k]=affine_func(d[k],d[k+1],((t-u[j+k+1])/(u[m+k]-u[j+k+1])));
173  }
174  }
175  return d;
176  }
177 
179  {
180  return get_curve_val(calc_curve_segment(t),t);
181  }
182 
184  {
185  int
186  j,k;
187 
189 
191 
192  if(!d.size())
193  return value_type();
194 
195  for(j=0;d.size()>1;d.pop_back(),j++)
196  {
197  for(k=0;k<(signed)d.size()-1;k++)
198  {
199  d[k]=affine_func(d[k],d[k+1],((t-u[j+k+1])/(u[m+k]-u[j+k+1])));
200  }
201  }
202  return d.front();
203  }
204 
205  cpoint_iterator find_closest_cpoint(const value_type &point, typename distance_func_type::result_type max)
206  {
207  cpoint_iterator i=_cpoints.begin();
208  cpoint_iterator ret=i;
209  typename distance_func_type::result_type dist=distance_func(point,_cpoints[0]);
210 
211  // The distance function returns "cooked" (ie: squared)
212  // distances, so we need to cook our max distance for
213  // the comparison to work correctly.
214  max=distance_func.cook(max);
215 
216  for(++i;i<_cpoints.end();i++)
217  {
218  typename distance_func_type::result_type thisdist=distance_func(point,*i);
219 
220  if(thisdist<dist)
221  {
222  dist=thisdist;
223  ret=i;
224  }
225  }
226  if(dist<max)
227  return ret;
228  return _cpoints.end();
229  }
230 };
231 
233 
234 /* -- F U N C T I O N S ----------------------------------------------------- */
235 
236 /* -- E N D ----------------------------------------------------------------- */
237 
238 #endif