quickplot
Loading...
Searching...
No Matches
vector3.h
1// SPDX-License-Identifier: GPL-3.0-or-later
2// Copyright (c) 2024 Team Dissolve and contributors
3
4#pragma once
5
6#include <cmath>
7#include <stdexcept>
8
9// 3D vector
10template <class T> class Vec3
11{
12 public:
13 Vec3<T>() : x(T()), y(T()), z(T()){};
14 Vec3<T>(T value) : x(value), y(value), z(value){};
15 Vec3<T>(T xx, T yy, T zz) : x(xx), y(yy), z(zz){};
16 // Components of vector
17 T x, y, z;
18
19 /*
20 * Set / adjust / retrieve
21 */
22 public:
23 // Set the vector to 0,0,0
24 void zero()
25 {
26 x = 0;
27 y = 0;
28 z = 0;
29 }
30 // Set the specific element to value
31 void set(int index, T value)
32 {
33 if (index == 0)
34 x = value;
35 else if (index == 1)
36 y = value;
37 else if (index == 2)
38 z = value;
39 }
40 // Set all three values simultaneously
41 void set(T newX, T newY, T newZ)
42 {
43 x = newX;
44 y = newY;
45 z = newZ;
46 }
47 // Add value to single component
48 void add(int index, T delta)
49 {
50 if (index == 0)
51 x += delta;
52 else if (index == 1)
53 y += delta;
54 else if (index == 2)
55 z += delta;
56 }
57 // Add values to all three values simultaneously
58 void add(T dx, T dy, T dz)
59 {
60 x += dx;
61 y += dy;
62 z += dz;
63 }
64
65 /*
66 * Operators
67 */
68 public:
69 bool operator==(const Vec3<T> &value) const { return x == value.x && y == value.y && z == value.z; }
70 bool operator!=(const Vec3<T> &value) const { return !(*this == value); }
71 bool operator==(const T &value) const { return x == value && y == value && z == value; }
72 bool operator!=(const T &value) const { return !(*this == value); }
73 void operator=(const T value)
74 {
75 x = value;
76 y = value;
77 z = value;
78 }
79 // Operators + and +=
80 void operator+=(const T value)
81 {
82 x += value;
83 y += value;
84 z += value;
85 }
86 void operator+=(const Vec3<T> &v)
87 {
88 x += v.x;
89 y += v.y;
90 z += v.z;
91 }
92 Vec3<T> operator+(const T value) const
93 {
94 Vec3<T> result;
95 result.x = x + value;
96 result.y = y + value;
97 result.z = z + value;
98 return result;
99 }
100 Vec3<T> operator+(const Vec3<T> &v) const
101 {
102 Vec3<T> result;
103 result.x = x + v.x;
104 result.y = y + v.y;
105 result.z = z + v.z;
106 return result;
107 }
108 // Operators - and -=
109 inline Vec3<T> operator-() const { return Vec3<T>(-x, -y, -z); }
110 void operator-=(const T value)
111 {
112 x -= value;
113 y -= value;
114 z -= value;
115 }
116 void operator-=(const Vec3<T> &v)
117 {
118 x -= v.x;
119 y -= v.y;
120 z -= v.z;
121 }
122 inline Vec3<T> operator-(const T value) const { return Vec3<T>(x - value, y - value, z - value); }
123 inline Vec3<T> operator-(const Vec3<T> &v) const { return Vec3<T>(x - v.x, y - v.y, z - v.z); }
124 // Operators / and /=
125 void operator/=(const T value)
126 {
127 x /= value;
128 y /= value;
129 z /= value;
130 }
131 void operator/=(const Vec3<T> &v)
132 {
133 x /= v.x;
134 y /= v.y;
135 z /= v.z;
136 }
137 Vec3<T> operator/(const T value) const { return Vec3<T>(x / value, y / value, z / value); }
138 Vec3<T> operator/(const Vec3<T> &v) const { return Vec3<T>(x / v.x, y / v.y, z / v.z); }
139 // Operators * and *=
140 Vec3<T> operator*(const T value) const { return Vec3<T>(x * value, y * value, z * value); }
141 void operator*=(const T value)
142 {
143 x *= value;
144 y *= value;
145 z *= value;
146 }
147 Vec3<T> operator*(const Vec3<T> &v) const
148 {
149 // Cross Product
150 return Vec3<T>(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
151 }
152
153 /*
154 * Methods
155 */
156 public:
157 // Return vector of absolute elements
158 Vec3<T> abs() const { return Vec3<T>(fabs(x), fabs(y), fabs(z)); }
159 // Returns the largest absolute value of the vector
160 T absMax() const
161 {
162 T a = (fabs(x) < fabs(y)) ? fabs(y) : fabs(x);
163 return (a < fabs(z)) ? fabs(z) : a;
164 }
165 // Returns the index of the maximum absolute-valued element in the vector
166 int absMaxElement() const
167 {
168 if ((fabs(x) >= fabs(y)) && (fabs(x) >= fabs(z)))
169 return 0;
170 if ((fabs(y) >= fabs(x)) && (fabs(y) >= fabs(z)))
171 return 1;
172 return 2;
173 }
174 // Returns the smallest absolute value of the vector
175 T absMin() const
176 {
177 T a = (fabs(x) > fabs(y)) ? fabs(y) : fabs(x);
178 return (a > fabs(z)) ? fabs(z) : a;
179 }
180 // Returns the index of the minimum absolute-valued element in the vector
181 int absMinElement() const
182 {
183 if ((fabs(x) <= fabs(y)) && (fabs(x) <= fabs(z)))
184 return 0;
185 if ((fabs(y) <= fabs(x)) && (fabs(y) <= fabs(z)))
186 return 1;
187 return 2;
188 }
189 // Dot product between this and supplied vector
190 double dp(const Vec3<T> &v) const { return (x * v.x + y * v.y + z * v.z); }
191 // Normalise and return original magnitude
192 double magAndNormalise()
193 {
194 double mag = sqrt(x * x + y * y + z * z);
195 if (mag < 1.0E-8)
196 zero();
197 else
198 {
199 x /= mag;
200 y /= mag;
201 z /= mag;
202 }
203 return mag;
204 }
205 // Normalise and return original magnitude squared
206 double magSqAndNormalise()
207 {
208 double magSq = x * x + y * y + z * z;
209 double mag = sqrt(magSq);
210 if (mag < 1.0E-8)
211 zero();
212 else
213 {
214 x /= mag;
215 y /= mag;
216 z /= mag;
217 }
218 return magSq;
219 }
220 // Calculate vector magnitude
221 inline double magnitude() const { return sqrt(x * x + y * y + z * z); }
222 // Calculate square of vector magnitude
223 inline double magnitudeSq() const { return x * x + y * y + z * z; }
224 // Returns the largest value of the vector
225 T max() const
226 {
227 T a = (x < y) ? y : x;
228 return (a < z) ? z : a;
229 }
230 // Returns the maximum valued element in the vector
231 int maxElement() const
232 {
233 if ((x >= y) && (x >= z))
234 return 0;
235 if ((y >= x) && (y >= z))
236 return 1;
237 return 2;
238 }
239 // Returns the smallest value of the vector
240 T min() const
241 {
242 T a = (x > y) ? y : x;
243 return (a > z) ? z : a;
244 }
245 // Returns the minimum valued element in the vector
246 int minElement() const
247 {
248 if ((x <= y) && (x <= z))
249 return 0;
250 if ((y <= x) && (y <= z))
251 return 1;
252 return 2;
253 }
254 // Return vector with specified element adjusted
255 Vec3<T> adjusted(int element, double delta) const
256 {
257 auto newValue = *this;
258 newValue[element] += delta;
259 return newValue;
260 }
261 // Multiply elements of this vector with factors supplied
262 void multiply(double facx, double facy, double facz)
263 {
264 x *= facx;
265 y *= facy;
266 z *= facz;
267 }
268 // Multiply elements of this vector by those of supplied vector
269 void multiply(Vec3<double> v)
270 {
271 x *= v.x;
272 y *= v.y;
273 z *= v.z;
274 }
275 // Normalise the vector to unity
276 void normalise()
277 {
278 double mag = sqrt(x * x + y * y + z * z);
279 if (mag < 1.0E-8)
280 zero();
281 else
282 {
283 x /= mag;
284 y /= mag;
285 z /= mag;
286 }
287 }
288 // Returns an orthogonal, normalised unit vector
289 Vec3<T> orthogonal() const
290 {
291 Vec3<T> result;
292 const int maxComponent = absMaxElement();
293 if (maxComponent == 0)
294 {
295 // X component is largest so return XP with (0,1,0)
296 result.x = -z;
297 result.y = 0.0;
298 result.z = x;
299 }
300 else if (maxComponent == 1)
301 {
302 // Y component is largest, so return XP with (0,0,1)
303 result.x = y;
304 result.y = -x;
305 result.z = 0.0;
306 }
307 else
308 {
309 // Z component is largest, so return XP with (1,0,0)
310 result.x = 0.0;
311 result.y = z;
312 result.z = -y;
313 }
314 result.normalise();
315 return result;
316 }
317 // Orthogonalise (Gram-Schmidt) w.r.t. supplied vector
318 void orthogonalise(const Vec3<T> &reference)
319 {
320 double sourcemag = reference.magnitude();
321 double dpovermagsq = dp(reference) / (sourcemag * sourcemag);
322 x = x - dpovermagsq * reference.x;
323 y = y - dpovermagsq * reference.y;
324 z = z - dpovermagsq * reference.z;
325 }
326 // Orthogonalise (two vectors)
327 void orthogonalise(const Vec3<T> &reference1, const Vec3<T> &reference2)
328 {
329 // This routine actually generates the orthogonal vector via the cross-product
330 // We also calculate the scalar resolute (dp) to ensure the new vector points in the same direction
331 Vec3<T> newvec = reference1 * reference2;
332 newvec.normalise();
333 double dp = newvec.dp(*this);
334 if (dp < 0.0)
335 newvec *= -1.0;
336 *this = newvec;
337 }
338 // Return a unit vector along the specified direction
339 static Vec3<T> unit(int index)
340 {
341 if (index == 0)
342 return Vec3<T>(1, 0, 0);
343 else if (index == 1)
344 return Vec3<T>(0, 1, 0);
345 else if (index == 2)
346 return Vec3<T>(0, 0, 1);
347
348 throw(std::runtime_error("Vec3 - unit() generation failed - index " + std::string(index) + " is out of bounds."));
349 return Vec3<T>();
350 }
351
352 // Write a vector to a buffer
353 T *write(T *buffer)
354 {
355 *buffer++ = x;
356 *buffer++ = y;
357 *buffer++ = z;
358 return buffer;
359 }
360};
361
362const Vec3<float> xhat = Vec3<float>{1, 0, 0};
363const Vec3<float> yhat = Vec3<float>{0, 1, 0};
364const Vec3<float> zhat = Vec3<float>{0, 0, 1};
Definition vector3.h:11