vector_misc.h

Go to the documentation of this file.
00001 /* -*- C++ -*- ------------------------------------------------------------
00002  
00003 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
00004 
00005 The Configurable Math Library (CML) is distributed under the terms of the
00006 Boost Software License, v1.0 (see cml/LICENSE for details).
00007 
00008  *-----------------------------------------------------------------------*/
00013 #ifndef vector_misc_h
00014 #define vector_misc_h
00015 
00016 #include <cml/mathlib/coord_conversion.h>
00017 
00018 /* Miscellaneous vector functions. */
00019 
00020 namespace cml {
00021 
00022 /* Function to project a vector v onto a hyperplane specified by a unit-length
00023  * normal n.
00024  *
00025  * @todo: Clean up promotion code.
00026  */
00027 
00028 template < class VecT_1, class VecT_2 >
00029 typename detail::CrossPromote<VecT_1,VecT_2>::promoted_vector
00030 project_to_hplane(const VecT_1& v, const VecT_2& n)
00031 {
00032     typedef typename detail::CrossPromote<VecT_1,VecT_2>::promoted_vector
00033         result_type;
00034         
00035     result_type result;
00036     et::detail::Resize(result, v.size());
00037 
00038     result = v - dot(v,n) * n;
00039     return result;
00040 }
00041 
00042 /* Return a vector perpendicular (CCW) to a 2D vector. */
00043 template < class VecT > vector< typename VecT::value_type, fixed<2> >
00044 perp(const VecT& v)
00045 {
00046     typedef vector< typename VecT::value_type, fixed<2> > temporary_type;
00047     
00048     /* Checking */
00049     detail::CheckVec2(v);
00050     
00051     return temporary_type(-v[1],v[0]);
00052 }
00053 
00054 /* @todo: unit_cross() and cross_cardinal() should probably go in
00055  * vector_products.h, but I'm trying to avoid modifying the existing codebase
00056  * for now.
00057  */
00058 
00060 template< class LeftT, class RightT >
00061 typename detail::CrossPromote<LeftT,RightT>::promoted_vector
00062 unit_cross(const LeftT& left, const RightT& right) {
00063     /* @todo: This will probably break with dynamic<> vectors */
00064     return normalize(cross(left,right));
00065 }
00066 
00068 template < class VecT > vector< typename VecT::value_type, fixed<3> >
00069 cross_cardinal(const VecT& v, size_t i)
00070 {
00071     typedef vector< typename VecT::value_type, fixed<3> > vector_type;
00072     typedef typename vector_type::value_type value_type;
00073 
00074     /* Checking */
00075     detail::CheckVec3(v);
00076     detail::CheckIndex3(i);
00077 
00078     size_t j, k;
00079     cyclic_permutation(i, i, j, k);
00080     vector_type result;
00081     result[i] = value_type(0);
00082     result[j] = v[k];
00083     result[k] = -v[j];
00084     return result;
00085 }
00086 
00088 template < class VecT > vector< typename VecT::value_type, fixed<3> >
00089 cross_cardinal(size_t i, const VecT& v)
00090 {
00091     typedef vector< typename VecT::value_type, fixed<3> > vector_type;
00092     typedef typename vector_type::value_type value_type;
00093 
00094     /* Checking */
00095     detail::CheckVec3(v);
00096     detail::CheckIndex3(i);
00097 
00098     size_t j, k;
00099     cyclic_permutation(i, i, j, k);
00100     vector_type result;
00101     result[i] = value_type(0);
00102     result[j] = -v[k];
00103     result[k] = v[j];
00104     return result;
00105 }
00106 
00108 template< class VecT_1, class VecT_2, typename Real >
00109 vector<
00110     typename et::ScalarPromote<
00111         typename VecT_1::value_type,
00112         typename VecT_2::value_type
00113     >::type,
00114     fixed<3>
00115 >
00116 rotate_vector(const VecT_1& v, const VecT_2& n, Real angle)
00117 {
00118     typedef vector<
00119         typename et::ScalarPromote<
00120             typename VecT_1::value_type,
00121             typename VecT_2::value_type
00122         >::type,
00123         fixed<3>
00124     > result_type;
00125     
00126     /* Checking */
00127     detail::CheckVec3(v);
00128     detail::CheckVec3(n);
00129     
00130     result_type parallel = dot(v,n)*n;
00131     return (
00132         std::cos(angle)*(v-parallel) + std::sin(angle)*cross(n,v) + parallel
00133     );
00134 }
00135 
00137 template< class VecT, typename Real >
00138 vector< typename VecT::value_type, fixed<2> >
00139 rotate_vector_2D(const VecT& v, Real angle)
00140 {
00141     typedef vector< typename VecT::value_type, fixed<2> > result_type;
00142     typedef typename result_type::value_type value_type;
00143     
00144     /* Checking */
00145     detail::CheckVec2(v);
00146     
00147     value_type s = std::sin(angle);
00148     value_type c = std::cos(angle);
00149     
00150     return result_type(c * v[0] - s * v[1], s * v[0] + c * v[1]);
00151 }
00152 
00172 template < typename E, class A > void
00173 random_unit(vector<E,A>& v)
00174 {
00175     typedef vector<E,A> vector_type;
00176     typedef typename vector_type::value_type value_type;
00177     
00178     switch (v.size()) {
00179         case 3:
00180         {
00181             vector< E, fixed<3> > temp;
00182             spherical_to_cartesian(
00183                 value_type(1),
00184                 value_type(random_unit() * constants<value_type>::two_pi()),
00185                 acos_safe(random_real(value_type(-1),value_type(1))),
00186                 2,
00187                 colatitude,
00188                 temp
00189             );
00190             v[0] = temp[0];
00191             v[1] = temp[1];
00192             v[2] = temp[2];
00193             break;
00194         }
00195         case 2:
00196         {
00197             vector< E, fixed<2> > temp;
00198             polar_to_cartesian(
00199                 value_type(1),
00200                 value_type(random_unit() * constants<value_type>::two_pi()),
00201                 temp
00202             );
00203             v[0] = temp[0];
00204             v[1] = temp[1];
00205             break;
00206         }
00207         default:
00208             throw std::invalid_argument(
00209                 "random_unit() for N-d vectors not implemented yet");
00210             break;
00211     }
00212 }
00213 
00214 /* Random vector within a given angle of a unit-length axis, i.e. in a cone
00215  * (3D) or wedge (2D).
00216  *
00217  * The same notes the appear above apply here too, more or less. One
00218  * difference is that this is really only useful in 2D and 3D (presumably), so
00219  * we'll probably just do a compile- or run-time dispatch as appropriate.
00220  *
00221  * Also, there may be a better algorithm for generating a random unit vector
00222  * in a cone; need to look into that.
00223  *
00224  * All of this 'temp' stuff is because there's no compile-time dispatch for
00225  * 3D and 2D vectors, but that'll be fixed soon.
00226  */
00227 
00228 template < typename E, class A, class VecT > void
00229 random_unit(vector<E,A>& v, const VecT& axis, E theta)
00230 {
00231     typedef vector<E,A> vector_type;
00232     typedef typename vector_type::value_type value_type;
00233     
00234     switch (v.size()) {
00235         case 3:
00236         {
00237             vector< E, fixed<3> > temp, n, temp_axis;
00238             temp_axis[0] = axis[0];
00239             temp_axis[1] = axis[1];
00240             temp_axis[2] = axis[2];
00241 
00242             /* @todo: Function for finding 'any perpendicular vector'? */
00243             n = axis_3D(cml::index_of_min_abs(axis[0],axis[1],axis[2]));
00244             n = cross(n,temp_axis);
00245             
00246             /* Rotate v 'away from' the axis by a random angle in the range
00247              * [-theta,theta]
00248              */
00249             temp = rotate_vector(temp_axis,n,random_real(-theta,theta));
00250              
00251             /* Rotate v about the axis by a random angle in the range [-pi,pi]
00252              */
00253             temp = rotate_vector(
00254                 temp,
00255                 temp_axis,
00256                 random_real(
00257                     -constants<value_type>::pi(),
00258                      constants<value_type>::pi()
00259                 )
00260             );
00261 
00262             v[0] = temp[0];
00263             v[1] = temp[1];
00264             v[2] = temp[2];
00265             break;
00266         }
00267         case 2:
00268         {
00269             vector< E, fixed<2> > temp, temp_axis;
00270             temp_axis[0] = axis[0];
00271             temp_axis[1] = axis[1];
00272             temp = rotate_vector_2D(temp_axis, random_real(-theta,theta));
00273             v[0] = temp[0];
00274             v[1] = temp[1];
00275             break;
00276         }
00277         default:
00278             throw std::invalid_argument(
00279                 "random_unit(v,axis,theta) only implemented for 2D and 3D");
00280             break;
00281     }
00282 }
00283 
00284 /* NEW: Manhattan distance */
00285 
00286 template< class VecT_1, class VecT_2 >
00287 typename detail::DotPromote< VecT_1, VecT_2 >::promoted_scalar
00288 manhattan_distance(const VecT_1& v1, const VecT_2& v2) {
00289     /* Check that a promotion exists */
00290     typedef typename et::VectorPromote<
00291         VecT_1,VecT_2>::temporary_type promoted_vector;
00292         
00293     typedef typename detail::DotPromote< VecT_1, VecT_2 >::promoted_scalar scalar_type;
00294     
00295     scalar_type sum = scalar_type(0);
00296     for (size_t i = 0; i < v1.size(); ++i) {
00297         sum += std::fabs(v2[i]-v1[i]);
00298     }
00299     return sum;
00300 }
00301 
00302 } // namespace cml
00303 
00304 #endif

Generated on Sat Jul 18 19:35:22 2009 for CML 1.0 by  doxygen 1.5.9