1 /*============================================================================
3 The Medical Imaging Interaction Toolkit (MITK)
5 Copyright (c) German Cancer Research Center (DKFZ)
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
11 ============================================================================*/
13 /*===================================================================
15 This file is based heavily on a corresponding ITK filter.
17 ===================================================================*/
19 /*********************************
20 This file was taken from ITK, CVS version 1.13 to circumvent a bug in ITK release 3.18 (see http://public.kitware.com/Bug/view.php?id=10633
21 *********************************/
23 #ifndef __itkNonUniformBSpline_txx
24 #define __itkNonUniformBSpline_txx
27 #pragma warning ( disable : 4786 )
30 #include "mitkItkNonUniformBSpline.h"
32 #include "vnl/vnl_vector.h"
33 #include "vnl/vnl_matrix.h"
34 #include "vnl/algo/vnl_lsqr.h"
35 #include "vnl/vnl_linear_system.h"
38 // #define DEBUG_SPLINE
44 template< unsigned int TDimension >
45 NonUniformBSpline< TDimension >
48 // Cubic bspline => 4th order
50 m_SpatialDimension = TDimension;
54 template< unsigned int TDimension >
55 NonUniformBSpline< TDimension >
56 ::~NonUniformBSpline()
60 /** Print the object */
61 template< unsigned int TDimension >
63 NonUniformBSpline< TDimension >
64 ::PrintSelf( std::ostream& os, Indent indent ) const
66 Superclass::PrintSelf( os, indent );
67 os << indent << "NonUniformBSpline(" << this << ")" << std::endl;
69 os << indent << "Chord lengths : " << std::endl;
70 for (ChordLengthListType::const_iterator iter = m_CumulativeChordLength.begin();
71 iter != m_CumulativeChordLength.end();
74 os << indent << indent << *iter << std::endl;
76 os << indent << "Knots : " << std::endl;
77 for (KnotListType::const_iterator kiter = m_Knots.begin();
78 kiter != m_Knots.end();
81 os << indent << indent << *kiter << std::endl;
83 os << indent << "Control Points : " << std::endl;
84 for (typename ControlPointListType::const_iterator cpiter = m_ControlPoints.begin();
85 cpiter != m_ControlPoints.end();
88 os << indent << indent << *cpiter << std::endl;
93 /** Set the list of points composing the tube */
94 template< unsigned int TDimension >
96 NonUniformBSpline< TDimension >
97 ::SetPoints( PointListType & points )
101 typename PointListType::iterator it,end;
106 m_Points.push_back(*it);
113 /** Set the list of points composing the tube */
114 template< unsigned int TDimension >
116 NonUniformBSpline< TDimension >
117 ::SetKnots( KnotListType & knots )
121 int len = knots.size();
122 double max_knot = knots[len - 1];
124 typename KnotListType::iterator it;
125 typename KnotListType::iterator end;
132 m_Knots.push_back(*it/max_knot);
139 template< unsigned int TDimension >
141 NonUniformBSpline< TDimension >
142 ::NonUniformBSplineFunctionRecursive(unsigned int order, unsigned int i, double t) const
146 if (m_Knots[i] <= t && t < m_Knots[i+1])
157 // Be careful, we must use the passed in parameter for the order since this
158 // function is recursive.
160 double numer1 = (t - m_Knots[i]) * NonUniformBSplineFunctionRecursive(order-1, i, t);
161 double denom1 = (m_Knots[i+order-1] - m_Knots[i]);
162 double val1 = numer1 / denom1;
163 if (denom1 == 0 && numer1 == 0)
165 else if (denom1 == 0)
166 std::cout << "Error : " << denom1 << ", " << numer1 << std::endl;
168 double numer2 = (m_Knots[i+order] - t) * NonUniformBSplineFunctionRecursive(order-1, i+1, t);
169 double denom2 = (m_Knots[i + order] - m_Knots[i+1]);
170 double val2 = numer2 / denom2;
171 if (denom2 == 0 && numer2 == 0)
173 else if (denom2 == 0)
174 std::cout << "Error : " << denom2 << ", " << numer2 << std::endl;
179 template< unsigned int TDimension >
181 NonUniformBSpline< TDimension >
182 ::ComputeChordLengths()
184 m_ChordLength.clear();
185 m_CumulativeChordLength.clear();
187 m_ChordLength.push_back(0);
188 m_CumulativeChordLength.push_back(0);
190 double total_chord_length = 0.0;
191 ChordLengthListType temp;
193 for (::size_t i = 0; i < m_Points.size()-1; i++)
195 PointType pt = m_Points[i];
196 PointType pt2 = m_Points[i+1];
198 double chord = pt.EuclideanDistanceTo(pt2);
199 m_ChordLength.push_back(chord);
200 total_chord_length = total_chord_length + chord;
201 temp.push_back(total_chord_length);
204 for (ChordLengthListType::iterator aiter = temp.begin();
208 m_CumulativeChordLength.push_back(*aiter/total_chord_length);
215 std::cout << "Total chord length : " << total_chord_length << std::endl;
217 std::cout << "Chord length : " << std::endl;
218 for (ChordLengthListType::iterator aiter2 = m_ChordLength.begin();
219 aiter2 != m_ChordLength.end();
222 std::cout << *aiter2 << std::endl;
225 std::cout << "Cumulative chord length : " << std::endl;
226 for (ChordLengthListType::iterator aiter3 = m_CumulativeChordLength.begin();
227 aiter3 != m_CumulativeChordLength.end();
230 std::cout << *aiter3 << std::endl;
232 std::cout << std::endl;
236 template< unsigned int TDimension >
238 NonUniformBSpline< TDimension >
239 ::SetControlPoints( ControlPointListType& ctrlpts )
241 m_ControlPoints.clear();
242 for (typename ControlPointListType::iterator iter = ctrlpts.begin();
243 iter != ctrlpts.end();
246 m_ControlPoints.push_back(*iter);
252 template< unsigned int TDimension >
254 NonUniformBSpline< TDimension >::ControlPointListType &
255 NonUniformBSpline< TDimension >::GetControlPoints() const
257 return this->m_ControlPoints;
261 template< unsigned int TDimension >
263 NonUniformBSpline< TDimension >::KnotListType &
264 NonUniformBSpline< TDimension >::GetKnots() const
266 return this->m_Knots;
270 template< unsigned int TDimension >
272 NonUniformBSpline< TDimension >::PointListType &
273 NonUniformBSpline< TDimension >::GetPoints() const
275 return this->m_Points;
279 template< unsigned int TDimension >
281 NonUniformBSpline< TDimension >::ComputeControlPoints()
283 unsigned int dim = m_Points[0].GetPointDimension();
286 std::cout << "Points have dimension : " << dim << std::endl;
290 // +1 in cols for radius
292 vnl_matrix<double> data_matrix(m_Points.size(), dim);
295 // Form data point matrix
298 for (typename PointListType::iterator iter = m_Points.begin();
299 iter != m_Points.end();
302 PointType pt = (*iter);
303 for (unsigned int i = 0; i < dim; i++)
305 data_matrix(rr, i) = pt.GetVnlVector()[i];
311 std::cout << std::endl << "Data matrix" << std::endl;
312 std::cout << data_matrix << std::endl;
316 // Form basis function matrix
318 //int num_basis_functions = 2 * m_SplineOrder - 1;
319 //int num_basis_functions = m_Points.size();
320 int num_rows = m_Points.size();
323 // Assumes multiplicity k (m_SplineOrder at the ends).
325 int num_cols = m_Knots.size() - m_SplineOrder;
327 vnl_matrix<double> N_matrix(num_rows, num_cols);
329 //N_matrix(0, 0) = 1.0;
331 for (int r = 0; r < num_rows; r++)
333 for (int c = 0; c < num_cols; c++)
335 double t = m_CumulativeChordLength[r];
336 N_matrix(r, c) = NonUniformBSplineFunctionRecursive(m_SplineOrder, c, t);
340 N_matrix(num_rows-1, num_cols-1) = 1.0;
343 std::cout << "Basis function matrix : " << std::endl;
344 std::cout << N_matrix << std::endl;
347 //FIXME: Use the LSQR linear solver here:
348 vnl_matrix<double> B;
350 // = vnl_matrix_inverse<double>(N_matrix.transpose() * N_matrix) * N_matrix.transpose() * data_matrix;
352 // vnl_linear_system ls( N_matrix.rows(), N_matrix.cols() );
354 // vnl_lsqr solver( ls );
357 //#ifdef DEBUG_SPLINE
358 std::cout << "Control point matrix : " << std::endl;
359 std::cout << B << std::endl;
362 m_ControlPoints.clear();
364 for ( unsigned int j = 0; j < B.rows(); j++ )
366 vnl_vector<double> v = B.get_row(j);
367 itk::Vector<double> iv;
369 itk::Point<double, TDimension> pt;
370 for ( unsigned int d = 0; d < dim; d++ )
374 m_ControlPoints.push_back(pt);
379 template< unsigned int TDimension >
380 typename NonUniformBSpline<TDimension>::PointType
381 NonUniformBSpline< TDimension >
382 ::EvaluateSpline(const itk::Array<double> & p) const
386 return EvaluateSpline(t);
389 template< unsigned int TDimension >
390 typename NonUniformBSpline<TDimension>::PointType
391 NonUniformBSpline< TDimension >
392 ::EvaluateSpline(double t) const
396 vnl_vector<double> result(TDimension);
399 for (typename ControlPointListType::const_iterator cpiter = m_ControlPoints.begin();
400 cpiter != m_ControlPoints.end();
403 ControlPointType pt = *cpiter;
404 vnl_vector<double> v = pt.GetVnlVector();
406 const double N = this->NonUniformBSplineFunctionRecursive(m_SplineOrder, i, t);
408 for( unsigned j = 0; j < TDimension; j++ )
410 result[j] += N * v[j];
416 double array[TDimension];
417 for ( unsigned int d = 0; d < TDimension; d++ )
419 array[d] = result[d];
422 ControlPointType sum(array);
424 std::cout << "Result : " << result << std::endl;
425 std::cout << "Sum : " << sum << std::endl;
431 } // end namespace itk