| // This file is part of Eigen, a lightweight C++ template library | 
 | // for linear algebra. | 
 | // | 
 | // Copyright (C) 2010-2011 Hauke Heibel <heibel@gmail.com> | 
 | // | 
 | // This Source Code Form is subject to the terms of the Mozilla | 
 | // Public License v. 2.0. If a copy of the MPL was not distributed | 
 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. | 
 |  | 
 | #include "main.h" | 
 |  | 
 | #include <unsupported/Eigen/Splines> | 
 |  | 
 | namespace Eigen { | 
 |    | 
 |   // lets do some explicit instantiations and thus | 
 |   // force the compilation of all spline functions... | 
 |   template class Spline<double, 2, Dynamic>; | 
 |   template class Spline<double, 3, Dynamic>; | 
 |  | 
 |   template class Spline<double, 2, 2>; | 
 |   template class Spline<double, 2, 3>; | 
 |   template class Spline<double, 2, 4>; | 
 |   template class Spline<double, 2, 5>; | 
 |  | 
 |   template class Spline<float, 2, Dynamic>; | 
 |   template class Spline<float, 3, Dynamic>; | 
 |  | 
 |   template class Spline<float, 3, 2>; | 
 |   template class Spline<float, 3, 3>; | 
 |   template class Spline<float, 3, 4>; | 
 |   template class Spline<float, 3, 5>; | 
 |  | 
 | } | 
 |  | 
 | Spline<double, 2, Dynamic> closed_spline2d() | 
 | { | 
 |   RowVectorXd knots(12); | 
 |   knots << 0, | 
 |     0, | 
 |     0, | 
 |     0, | 
 |     0.867193179093898, | 
 |     1.660330955342408, | 
 |     2.605084834823134, | 
 |     3.484154586374428, | 
 |     4.252699478956276, | 
 |     4.252699478956276, | 
 |     4.252699478956276, | 
 |     4.252699478956276; | 
 |  | 
 |   MatrixXd ctrls(8,2); | 
 |   ctrls << -0.370967741935484,   0.236842105263158, | 
 |     -0.231401860693277,   0.442245185027632, | 
 |     0.344361228532831,   0.773369994120753, | 
 |     0.828990216203802,   0.106550882647595, | 
 |     0.407270163678382,  -1.043452922172848, | 
 |     -0.488467813584053,  -0.390098582530090, | 
 |     -0.494657189446427,   0.054804824897884, | 
 |     -0.370967741935484,   0.236842105263158; | 
 |   ctrls.transposeInPlace(); | 
 |  | 
 |   return Spline<double, 2, Dynamic>(knots, ctrls); | 
 | } | 
 |  | 
 | /* create a reference spline */ | 
 | Spline<double, 3, Dynamic> spline3d() | 
 | { | 
 |   RowVectorXd knots(11); | 
 |   knots << 0, | 
 |     0, | 
 |     0, | 
 |     0.118997681558377, | 
 |     0.162611735194631, | 
 |     0.498364051982143, | 
 |     0.655098003973841, | 
 |     0.679702676853675, | 
 |     1.000000000000000, | 
 |     1.000000000000000, | 
 |     1.000000000000000; | 
 |  | 
 |   MatrixXd ctrls(8,3); | 
 |   ctrls <<    0.959743958516081,   0.340385726666133,   0.585267750979777, | 
 |     0.223811939491137,   0.751267059305653,   0.255095115459269, | 
 |     0.505957051665142,   0.699076722656686,   0.890903252535799, | 
 |     0.959291425205444,   0.547215529963803,   0.138624442828679, | 
 |     0.149294005559057,   0.257508254123736,   0.840717255983663, | 
 |     0.254282178971531,   0.814284826068816,   0.243524968724989, | 
 |     0.929263623187228,   0.349983765984809,   0.196595250431208, | 
 |     0.251083857976031,   0.616044676146639,   0.473288848902729; | 
 |   ctrls.transposeInPlace(); | 
 |  | 
 |   return Spline<double, 3, Dynamic>(knots, ctrls); | 
 | } | 
 |  | 
 | /* compares evaluations against known results */ | 
 | void eval_spline3d() | 
 | { | 
 |   Spline3d spline = spline3d(); | 
 |  | 
 |   RowVectorXd u(10); | 
 |   u << 0.351659507062997, | 
 |     0.830828627896291, | 
 |     0.585264091152724, | 
 |     0.549723608291140, | 
 |     0.917193663829810, | 
 |     0.285839018820374, | 
 |     0.757200229110721, | 
 |     0.753729094278495, | 
 |     0.380445846975357, | 
 |     0.567821640725221; | 
 |  | 
 |   MatrixXd pts(10,3); | 
 |   pts << 0.707620811535916,   0.510258911240815,   0.417485437023409, | 
 |     0.603422256426978,   0.529498282727551,   0.270351549348981, | 
 |     0.228364197569334,   0.423745615677815,   0.637687289287490, | 
 |     0.275556796335168,   0.350856706427970,   0.684295784598905, | 
 |     0.514519311047655,   0.525077224890754,   0.351628308305896, | 
 |     0.724152914315666,   0.574461155457304,   0.469860285484058, | 
 |     0.529365063753288,   0.613328702656816,   0.237837040141739, | 
 |     0.522469395136878,   0.619099658652895,   0.237139665242069, | 
 |     0.677357023849552,   0.480655768435853,   0.422227610314397, | 
 |     0.247046593173758,   0.380604672404750,   0.670065791405019; | 
 |   pts.transposeInPlace(); | 
 |  | 
 |   for (int i=0; i<u.size(); ++i) | 
 |   { | 
 |     Vector3d pt = spline(u(i)); | 
 |     VERIFY( (pt - pts.col(i)).norm() < 1e-14 ); | 
 |   } | 
 | } | 
 |  | 
 | /* compares evaluations on corner cases */ | 
 | void eval_spline3d_onbrks() | 
 | { | 
 |   Spline3d spline = spline3d(); | 
 |  | 
 |   RowVectorXd u = spline.knots(); | 
 |  | 
 |   MatrixXd pts(11,3); | 
 |   pts <<    0.959743958516081,   0.340385726666133,   0.585267750979777, | 
 |     0.959743958516081,   0.340385726666133,   0.585267750979777, | 
 |     0.959743958516081,   0.340385726666133,   0.585267750979777, | 
 |     0.430282980289940,   0.713074680056118,   0.720373307943349, | 
 |     0.558074875553060,   0.681617921034459,   0.804417124839942, | 
 |     0.407076008291750,   0.349707710518163,   0.617275937419545, | 
 |     0.240037008286602,   0.738739390398014,   0.324554153129411, | 
 |     0.302434111480572,   0.781162443963899,   0.240177089094644, | 
 |     0.251083857976031,   0.616044676146639,   0.473288848902729, | 
 |     0.251083857976031,   0.616044676146639,   0.473288848902729, | 
 |     0.251083857976031,   0.616044676146639,   0.473288848902729; | 
 |   pts.transposeInPlace(); | 
 |  | 
 |   for (int i=0; i<u.size(); ++i) | 
 |   { | 
 |     Vector3d pt = spline(u(i)); | 
 |     VERIFY( (pt - pts.col(i)).norm() < 1e-14 ); | 
 |   } | 
 | } | 
 |  | 
 | void eval_closed_spline2d() | 
 | { | 
 |   Spline2d spline = closed_spline2d(); | 
 |  | 
 |   RowVectorXd u(12); | 
 |   u << 0, | 
 |     0.332457030395796, | 
 |     0.356467130532952, | 
 |     0.453562180176215, | 
 |     0.648017921874804, | 
 |     0.973770235555003, | 
 |     1.882577647219307, | 
 |     2.289408593930498, | 
 |     3.511951429883045, | 
 |     3.884149321369450, | 
 |     4.236261590369414, | 
 |     4.252699478956276; | 
 |  | 
 |   MatrixXd pts(12,2); | 
 |   pts << -0.370967741935484,   0.236842105263158, | 
 |     -0.152576775123250,   0.448975001279334, | 
 |     -0.133417538277668,   0.461615613865667, | 
 |     -0.053199060826740,   0.507630360006299, | 
 |     0.114249591147281,   0.570414135097409, | 
 |     0.377810316891987,   0.560497102875315, | 
 |     0.665052120135908,  -0.157557441109611, | 
 |     0.516006487053228,  -0.559763292174825, | 
 |     -0.379486035348887,  -0.331959640488223, | 
 |     -0.462034726249078,  -0.039105670080824, | 
 |     -0.378730600917982,   0.225127015099919, | 
 |     -0.370967741935484,   0.236842105263158; | 
 |   pts.transposeInPlace(); | 
 |  | 
 |   for (int i=0; i<u.size(); ++i) | 
 |   { | 
 |     Vector2d pt = spline(u(i)); | 
 |     VERIFY( (pt - pts.col(i)).norm() < 1e-14 ); | 
 |   } | 
 | } | 
 |  | 
 | void check_global_interpolation2d() | 
 | { | 
 |   typedef Spline2d::PointType PointType; | 
 |   typedef Spline2d::KnotVectorType KnotVectorType; | 
 |   typedef Spline2d::ControlPointVectorType ControlPointVectorType; | 
 |  | 
 |   ControlPointVectorType points = ControlPointVectorType::Random(2,100); | 
 |  | 
 |   KnotVectorType chord_lengths; // knot parameters | 
 |   Eigen::ChordLengths(points, chord_lengths); | 
 |  | 
 |   // interpolation without knot parameters | 
 |   { | 
 |     const Spline2d spline = SplineFitting<Spline2d>::Interpolate(points,3);   | 
 |  | 
 |     for (Eigen::DenseIndex i=0; i<points.cols(); ++i) | 
 |     { | 
 |       PointType pt = spline( chord_lengths(i) ); | 
 |       PointType ref = points.col(i); | 
 |       VERIFY( (pt - ref).matrix().norm() < 1e-14 ); | 
 |     } | 
 |   } | 
 |  | 
 |   // interpolation with given knot parameters | 
 |   { | 
 |     const Spline2d spline = SplineFitting<Spline2d>::Interpolate(points,3,chord_lengths);   | 
 |  | 
 |     for (Eigen::DenseIndex i=0; i<points.cols(); ++i) | 
 |     { | 
 |       PointType pt = spline( chord_lengths(i) ); | 
 |       PointType ref = points.col(i); | 
 |       VERIFY( (pt - ref).matrix().norm() < 1e-14 ); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void check_global_interpolation_with_derivatives2d() | 
 | { | 
 |   typedef Spline2d::PointType PointType; | 
 |   typedef Spline2d::KnotVectorType KnotVectorType; | 
 |  | 
 |   const Eigen::DenseIndex numPoints = 100; | 
 |   const unsigned int dimension = 2; | 
 |   const unsigned int degree = 3; | 
 |  | 
 |   ArrayXXd points = ArrayXXd::Random(dimension, numPoints); | 
 |  | 
 |   KnotVectorType knots; | 
 |   Eigen::ChordLengths(points, knots); | 
 |  | 
 |   ArrayXXd derivatives = ArrayXXd::Random(dimension, numPoints); | 
 |   VectorXd derivativeIndices(numPoints); | 
 |  | 
 |   for (Eigen::DenseIndex i = 0; i < numPoints; ++i) | 
 |       derivativeIndices(i) = static_cast<double>(i); | 
 |  | 
 |   const Spline2d spline = SplineFitting<Spline2d>::InterpolateWithDerivatives( | 
 |     points, derivatives, derivativeIndices, degree);   | 
 |      | 
 |   for (Eigen::DenseIndex i = 0; i < points.cols(); ++i) | 
 |   { | 
 |     PointType point = spline(knots(i)); | 
 |     PointType referencePoint = points.col(i); | 
 |     VERIFY_IS_APPROX(point, referencePoint); | 
 |     PointType derivative = spline.derivatives(knots(i), 1).col(1); | 
 |     PointType referenceDerivative = derivatives.col(i); | 
 |     VERIFY_IS_APPROX(derivative, referenceDerivative); | 
 |   } | 
 | } | 
 |  | 
 | EIGEN_DECLARE_TEST(splines) | 
 | { | 
 |   for (int i = 0; i < g_repeat; ++i) | 
 |   { | 
 |     CALL_SUBTEST( eval_spline3d() ); | 
 |     CALL_SUBTEST( eval_spline3d_onbrks() ); | 
 |     CALL_SUBTEST( eval_closed_spline2d() ); | 
 |     CALL_SUBTEST( check_global_interpolation2d() ); | 
 |     CALL_SUBTEST( check_global_interpolation_with_derivatives2d() ); | 
 |   } | 
 | } |