wfmath  1.0.3
A math library for the Worldforge system.
vector_funcs.h
1 // vector_funcs.h (Vector<> template functions)
2 //
3 // The WorldForge Project
4 // Copyright (C) 2001 The WorldForge Project
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 //
20 // For information about WorldForge and its authors, please contact
21 // the Worldforge Web Site at http://www.worldforge.org.
22 
23 // Author: Ron Steinke
24 // Created: 2001-12-7
25 
26 // Extensive amounts of this material come from the Vector2D
27 // and Vector3D classes from stage/math, written by Bryce W.
28 // Harrington, Kosh, and Jari Sundell (Rakshasa).
29 
30 #ifndef WFMATH_VECTOR_FUNCS_H
31 #define WFMATH_VECTOR_FUNCS_H
32 
33 #include <wfmath/vector.h>
34 #include <wfmath/rotmatrix.h>
35 #include <wfmath/zero.h>
36 
37 #include <limits>
38 
39 #include <cmath>
40 
41 #include <cassert>
42 
43 namespace WFMath {
44 
45 template<int dim>
46 Vector<dim>::Vector(const Vector<dim>& v) : m_valid(v.m_valid)
47 {
48  for(int i = 0; i < dim; ++i) {
49  m_elem[i] = v.m_elem[i];
50  }
51 }
52 
53 template<int dim>
54 Vector<dim>::Vector(const Point<dim>& p) : m_valid(p.isValid())
55 {
56  for(int i = 0; i < dim; ++i) {
57  m_elem[i] = p.elements()[i];
58  }
59 }
60 
61 template<int dim>
63 {
64  static ZeroPrimitive<Vector<dim> > zeroVector(dim);
65  return zeroVector.getShape();
66 }
67 
68 
69 template<int dim>
71 {
72  m_valid = v.m_valid;
73 
74  for(int i = 0; i < dim; ++i) {
75  m_elem[i] = v.m_elem[i];
76  }
77 
78  return *this;
79 }
80 
81 template<int dim>
82 bool Vector<dim>::isEqualTo(const Vector<dim>& v, CoordType epsilon) const
83 {
84  //If anyone is invalid they are never equal
85  if (!v.m_valid || !m_valid) {
86  return false;
87  }
88 
89  CoordType delta = _ScaleEpsilon(m_elem, v.m_elem, dim, epsilon);
90  for(int i = 0; i < dim; ++i) {
91  if(std::fabs(m_elem[i] - v.m_elem[i]) > delta) {
92  return false;
93  }
94  }
95 
96  return true;
97 }
98 
99 template <int dim>
100 Vector<dim>& operator+=(Vector<dim>& v1, const Vector<dim>& v2)
101 {
102  v1.m_valid = v1.m_valid && v2.m_valid;
103 
104  for(int i = 0; i < dim; ++i) {
105  v1.m_elem[i] += v2.m_elem[i];
106  }
107 
108  return v1;
109 }
110 
111 template <int dim>
112 Vector<dim>& operator-=(Vector<dim>& v1, const Vector<dim>& v2)
113 {
114  v1.m_valid = v1.m_valid && v2.m_valid;
115 
116  for(int i = 0; i < dim; ++i) {
117  v1.m_elem[i] -= v2.m_elem[i];
118  }
119 
120  return v1;
121 }
122 
123 template <int dim>
125 {
126  for(int i = 0; i < dim; ++i) {
127  v.m_elem[i] *= d;
128  }
129 
130  return v;
131 }
132 
133 template <int dim>
135 {
136  for(int i = 0; i < dim; ++i) {
137  v.m_elem[i] /= d;
138  }
139 
140  return v;
141 }
142 
143 
144 template <int dim>
145 Vector<dim> operator-(const Vector<dim>& v)
146 {
147  Vector<dim> ans;
148 
149  ans.m_valid = v.m_valid;
150 
151  for(int i = 0; i < dim; ++i) {
152  ans.m_elem[i] = -v.m_elem[i];
153  }
154 
155  return ans;
156 }
157 
158 template<int dim>
160 {
161  CoordType mag = sloppyMag();
162 
163  assert("need nonzero length vector" && mag > norm / std::numeric_limits<CoordType>::max());
164 
165  return (*this *= norm / mag);
166 }
167 
168 template<int dim>
170 {
171  m_valid = true;
172 
173  for(int i = 0; i < dim; ++i) {
174  m_elem[i] = 0;
175  }
176 
177  return *this;
178 }
179 
180 template<int dim>
181 CoordType Angle(const Vector<dim>& v, const Vector<dim>& u)
182 {
183  // Adding numbers with large magnitude differences can cause
184  // a loss of precision, but Dot() checks for this now
185 
186  CoordType dp = FloatClamp(Dot(u, v) / std::sqrt(u.sqrMag() * v.sqrMag()),
187  -1.0, 1.0);
188 
189  CoordType angle = std::acos(dp);
190 
191  return angle;
192 }
193 
194 template<int dim>
195 Vector<dim>& Vector<dim>::rotate(int axis1, int axis2, CoordType theta)
196 {
197  assert(axis1 >= 0 && axis2 >= 0 && axis1 < dim && axis2 < dim && axis1 != axis2);
198 
199  CoordType tmp1 = m_elem[axis1], tmp2 = m_elem[axis2];
200  CoordType stheta = std::sin(theta),
201  ctheta = std::cos(theta);
202 
203  m_elem[axis1] = tmp1 * ctheta - tmp2 * stheta;
204  m_elem[axis2] = tmp2 * ctheta + tmp1 * stheta;
205 
206  return *this;
207 }
208 
209 template<int dim>
211  CoordType theta)
212 {
213  RotMatrix<dim> m;
214  return operator=(Prod(*this, m.rotation(v1, v2, theta)));
215 }
216 
217 template<int dim>
219 {
220  return *this = Prod(*this, m);
221 }
222 
223 template<> Vector<3>& Vector<3>::rotate(const Vector<3>& axis, CoordType theta);
224 template<> Vector<3>& Vector<3>::rotate(const Quaternion& q);
225 
226 template<int dim>
227 CoordType Dot(const Vector<dim>& v1, const Vector<dim>& v2)
228 {
229  double delta = _ScaleEpsilon(v1.m_elem, v2.m_elem, dim);
230 
231  CoordType ans = 0;
232 
233  for(int i = 0; i < dim; ++i) {
234  ans += v1.m_elem[i] * v2.m_elem[i];
235  }
236 
237  return (std::fabs(ans) >= delta) ? ans : 0;
238 }
239 
240 template<int dim>
242 {
243  CoordType ans = 0;
244 
245  for(int i = 0; i < dim; ++i) {
246  // all terms > 0, no loss of precision through cancelation
247  ans += m_elem[i] * m_elem[i];
248  }
249 
250  return ans;
251 }
252 
253 template<int dim>
254 bool Perpendicular(const Vector<dim>& v1, const Vector<dim>& v2)
255 {
256  CoordType max1 = 0, max2 = 0;
257 
258  for(int i = 0; i < dim; ++i) {
259  CoordType val1 = std::fabs(v1[i]), val2 = std::fabs(v2[i]);
260  if(val1 > max1) {
261  max1 = val1;
262  }
263  if(val2 > max2) {
264  max2 = val2;
265  }
266  }
267 
268  // Need to scale by both, since Dot(v1, v2) goes like the product of the magnitudes
269  int exp1, exp2;
270  (void) std::frexp(max1, &exp1);
271  (void) std::frexp(max2, &exp2);
272 
273  return std::fabs(Dot(v1, v2)) < std::ldexp(numeric_constants<CoordType>::epsilon(), exp1 + exp2);
274 }
275 
276 // Note for people trying to compute the above numbers
277 // more accurately:
278 
279 // The worst value for dim == 2 occurs when the ratio of the components
280 // of the vector is sqrt(2) - 1. The value above is equal to sqrt(4 - 2 * sqrt(2)).
281 
282 // The worst value for dim == 3 occurs when the two smaller components
283 // are equal, and their ratio with the large component is the
284 // (unique, real) solution to the equation q x^3 + (q-1) x + p == 0,
285 // where p = sqrt(2) - 1, and q = sqrt(3) + 1 - 2 * sqrt(2).
286 // Running the script bc_sloppy_mag_3 provided with the WFMath source
287 // will calculate the above number.
288 
289 template<> Vector<2>& Vector<2>::polar(CoordType r, CoordType theta);
290 template<> void Vector<2>::asPolar(CoordType& r, CoordType& theta) const;
291 
292 template<> Vector<3>& Vector<3>::polar(CoordType r, CoordType theta,
293  CoordType z);
294 template<> void Vector<3>::asPolar(CoordType& r, CoordType& theta,
295  CoordType& z) const;
296 template<> Vector<3>& Vector<3>::spherical(CoordType r, CoordType theta,
297  CoordType phi);
298 template<> void Vector<3>::asSpherical(CoordType& r, CoordType& theta,
299  CoordType& phi) const;
300 
301 template<> CoordType Vector<2>::sloppyMag() const;
302 template<> CoordType Vector<3>::sloppyMag() const;
303 
304 template<> CoordType Vector<1>::sloppyMag() const
305  {return std::fabs(m_elem[0]);}
306 
307 template<> Vector<2>::Vector(CoordType x, CoordType y) : m_valid(true)
308  {m_elem[0] = x; m_elem[1] = y;}
309 template<> Vector<3>::Vector(CoordType x, CoordType y, CoordType z) : m_valid(true)
310  {m_elem[0] = x; m_elem[1] = y; m_elem[2] = z;}
311 
312 template<> Vector<2>& Vector<2>::rotate(CoordType theta)
313  {return rotate(0, 1, theta);}
314 
315 template<> Vector<3>& Vector<3>::rotateX(CoordType theta)
316  {return rotate(1, 2, theta);}
317 template<> Vector<3>& Vector<3>::rotateY(CoordType theta)
318  {return rotate(2, 0, theta);}
319 template<> Vector<3>& Vector<3>::rotateZ(CoordType theta)
320  {return rotate(0, 1, theta);}
321 
322 
323 } // namespace WFMath
324 
325 #endif // WFMATH_VECTOR_FUNCS_H
WFMath::RotMatrix::rotation
RotMatrix & rotation(int i, int j, CoordType theta)
set the matrix to a rotation by the angle theta in the (i, j) plane
Definition: rotmatrix_funcs.h:366
WFMath::Vector< 2 >::sloppyMag
CoordType sloppyMag() const
An approximation to the magnitude of a vector.
WFMath::Vector< 3 >::spherical
Vector & spherical(CoordType r, CoordType theta, CoordType phi)
3D only: construct a vector from shperical coordinates
WFMath::Vector< 3 >::rotateX
Vector & rotateX(CoordType theta)
3D only: rotate a vector about the x axis by an angle theta
WFMath::RotMatrix
A dim dimensional rotation matrix. Technically, a member of the group O(dim).
Definition: const.h:53
WFMath::Vector::sqrMag
CoordType sqrMag() const
The squared magnitude of a vector.
Definition: vector_funcs.h:241
WFMath::Vector< 3 >::asSpherical
void asSpherical(CoordType &r, CoordType &theta, CoordType &phi) const
3D only: convert a vector to shperical coordinates
WFMath::Quaternion
A normalized quaternion.
Definition: quaternion.h:35
WFMath::Prod
RotMatrix< dim > Prod(const RotMatrix< dim > &m1, const RotMatrix< dim > &m2)
returns m1 * m2
Definition: rotmatrix_funcs.h:95
WFMath::Vector< 3 >::rotateY
Vector & rotateY(CoordType theta)
3D only: rotate a vector about the y axis by an angle theta
WFMath::Vector< 2 >::polar
Vector & polar(CoordType r, CoordType theta)
2D only: construct a vector from polar coordinates
WFMath::ZeroPrimitive::getShape
const Shape & getShape() const
Gets the zeroed shape.
Definition: zero.h:53
WFMath
Generic library namespace.
Definition: shape.h:41
WFMath::Vector
A dim dimensional vector.
Definition: const.h:55
WFMath::CoordType
double CoordType
Basic floating point type.
Definition: const.h:140
WFMath::numeric_constants
Definition: const.h:64
WFMath::Vector< 2 >::rotate
Vector & rotate(int axis1, int axis2, CoordType theta)
Rotate the vector in the (axis1, axis2) plane by the angle theta.
Definition: vector_funcs.h:195
WFMath::Perpendicular
bool Perpendicular(const Vector< dim > &v1, const Vector< dim > &v2)
Check if two vectors are perpendicular.
Definition: vector_funcs.h:254
WFMath::Vector< 3 >::rotateZ
Vector & rotateZ(CoordType theta)
3D only: rotate a vector about the z axis by an angle theta
WFMath::ZeroPrimitive
Utility class for providing zero primitives. This class will only work with simple structures such as...
Definition: point.h:87
WFMath::Vector::Vector
Vector()
Construct an uninitialized vector.
Definition: vector.h:125
WFMath::Point
A dim dimensional point.
Definition: const.h:50
WFMath::Vector< 2 >::asPolar
void asPolar(CoordType &r, CoordType &theta) const
2D only: convert a vector to polar coordinates