-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjartsyla.h
326 lines (285 loc) · 12.1 KB
/
jartsyla.h
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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
#ifndef JARTSY_LA_H
#define JARTSY_LA_H
#include "jartsy.h"
// All the linear algebra stuff, vectors, quaternions, transforms, points ...
// Stolen, borrowed, ideas from SolveSpace
class Vector {
public:
Float x, y, z;
inline Vector operator-() const { return {-x, -y, -z}; }
inline auto operator[](int i) {
switch(i) {
case 0: return x;
case 1: return y;
case 2: return z;
default: jartsyassert(false, "Unexpected vector element index");
}
}
inline auto &operator+=(const Vector &v) {
x += v.x;
y += v.y;
z += v.z;
return *this;
}
inline auto &operator-=(const Vector &v) { return *this += -v; }
inline auto &operator*=(const Float t) {
x *= t;
y *= t;
z *= t;
return *this;
}
inline auto &operator/=(const Float t) { return *this *= (1 / t); }
inline bool operator==(const Vector &v) const { return x == v.x && y == v.y && z == v.z; }
// Should this or the operator== be the exact comparison? Which one will I use more often?
inline bool EqualsExactly(const Vector &v) const { return x == v.x && y == v.y && z == v.z; };
inline Vector operator+(const Vector &v) const { return {x + v.x, y + v.y, z + v.z}; }
inline Vector operator-(const Vector &v) const { return {x - v.x, y - v.y, z - v.z}; }
inline Vector operator*(const Float t) const { return {x * t, y * t, z * t}; }
inline auto operator/(const Float &t) const { return *this * (1 / t); }
// The element wize vector multiplication I need ffor the scaling operation
inline Vector operator*(const Vector &v) const { return {x * v.x, y * v.y, z * v.z}; }
inline Vector Cross(const Vector &v) const {
return {-(z * v.y) + (y * v.z), (z * v.x) - (x * v.z), -(y * v.x) + (x * v.y)};
}
inline auto Dot(const Vector &v) const { return (x * v.x + y * v.y + z * v.z); }
inline auto MagSquared() const { return x * x + y * y + z * z; }
inline auto Magnitude() const { return (Float)sqrt(x * x + y * y + z * z); }
inline Vector WithMagnitude(Float t) const {
Float m = Magnitude();
if(EXACT(0 == m)) {
// We can do a zero vector with zero magnitude, but not any other cases.
if(fabs(t) > 1e-100) {
dbp("Vector::WithMagnitude(%g) of zero vector!", t);
}
return {0, 0, 0};
} else {
return *this * (t / m);
}
}
/* Float DirectionCosineWith(Vector b) const;
static Vector AtIntersectionOfPlanes(Vector n1, Float d1, Vector n2, Float d2);
static Vector AtIntersectionOfLines(Vector a0, Vector a1, Vector b0, Vector b1, bool *skew,
Float *pa = NULL, Float *pb = NULL);
static Vector AtIntersectionOfPlaneAndLine(Vector n, Float d, Vector p0, Vector p1,
bool *parallel);
static Vector AtIntersectionOfPlanes(Vector na, Float da, Vector nb, Float db, Vector nc,
Float dc, bool *parallel);
static void ClosestPointBetweenLines(Vector pa, Vector da, Vector pb, Vector db, Float *ta,
Float *tb);
Vector Normal(int which) const;
Vector RotatedAbout(Vector orig, Vector axis, Float theta) const;
Vector RotatedAbout(Vector axis, Float theta) const;
Vector DotInToCsys(Vector u, Vector v, Vector n) const;
Vector ScaleOutOfCsys(Vector u, Vector v, Vector n) const;
Float DistanceToLine(Vector p0, Vector dp) const;
Float DistanceToPlane(Vector normal, Vector origin) const;
bool OnLineSegment(Vector a, Vector b, Float tol = LENGTH_EPS) const;
Vector ClosestPointOnLine(Vector p0, Vector deltal) const;
Vector ProjectInto(hEntity wrkpl) const;
Vector ProjectVectorInto(hEntity wrkpl) const;
Float DivProjected(Vector delta) const;
Vector ClosestOrtho() const;
void MakeMaxMin(Vector *maxv, Vector *minv) const;
Vector ClampWithin(Float minv, Float maxv) const;
static bool BoundingBoxesDisjoint(Vector amax, Vector amin, Vector bmax, Vector bmin);
static bool BoundingBoxIntersectsLine(Vector amax, Vector amin, Vector p0, Vector p1,
bool asSegment);
bool OutsideAndNotOn(Vector maxv, Vector minv) const;
Vector InPerspective(Vector u, Vector v, Vector n, Vector origin, Float cameraTan) const;
Point2d Project2d(Vector u, Vector v) const;
Point2d ProjectXy() const;
Vector4 Project4d() const;
*/
};
inline Vector operator*(const Float t, const Vector &v) {
return v * t;
}
using Point = Vector; // Meeh this is not quite nice but anyway :-)
using Normal = Vector;
class Quaternion {
public:
// w + (v.x)*i + (v.y)*j + (v.z)*k
Vector v;
Float w = 1; // Make the default quaternion identity {{0, 0, 0}, 1}
inline Quaternion operator-() const { return {-v, -w}; }
inline Quaternion &operator+=(const Quaternion &q) { v += q.v; w += q.w; return *this; }
inline auto operator-=(const Quaternion &q) { return *this += -q; }
inline auto operator*=(const Float t) { v *= t; w *= t; return *this; }
inline auto &operator/=(const Float t) { return *this *= (1 / t); }
inline bool operator==(const Quaternion &q) const { return v == q.v && w == q.w; }
// Should this or the operator== be the exact comparison? Which one will I use more often?
inline bool EqualsExactly(const Quaternion &q) const { return v == q.v && w == q.w; };
inline Quaternion operator+(const Quaternion &q) const { return {v + q.v, w + q.w}; }
inline Quaternion operator-(const Quaternion &q) const { return {v - q.v, w - q.w}; }
inline Quaternion operator*(const Float &t) const { return {v * t, w * t}; }
inline auto operator/(const Float &t) const { return *this * (1 / t); }
inline auto MagSquared() const { return v.MagSquared() + w * w; }
inline auto Magnitude() const { return sqrt(MagSquared()); }
inline Quaternion WithMagnitude(Float t) const {
Float m = Magnitude();
if(EXACT(0 == m)) {
// We can do a zero Quaternion with zero magnitude, but not any other cases.
if(fabs(t) > 1e-100) {
dbp("Quaternion::WithMagnitude(%g) of zero Quaternion!", t);
}
return {{0, 0, 0}, 0};
} else {
return *this * (t / m);
}
}
inline Vector RotationU() const {
return {w * w + v.x * v.x - v.y * v.y - v.z * v.z,
2 * w * v.z + 2 * v.x * v.y,
2 * v.x * v.z - 2 * w * v.y};
}
inline Vector RotationV() const {
return {2 * v.x * v.y - 2 * w * v.z,
w * w - v.x * v.x + v.y * v.y - v.z * v.z,
2 * w * v.x + 2 * v.y * v.z};
}
inline Vector RotationN() const {
return {2 * w * v.y + 2 * v.x * v.z,
2 * v.y * v.z - 2 * w * v.x,
w * w - v.x * v.x - v.y * v.y + v.z * v.z};
}
inline Vector operator()(const Vector p) const {
// Rotate a vector according to the quaternion
// Express the vector in the new basis
return RotationU() * p.x + RotationV() * p.y + RotationN() * p.z;
}
static Quaternion From(Vector axis, Float dtheta) {
Float c = cos(dtheta / 2), s = sin(dtheta / 2);
axis = axis.WithMagnitude(s);
return {axis, c};
}
static Quaternion From(Vector u, Vector v) {
Vector n = u.Cross(v);
Quaternion q;
double s, tr = 1 + u.x + v.y + n.z;
if(tr > 1e-4) {
s = 2 * sqrt(tr);
q.w = s / 4;
q.v.x = (v.z - n.y) / s;
q.v.y = (n.x - u.z) / s;
q.v.z = (u.y - v.x) / s;
} else {
if(u.x > v.y && u.x > n.z) {
s = 2 * sqrt(1 + u.x - v.y - n.z);
q.w = (v.z - n.y) / s;
q.v.x = s / 4;
q.v.y = (u.y + v.x) / s;
q.v.z = (n.x + u.z) / s;
} else if(v.y > n.z) {
s = 2 * sqrt(1 - u.x + v.y - n.z);
q.w = (n.x - u.z) / s;
q.v.x = (u.y + v.x) / s;
q.v.y = s / 4;
q.v.z = (v.z + n.y) / s;
} else {
s = 2 * sqrt(1 - u.x - v.y + n.z);
q.w = (u.y - v.x) / s;
q.v.x = (n.x + u.z) / s;
q.v.y = (v.z + n.y) / s;
q.v.z = s / 4;
}
}
return q.WithMagnitude(1);
}
// Quaternion from a 3x3 rotation matrix, rows u, v, n
static Quaternion From(Vector u, Vector v, Vector n) {
Quaternion q;
double s, tr = 1 + u.x + v.y + n.z;
if(tr > 1e-4) {
s = 2 * sqrt(tr);
q.w = s / 4;
q.v.x = (v.z - n.y) / s;
q.v.y = (n.x - u.z) / s;
q.v.z = (u.y - v.x) / s;
} else {
if(u.x > v.y && u.x > n.z) {
s = 2 * sqrt(1 + u.x - v.y - n.z);
q.w = (v.z - n.y) / s;
q.v.x = s / 4;
q.v.y = (u.y + v.x) / s;
q.v.z = (n.x + u.z) / s;
} else if(v.y > n.z) {
s = 2 * sqrt(1 - u.x + v.y - n.z);
q.w = (n.x - u.z) / s;
q.v.x = (u.y + v.x) / s;
q.v.y = s / 4;
q.v.z = (v.z + n.y) / s;
} else {
s = 2 * sqrt(1 - u.x - v.y + n.z);
q.w = (u.y - v.x) / s;
q.v.x = (n.x + u.z) / s;
q.v.y = (v.z + n.y) / s;
q.v.z = s / 4;
}
}
return q.WithMagnitude(1);
}
};
class Transform {
public:
// Transform Private Members
Vector t; // Translate XYZ
Quaternion r; // Rotate
Vector s = {1, 1, 1}; // Scale XYZ
// Or maybe a 4x4 transformation matrix directly?
inline Vector operator()(const Vector &v) const {
// PAR@@@@@@ Sequence of operations?
return r(v*s+t);
}
// PAR@@@ transform multiplication?
};
template<typename T>
class Vector2 {
public:
T x, y;
inline Vector2 operator-() const { return {-x, -y}; }
inline auto operator[](int i) {
switch(i) {
case 0: return x;
case 1: return y;
default: jartsyassert(false, "Unexpected Vector2 element index");
}
}
inline auto &operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; }
inline auto &operator-=(const Vector2 &v) { return *this += -v; }
inline auto &operator*=(const T t) { x *= t; y *= t; return *this; }
inline auto &operator/=(const T t) { return *this *= (1 / t); }
inline bool operator==(const Vector2 &v) const { return x == v.x && y == v.y; }
// Should this or the operator== be the exact comparison? Which one will I use more often?
inline bool EqualsExactly(const Vector2 &v) const { return x == v.x && y == v.y; };
inline Vector2 operator+(const Vector2 &v) const { return { x + v.x, y + v.y}; }
inline Vector2 operator-(const Vector2 &v) const { return { x - v.x, y - v.y}; }
inline Vector2 operator*(const T &t) const { return { x * t, y * t }; }
inline auto operator/(const T &t) const { return *this * (1 / t); }
inline auto Dot(const Vector2 &v) const { return (x * v.x + y * v.y); }
inline auto MagSquared() const { return x * x + y * y; }
inline auto Magnitude() const { return sqrt(x * x + y * y); }
inline Vector2 WithMagnitude(T t) const {
T m = Magnitude();
if(EXACT(0 == m)) {
// We can do a zero Vector2 with zero magnitude, but not any other cases.
if(fabs(t) > 1e-100) {
dbp("Vector2::WithMagnitude(%g) of zero Vector2!", t);
}
return {0, 0};
} else {
return *this * (t / m);
}
}
};
using Vector2f = Vector2<Float>;
using Point2f = Vector2f;
using Point2i = Vector2<int>;
// Linearly interpolates a vale t in [0,1] to a value in the range [a,b]
// Didn't know this was called a LERP :-)
// https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html
// Should woork with all fo the above. Untested.
template<typename T>
inline T Lerp(Float t, T a, T b) {
return (1 - t) * a + t * b;
}
#endif