1 /* -*- C++ -*- ------------------------------------------------------------
3 Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/
5 The Configurable Math Library (CML) is distributed under the terms of the
6 Boost Software License, v1.0 (see cml/LICENSE for details).
8 *-----------------------------------------------------------------------*/
16 #include <cml/mathlib/coord_conversion.h>
18 /* Miscellaneous vector functions. */
22 /* Function to project a vector v onto a hyperplane specified by a unit-length
25 * @todo: Clean up promotion code.
28 template < class VecT_1
, class VecT_2
>
29 typename
detail::CrossPromote
<VecT_1
,VecT_2
>::promoted_vector
30 project_to_hplane(const VecT_1
& v
, const VecT_2
& n
)
32 typedef typename
detail::CrossPromote
<VecT_1
,VecT_2
>::promoted_vector
36 et::detail::Resize(result
, v
.size());
38 result
= v
- dot(v
,n
) * n
;
42 /* Return a vector perpendicular (CCW) to a 2D vector. */
43 template < class VecT
> vector
< typename
VecT::value_type
, fixed
<2> >
46 typedef vector
< typename
VecT::value_type
, fixed
<2> > temporary_type
;
51 return temporary_type(-v
[1],v
[0]);
54 /* @todo: unit_cross() and cross_cardinal() should probably go in
55 * vector_products.h, but I'm trying to avoid modifying the existing codebase
59 /** Return normalized cross product of two vectors */
60 template< class LeftT
, class RightT
>
61 typename
detail::CrossPromote
<LeftT
,RightT
>::promoted_vector
62 unit_cross(const LeftT
& left
, const RightT
& right
) {
63 /* @todo: This will probably break with dynamic<> vectors */
64 return normalize(cross(left
,right
));
67 /** Return the cross product of v and the i'th cardinal basis vector */
68 template < class VecT
> vector
< typename
VecT::value_type
, fixed
<3> >
69 cross_cardinal(const VecT
& v
, size_t i
)
71 typedef vector
< typename
VecT::value_type
, fixed
<3> > vector_type
;
72 typedef typename
vector_type::value_type value_type
;
76 detail::CheckIndex3(i
);
79 cyclic_permutation(i
, i
, j
, k
);
81 result
[i
] = value_type(0);
87 /** Return the cross product of the i'th cardinal basis vector and v */
88 template < class VecT
> vector
< typename
VecT::value_type
, fixed
<3> >
89 cross_cardinal(size_t i
, const VecT
& v
)
91 typedef vector
< typename
VecT::value_type
, fixed
<3> > vector_type
;
92 typedef typename
vector_type::value_type value_type
;
96 detail::CheckIndex3(i
);
99 cyclic_permutation(i
, i
, j
, k
);
101 result
[i
] = value_type(0);
107 /** Rotate a 3D vector v about a unit-length vector n. */
108 template< class VecT_1
, class VecT_2
, typename Real
>
110 typename
et::ScalarPromote
<
111 typename
VecT_1::value_type
,
112 typename
VecT_2::value_type
116 rotate_vector(const VecT_1
& v
, const VecT_2
& n
, Real angle
)
119 typename
et::ScalarPromote
<
120 typename
VecT_1::value_type
,
121 typename
VecT_2::value_type
127 detail::CheckVec3(v
);
128 detail::CheckVec3(n
);
130 result_type parallel
= dot(v
,n
)*n
;
132 std::cos(angle
)*(v
-parallel
) + std::sin(angle
)*cross(n
,v
) + parallel
136 /** Rotate a 2D vector v about a unit-length vector n. */
137 template< class VecT
, typename Real
>
138 vector
< typename
VecT::value_type
, fixed
<2> >
139 rotate_vector_2D(const VecT
& v
, Real angle
)
141 typedef vector
< typename
VecT::value_type
, fixed
<2> > result_type
;
142 typedef typename
result_type::value_type value_type
;
145 detail::CheckVec2(v
);
147 value_type s
= std::sin(angle
);
148 value_type c
= std::cos(angle
);
150 return result_type(c
* v
[0] - s
* v
[1], s
* v
[0] + c
* v
[1]);
153 /** Random unit 3D or 2D vector
155 * @todo: This is just placeholder code for what will be a more thorough
156 * 'random unit' implementation:
158 * - All dimensions will be handled uniformly if practical, perhaps through
159 * a normal distrubution PRNG.
161 * - Failing that (or perhaps even in this case), dimensions 2 and 3 will be
162 * dispatched to special-case code, most likely implementing the algorithms
165 * - Like the utility random functions, the option of using one's own PRGN
166 * will be made available.
168 * @todo: Once N-d random vectors are supported, add a 'random unit
169 * quaternion' function that wraps a call to random_unit() with a 4D vector as
172 template < typename E
, class A
> void
173 random_unit(vector
<E
,A
>& v
)
175 typedef vector
<E
,A
> vector_type
;
176 typedef typename
vector_type::value_type value_type
;
181 vector
< E
, fixed
<3> > temp
;
182 spherical_to_cartesian(
184 value_type(random_unit() * constants
<value_type
>::two_pi()),
185 acos_safe(random_real(value_type(-1),value_type(1))),
197 vector
< E
, fixed
<2> > temp
;
200 value_type(random_unit() * constants
<value_type
>::two_pi()),
208 throw std::invalid_argument(
209 "random_unit() for N-d vectors not implemented yet");
214 /* Random vector within a given angle of a unit-length axis, i.e. in a cone
215 * (3D) or wedge (2D).
217 * The same notes the appear above apply here too, more or less. One
218 * difference is that this is really only useful in 2D and 3D (presumably), so
219 * we'll probably just do a compile- or run-time dispatch as appropriate.
221 * Also, there may be a better algorithm for generating a random unit vector
222 * in a cone; need to look into that.
224 * All of this 'temp' stuff is because there's no compile-time dispatch for
225 * 3D and 2D vectors, but that'll be fixed soon.
228 template < typename E
, class A
, class VecT
> void
229 random_unit(vector
<E
,A
>& v
, const VecT
& axis
, E theta
)
231 typedef vector
<E
,A
> vector_type
;
232 typedef typename
vector_type::value_type value_type
;
237 vector
< E
, fixed
<3> > temp
, n
, temp_axis
;
238 temp_axis
[0] = axis
[0];
239 temp_axis
[1] = axis
[1];
240 temp_axis
[2] = axis
[2];
242 /* @todo: Function for finding 'any perpendicular vector'? */
243 n
= axis_3D(cml::index_of_min_abs(axis
[0],axis
[1],axis
[2]));
244 n
= cross(n
,temp_axis
);
246 /* Rotate v 'away from' the axis by a random angle in the range
249 temp
= rotate_vector(temp_axis
,n
,random_real(-theta
,theta
));
251 /* Rotate v about the axis by a random angle in the range [-pi,pi]
253 temp
= rotate_vector(
257 -constants
<value_type
>::pi(),
258 constants
<value_type
>::pi()
269 vector
< E
, fixed
<2> > temp
, temp_axis
;
270 temp_axis
[0] = axis
[0];
271 temp_axis
[1] = axis
[1];
272 temp
= rotate_vector_2D(temp_axis
, random_real(-theta
,theta
));
278 throw std::invalid_argument(
279 "random_unit(v,axis,theta) only implemented for 2D and 3D");
284 /* NEW: Manhattan distance */
286 template< class VecT_1
, class VecT_2
>
287 typename
detail::DotPromote
< VecT_1
, VecT_2
>::promoted_scalar
288 manhattan_distance(const VecT_1
& v1
, const VecT_2
& v2
) {
289 /* Check that a promotion exists */
290 typedef typename
et::VectorPromote
<
291 VecT_1
,VecT_2
>::temporary_type promoted_vector
;
293 typedef typename
detail::DotPromote
< VecT_1
, VecT_2
>::promoted_scalar scalar_type
;
295 scalar_type sum
= scalar_type(0);
296 for (size_t i
= 0; i
< v1
.size(); ++i
) {
297 sum
+= std::fabs(v2
[i
]-v1
[i
]);