• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List

rotation.hh

00001 // Copyright (C) 2007, 2008, 2009, 2010 EPITA Research and Development
00002 // Laboratory (LRDE)
00003 //
00004 // This file is part of Olena.
00005 //
00006 // Olena is free software: you can redistribute it and/or modify it under
00007 // the terms of the GNU General Public License as published by the Free
00008 // Software Foundation, version 2 of the License.
00009 //
00010 // Olena is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with Olena.  If not, see <http://www.gnu.org/licenses/>.
00017 //
00018 // As a special exception, you may use this file as part of a free
00019 // software project without restriction.  Specifically, if other files
00020 // instantiate templates or use macros or inline functions from this
00021 // file, or you compile this file and link it with other files to produce
00022 // an executable, this file does not by itself cause the resulting
00023 // executable to be covered by the GNU General Public License.  This
00024 // exception does not however invalidate any other reasons why the
00025 // executable file might be covered by the GNU General Public License.
00026 
00027 #ifndef MLN_FUN_X2X_ROTATION_HH
00028 # define MLN_FUN_X2X_ROTATION_HH
00029 
00039 
00040 # include <cstdlib>
00041 # include <cmath>
00042 
00043 # include <mln/core/concept/function.hh>
00044 # include <mln/fun/internal/x2x_linear_impl.hh>
00045 # include <mln/algebra/vec.hh>
00046 # include <mln/algebra/mat.hh>
00047 # include <mln/algebra/quat.hh>
00048 # include <mln/make/h_mat.hh>
00049 
00050 # include <mln/norm/l2.hh>
00051 
00052 
00053 namespace mln
00054 {
00055 
00056   namespace fun
00057   {
00058 
00059     namespace x2x
00060     {
00061 
00062       namespace internal
00063       {
00064         // (Axis, angle)-based rotation: general case (not implemented).
00065         template < unsigned n, typename C >
00066         algebra::h_mat<n, C>
00067         get_rot_h_mat(const C alpha_, const algebra::vec<n,C>& axis_)
00068         {
00069           std::cerr
00070             << __FILE__ << ":" << __LINE__ << ": error:"
00071             << " generic mln::fun::x2x::internal::get_rot_h_mat<n, C>"
00072             << " not implemented."
00073             << std::endl;
00074           std::abort();
00075         }
00076 
00077         // (Axis, angle)-based rotation: 2D case.
00078         template <typename C >
00079         algebra::h_mat<2, C>
00080         get_rot_h_mat(const C alpha, const algebra::vec<2,C>&)
00081         {
00082           const C cos_a = cos(alpha);
00083           const C sin_a = sin(alpha);
00084 
00085           algebra::h_mat<2, C> m;
00086 
00087           m(0,0) = cos_a; m(0,1) = -sin_a; m(0,2) = 0;
00088           m(1,0) = sin_a; m(1,1) = cos_a;  m(1,2) = 0;
00089           m(2,0) = 0;     m(2,1) = 0;      m(2,2) = 1;
00090 
00091           return m;
00092         }
00093 
00094         // (Axis, angle)-based rotation: 3D case.
00095         template <typename C >
00096         algebra::h_mat<3, C>
00097         get_rot_h_mat(const C alpha, const algebra::vec<3,C>& axis)
00098         {
00099           // Ensure axis is valid.
00100           typedef algebra::vec<3,C> vec_t;
00101           // FIXME: This check is not precise enought when the vector
00102           // holds floating point values.
00103           mln_precondition(axis != vec_t(literal::zero));
00104 
00105           algebra::vec<3,C> normed_axis = axis;
00106           normed_axis.normalize();
00107 
00108           const C cos_a = cos(alpha);
00109           const C sin_a = sin(alpha);
00110           const C u = normed_axis[0];
00111           const C v = normed_axis[1];
00112           const C w = normed_axis[2];
00113           const C u2 = u * u;
00114           const C v2 = v * v;
00115           const C w2 = w * w;
00116 
00117           algebra::h_mat<3, C> m;
00118 
00119           m(0,0) = u2 + (1 - u2) * cos_a;
00120           m(0,1) = u * v * (1 - cos_a) - w * sin_a;
00121           m(0,2) = u * w * (1 - cos_a) + v * sin_a;
00122           m(0,3) = 0;
00123 
00124           m(1,0) = u * v * (1 - cos_a) + w * sin_a;
00125           m(1,1) = v2 + (1 - v2) * cos_a;
00126           m(1,2) = v * w * (1 - cos_a) - u * sin_a;
00127           m(1,3) = 0;
00128 
00129           m(2,0) = u * w * (1 - cos_a) - v * sin_a;
00130           m(2,1) = v * w * (1 - cos_a) + u * sin_a;
00131           m(2,2) = w2 + (1 - w2) * cos_a;
00132           m(2,3) = 0;
00133 
00134           m(3,0) = 0;
00135           m(3,1) = 0;
00136           m(3,2) = 0;
00137           m(3,3) = 1;
00138 
00139           return m;
00140         }
00141 
00142       } // end of namespace internal
00143 
00144 
00146       template <unsigned n, typename C>
00147       struct rotation
00148         : fun::internal::x2x_linear_impl_< algebra::vec<n,C>, C, rotation<n,C> >,
00149           public Function_v2v< rotation<n,C> >
00150       {
00152         typedef C data_t;
00153 
00155         typedef rotation<n,C> invert;
00157         invert inv() const;
00158 
00160         rotation();
00163         rotation(C alpha, const algebra::vec<n,C>& axis);
00165         rotation(const algebra::quat& q);
00167         rotation(const algebra::h_mat<n,C>& m);
00168 
00170         algebra::vec<n,C> operator()(const algebra::vec<n,C>& v) const;
00171 
00173         void set_alpha(C alpha);
00175         void set_axis(const algebra::vec<n,C>& axis);
00176 
00177       protected:
00178         void update();
00179         bool check_rotation(const algebra::quat& q);
00180 
00181         /* FIXME: Is it useful to keep these values, since they are
00182            primarily used to build the matrix `m_'?  */
00183         C alpha_;
00184         algebra::vec<n,C> axis_;
00185       };
00186 
00187 
00188 # ifndef MLN_INCLUDE_ONLY
00189 
00190       template <unsigned n, typename C>
00191       inline
00192       rotation<n,C>::rotation()
00193       {
00194       }
00195 
00196       template <unsigned n, typename C>
00197       inline
00198       rotation<n,C>::rotation(C alpha, const algebra::vec<n,C>& axis)
00199         : alpha_(alpha),
00200           axis_(axis)
00201       {
00202         this->m_ = algebra::h_mat<n,C>::Id;
00203         update();
00204       }
00205 
00206       template <unsigned n, typename C>
00207       inline
00208       rotation<n,C>::rotation(const algebra::quat& q)
00209       {
00210         // FIXME: Should also work for 2D.
00211         mlc_bool(n == 3)::check();
00212         mln_precondition(q.is_unit());
00213 
00214         C
00215           w = q.to_vec()[0],
00216           x = q.to_vec()[1],  x2 = 2*x*x,  xw = 2*x*w,
00217           y = q.to_vec()[2],  y2 = 2*y*y,  xy = 2*x*y,  yw = 2*y*w,
00218           z = q.to_vec()[3],  z2 = 2*z*z,  xz = 2*x*z,  yz = 2*y*z,  zw = 2*z*w;
00219 
00220         C t[9] = {1.f - y2 - z2,  xy - zw,  xz + yw,
00221                       xy + zw,  1.f - x2 - z2,  yz - xw,
00222                       xz - yw,  yz + xw,  1.f - x2 - y2};
00223 
00224         this->m_ = mln::make::h_mat(t);
00225         mln_assertion(check_rotation(q));
00226 
00228         alpha_ = acos(w) * 2;
00229         axis_[0] = x;
00230         axis_[1] = y;
00231         axis_[2] = z;
00232         axis_.normalize();
00233       }
00234 
00235 
00236       template <unsigned n, typename C>
00237       inline
00238       rotation<n,C>::rotation(const algebra::h_mat<n,C>& m)
00239       {
00240         this->m_ = m;
00241       }
00242 
00243 
00244       template <unsigned n, typename C>
00245       inline
00246       algebra::vec<n,C>
00247       rotation<n,C>::operator()(const algebra::vec<n,C>& v) const
00248       {
00249         algebra::mat<n+1,1,C> hmg;
00250         algebra::mat<n+1,1,C> tmp;
00251         algebra::vec<n,C> res;
00252         for (unsigned i = 0; i < n; ++i)
00253           hmg(i,0) = v[i];
00254         hmg(n,0) = 1;
00255         tmp = this->m_ * hmg;
00256         mln_assertion(tmp(n,0) == 1);
00257         for (unsigned i = 0; i < n; ++i)
00258           res[i] = tmp(i,0);
00259         return res;
00260       }
00261 
00262       template <unsigned n, typename C>
00263       inline
00264       rotation<n,C>
00265       rotation<n,C>::inv() const
00266       {
00267         typename rotation::invert res(-alpha_, axis_);
00268         return res;
00269       }
00270 
00271       template <unsigned n, typename C>
00272       inline
00273       void
00274       rotation<n,C>::set_alpha(C alpha)
00275       {
00276         alpha_ = alpha;
00277         update();
00278       }
00279 
00280       template <unsigned n, typename C>
00281       inline
00282       void
00283       rotation<n,C>::set_axis(const algebra::vec<n,C>& axis)
00284       {
00285         axis_ = axis;
00286         update();
00287       }
00288 
00289       // Homogenous matrix for a rotation of a point (x,y,z)
00290       // about the vector (u,v,w) by the angle alpha.
00291       template <unsigned n, typename C>
00292       inline
00293       void
00294       rotation<n,C>::update()
00295       {
00296         this->m_ = internal::get_rot_h_mat(alpha_, axis_);
00297       }
00298 
00299       template <unsigned n, typename C>
00300       inline
00301       bool
00302       rotation<n,C>::check_rotation(const algebra::quat& q)
00303       {
00304         srand(time(0));
00305         assert(q.is_unit());
00306 
00307         algebra::vec<n,C>
00308           tmp = make::vec(rand(), rand(), rand()),
00309               p = tmp / norm::l2(tmp),
00310               p_rot_1 = q.rotate(p),
00311               p_rot_2 = (*this)(p);
00312         return norm::l2(p_rot_1 - p_rot_2) < mln_epsilon(C);
00313       }
00314 
00315 # endif // ! MLN_INCLUDE_ONLY
00316 
00317 
00318     } // end of namespace mln::fun::x2x
00319 
00320   } // end of namespace mln::fun
00321 
00322 } // end of namespace mln
00323 
00324 
00325 #endif // ! MLN_FUN_X2X_ROTATION_HH

Generated on Tue Oct 4 2011 15:24:22 for Milena (Olena) by  doxygen 1.7.1