summaryrefslogtreecommitdiffstats
path: root/kscreensaver/kdesavers/vec3.h
blob: 62aeb8ed208b2ab9a5f18405ce3b99345110507e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
//============================================================================
//
// 3-dim real vector class
// $Id$
// Copyright (C) 2004 Georg Drenkhahn
//
// This file is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License version 2 as published by the
// Free Software Foundation.
//
//============================================================================

#ifndef VEC3_H
#define VEC3_H

#include <valarray>

/** @brief 3-dimensional real vector
 *
 * Implements regular 3 dimensional (space) vectors including the common inner
 * scalar product (2 norm) and the cross product.  @a T may be any integer or
 * float data type which is an acceptable template argument of std::valarray. */
template<typename T>
class vec3 : public std::valarray<T>
{
  public:
   /** Default constructor */
   vec3();
   /** Constructor with initial element values */
   vec3(const T&, const T&, const T&);
   /** Copy constructor */
   vec3(const std::valarray<T>&);
   /** Copy constructor */
   vec3(const std::slice_array<T>&);

   /** Normalize the vector to have a norm of 1.  @return Normalized vector if
    * length is non-zero and otherwise the zero vector. */
   vec3& normalize();

   /** Rotate the vector (*this) in positive mathematical direction around the
    * direction given by @a r.  The norm of @a r specifies the rotation angle in
    * radians.
    * @param r Rotation vector.
    * @return Rotated vector. */
   vec3& rotate(const vec3& r);

   /*--- static funcions ---*/

   /** @param a first vector
    * @param b second vector
    * @return Cosine of the angle between @a a and @a b.  If norm(@a a)==0 or
    * norm(@a b)==0 the global variable errno is set to EDOM and NAN (or
    * std::numeric_limits<T>::quiet_NaN()) is returned. */
   static T cos_angle(const vec3& a, const vec3& b);

   /** @brief Returns the angle between vectors @c a and @a b but with respect
    * to a preferred rotation direction @a c.
    *
    * @param a First vector for angle.  Must be | @a a |>0 otherwises NAN is
    * returned.
    * @param b Second vector for angle.  Must be | @a b |>0 otherwises NAN is
    * returned.
    * @param c Indicates the rotation direction. @a c can be any vector which is
    * not part of the plane spanned by @a a and @a b.  If | @a c | = 0 the
    * smalest possible angle angle is returned.
    * @return Angle in radians between 0 and 2*Pi or NAN if | @a a |=0 or | @a b
    * |=0.
    *
    * For @a a not parallel to @a b and @a a not antiparallel to @a b the 2
    * vectors @a a,@a b span a unique plane in the 3-dimensional space.  Let @b
    * n<sub>1</sub> and @b n<sub>2</sub> be the two possible normal vectors for
    * this plane with |@b n<sub>i</sub> |=1, i={1,2} and @b n<sub>1</sub> = -@b
    * n<sub>2</sub> .
    *
    * Let further @a a and @a b enclose an angle alpha in [0,Pi], then there is
    * one i in {1,2} so that (alpha*@b n<sub>i</sub> x @a a) * @a b = 0.  This
    * means @a a rotated by the rotation vector alpha*@b n<sub>i</sub> is
    * parallel to @a b.  One could also rotate @a a by (2*Pi-alpha)*(-@b
    * n<sub>i</sub>) to acomplish the same transformation with
    * ((2*Pi-alpha)*(-@b n<sub>i</sub>) x @a a) * @a b = 0
    *
    * The vector @a c defines the direction of the normal vector to take as
    * reference.  If @a c * @b n<sub>i</sub> > 0 alpha is returned and otherwise
    * 2*Pi-alpha.  If @a a parallel to @a b or @a a parallel to @a b the choice
    * of @a c does not matter. */
   static T angle(const vec3& a, const vec3& b, const vec3& c);

   /*--- static inline funcions ---*/

   /** Norm of argument vector.
    * @param a vector.
    * @return | @a a | */
   static T norm(const vec3& a);

   /** Angle between @a a and @a b.
    * @param a fist vector.  Must be | @a a | > 0 otherwises NAN is returned.
    * @param b second vector.  Must be | @a b | > 0 otherwises NAN is returned.
    * @return Angle in radians between 0 and Pi or NAN if | @a a | = 0 or | @a b
    * | = 0. */
   static T angle(const vec3& a, const vec3& b);

   /** Cross product of @a a and @a b.
    * @param a fist vector.
    * @param b second vector.
    * @return Cross product of argument vectors @a a x @a b. */
   static vec3 crossprod(const vec3& a, const vec3& b);

   /** Normalized version of argument vector.
    * @param a vector.
    * @return @a a / | @a a | for | @a a | > 0 and otherwise the zero vector
    * (=@a a).  In the latter case the global variable errno is set to EDOM. */
   static vec3 normalized(vec3 a);
};

/*--- inline member functions ---*/

template<typename T>
inline vec3<T>::vec3()
   : std::valarray<T>(3)
{}

template<typename T>
inline vec3<T>::vec3(const T& a, const T& b, const T& c)
   : std::valarray<T>(3)
{
   (*this)[0] = a;
   (*this)[1] = b;
   (*this)[2] = c;
}

template<typename T>
inline vec3<T>::vec3(const std::valarray<T>& a)
   : std::valarray<T>(a)
{
}

template<typename T>
inline vec3<T>::vec3(const std::slice_array<T>& a)
   : std::valarray<T>(a)
{
}

/*--- inline non-member operators ---*/

/** @param a first vector summand
 * @param b second vector summand
 * @return Sum vector of vectors @a a and @a b. */
template<typename T>
inline vec3<T> operator+(vec3<T> a, const vec3<T>& b)
{
   a += b;   /* valarray<T>::operator+=(const valarray<T>&) */
   return a;
}

/** @param a first vector multiplicant
 * @param b second vector multiplicant
 * @return Scalar product of vectors @a a and @a b. */
template<typename T>
inline T operator*(vec3<T> a, const vec3<T>& b)
{
   a *= b;   /* valarray<T>::operator*=(const T&) */
   return a.sum();
}

/** @param a scalar multiplicant
 * @param b vector operand
 * @return Product vector of scalar @a a and vector @a b. */
template<typename T>
inline vec3<T> operator*(const T& a, vec3<T> b)
{
   b *= a;    /* valarray<T>::operator*=(const T&) */
   return b;
}

/** @param a vector operand
 * @param b scalar multiplicant
 * @return Product vector of scalar @a b and vector @a a. */
template<typename T>
inline vec3<T> operator*(vec3<T> a, const T& b)
{
   return b*a; /* vec3<T>::operator*(const T&, vec3<T>) */
}

/*--- static inline funcions ---*/

template<typename T>
inline T vec3<T>::norm(const vec3<T>& a)
{
   return sqrt(a*a);
}

template<typename T>
inline T vec3<T>::angle(const vec3<T>& a, const vec3<T>& b)
{
   // returns NAN if cos_angle() returns NAN (TODO: test this case)
   return acos(cos_angle(a,b));
}

template<typename T>
inline vec3<T> vec3<T>::crossprod(const vec3<T>& a, const vec3<T>& b)
{
   return vec3<T>(
      a[1]*b[2] - a[2]*b[1],
      a[2]*b[0] - a[0]*b[2],
      a[0]*b[1] - a[1]*b[0]);
}

template<typename T>
inline vec3<T> vec3<T>::normalized(vec3<T> a)
{
   return a.normalize();
}

#endif