JSim 2026.06.01-p(1)
Loading...
Searching...
No Matches
vector.hpp
Go to the documentation of this file.
1// Copyright (c) JSim contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the LGPLv3 license file in the root directory of this project.
4
5#pragma once
6#include <cmath>
7#include <algorithm>
8#include <iostream>
9#include <cassert>
10#include <limits>
11#include <iomanip>
12
13namespace frcsim {
14
22struct alignas(16) Vector3 {
24 double x;
26 double y;
28 double z;
29
31 constexpr Vector3() noexcept : x(0.0), y(0.0), z(0.0) {}
38 constexpr Vector3(double x_, double y_, double z_) noexcept
39 : x(x_), y(y_), z(z_) {}
40 constexpr Vector3(const Vector3&) noexcept = default;
41 constexpr Vector3(Vector3&&) noexcept = default;
42 constexpr Vector3& operator=(const Vector3&) noexcept = default;
43 constexpr Vector3& operator=(Vector3&&) noexcept = default;
44
46 constexpr Vector3 operator+(const Vector3& o) const noexcept {
47 return {x + o.x, y + o.y, z + o.z};
48 }
49
50 constexpr Vector3 operator-(const Vector3& o) const noexcept {
51 return {x - o.x, y - o.y, z - o.z};
52 }
53
54 constexpr Vector3 operator*(double s) const noexcept {
55 return {x * s, y * s, z * s};
56 }
57
61 constexpr Vector3 operator/(double s) const noexcept {
62 return (std::abs(s) > std::numeric_limits<double>::epsilon())
63 ? Vector3{x / s, y / s, z / s}
64 : Vector3{};
65 }
66
67 Vector3& operator+=(const Vector3& o) noexcept {
68 x += o.x;
69 y += o.y;
70 z += o.z;
71 return *this;
72 }
73
74 Vector3& operator-=(const Vector3& o) noexcept {
75 x -= o.x;
76 y -= o.y;
77 z -= o.z;
78 return *this;
79 }
80
81 Vector3& operator*=(double s) noexcept {
82 x *= s;
83 y *= s;
84 z *= s;
85 return *this;
86 }
87
91 Vector3& operator/=(double s) noexcept {
92 if (std::abs(s) > std::numeric_limits<double>::epsilon()) {
93 x /= s;
94 y /= s;
95 z /= s;
96 } else {
97 x = y = z = 0.0;
98 }
99 return *this;
100 }
101
103 constexpr bool operator==(const Vector3& o) const noexcept {
104 return x == o.x && y == o.y && z == o.z;
105 }
106
107 constexpr bool operator!=(const Vector3& o) const noexcept {
108 return !(*this == o);
109 }
110
112 constexpr double norm2() const noexcept { return x * x + y * y + z * z; }
114 double norm() const noexcept { return std::sqrt(norm2()); }
119 Vector3 normalized() const noexcept {
120 double n = norm();
121 return (n > std::numeric_limits<double>::epsilon()) ? (*this) / n
122 : Vector3{};
123 }
124
128 constexpr bool isZero(double eps = 1e-12) const noexcept {
129 return norm2() < eps * eps;
130 }
131
132 bool hasNaN() const noexcept {
133 return std::isnan(x) || std::isnan(y) || std::isnan(z);
134 }
135
136 static Vector3 fromArray(const double arr[3]) noexcept {
137 return Vector3(arr[0], arr[1], arr[2]);
138 }
139
140 void toArray(double arr[3]) const noexcept {
141 arr[0] = x;
142 arr[1] = y;
143 arr[2] = z;
144 }
145
146 static double distance(const Vector3& a, const Vector3& b) noexcept {
147 return (a - b).norm();
148 }
149
152 Vector3 clamp(const Vector3& min, const Vector3& max) const noexcept {
153 return Vector3(std::max(min.x, std::min(x, max.x)),
154 std::max(min.y, std::min(y, max.y)),
155 std::max(min.z, std::min(z, max.z)));
156 }
157
163 static Vector3 lerp(const Vector3& a, const Vector3& b, double t) noexcept {
164 return a * (1.0 - t) + b * t;
165 }
166
168 constexpr double dot(const Vector3& o) const noexcept {
169 return x * o.x + y * o.y + z * o.z;
170 }
171
172 Vector3 cross(const Vector3& o) const noexcept {
173 return {y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x};
174 }
175
177 double planarSpeed() const noexcept { return std::sqrt(x * x + y * y); }
179 constexpr Vector3 xy() const noexcept { return {x, y, 0.0}; }
184 Vector3 planarDir() const noexcept {
185 double mag = planarSpeed();
186 return (mag > std::numeric_limits<double>::epsilon())
187 ? Vector3{x / mag, y / mag, 0.0}
188 : Vector3{};
189 }
190
196 Vector3 projectOnto(const Vector3& axis) const noexcept {
197 double denom = axis.norm2();
198 if (denom < std::numeric_limits<double>::epsilon())
199 return Vector3{};
200 return axis * (dot(axis) / denom);
201 }
202
208 Vector3 reflect(const Vector3& n) const noexcept {
209 return *this - n * (2.0 * dot(n));
210 }
211
217 Vector3 torque(const Vector3& r) const noexcept { return r.cross(*this); }
218
226 static Vector3 magnusForce(const Vector3& velocity, const Vector3& omega,
227 double k = 1e-4) noexcept {
228 return omega.cross(velocity) * k;
229 }
230
234 struct DragVector {
236 double x{0.0};
238 double y{0.0};
240 double z{0.0};
241
243 bool isZero(double eps = 1e-12) const noexcept {
244 return std::abs(x) < eps && std::abs(y) < eps && std::abs(z) < eps;
245 }
246 };
247
277
288 const Vector3& v, double Cd, double A, double rho = 1.225,
289 double linear_drag_coefficient_n_per_mps = 0.0) noexcept {
290 DragForceDetails details{};
291 details.drag_coefficient = Cd;
292 details.reference_area_m2 = A;
293 details.cross_section_area_m2 = A;
294 details.air_density_kgpm3 = rho;
296 linear_drag_coefficient_n_per_mps;
297 details.quadratic_drag_coefficient_n_per_mps2 = 0.5 * rho * Cd * A;
298
299 if (!std::isfinite(v.x) || !std::isfinite(v.y) || !std::isfinite(v.z) ||
300 !std::isfinite(Cd) || !std::isfinite(A) || !std::isfinite(rho) ||
301 !std::isfinite(linear_drag_coefficient_n_per_mps)) {
302 return details;
303 }
304
305 details.speed_mps = v.norm();
306 details.speed_squared_mps2 = details.speed_mps * details.speed_mps;
307
308 if (details.speed_mps <= std::numeric_limits<double>::epsilon() ||
309 Cd <= 0.0 || A <= 0.0 || rho <= 0.0 ||
310 linear_drag_coefficient_n_per_mps < 0.0) {
311 return details;
312 }
313
314 details.direction = {v.x / details.speed_mps, v.y / details.speed_mps,
315 v.z / details.speed_mps};
316 details.dynamic_pressure_pa = 0.5 * rho * details.speed_squared_mps2;
317 const double linear_force_n =
318 linear_drag_coefficient_n_per_mps * details.speed_mps;
319 const double quadratic_force_n = details.dynamic_pressure_pa * Cd * A;
320 const double force_magnitude_n = linear_force_n + quadratic_force_n;
321 details.drag_force_magnitude_n = force_magnitude_n;
322 details.force = {details.direction.x * (-force_magnitude_n),
323 details.direction.y * (-force_magnitude_n),
324 details.direction.z * (-force_magnitude_n)};
325 details.valid = true;
326 return details;
327 }
328
337 static Vector3 dragForce(const Vector3& v, double Cd, double A,
338 double rho = 1.225) noexcept {
339 const auto details = dragForceDetailed(v, Cd, A, rho);
340 return Vector3(details.force.x, details.force.y, details.force.z);
341 }
342
352 static Vector3 dynamicGravity(const Vector3& velocity, const Vector3& spin,
353 double g = 9.81, double magnusCoeff = 1e-4,
354 double gravityEffect = 1.0) noexcept {
355 Vector3 magnus = magnusForce(velocity, spin, magnusCoeff);
356 return Vector3(0.0, 0.0, -g * gravityEffect) + magnus;
357 }
358
360 static constexpr Vector3 zero() noexcept { return Vector3(0.0, 0.0, 0.0); }
361
363 constexpr Vector3 operator-() const noexcept { return Vector3(-x, -y, -z); }
364
370 double& operator[](size_t i) {
371 assert(i < 3 && "Vector3 index out of bounds");
372 return i == 0 ? x : i == 1 ? y : z;
373 }
374
379 const double& operator[](size_t i) const {
380 assert(i < 3 && "Vector3 index out of bounds");
381 return i == 0 ? x : i == 1 ? y : z;
382 }
383
385 friend std::ostream& operator<<(std::ostream& os, const Vector3& v) {
386 os << std::fixed << std::setprecision(4) << "[" << v.x << ", " << v.y
387 << ", " << v.z << "]";
388 return os;
389 }
390
392 static constexpr Vector3 unitX() noexcept { return Vector3(1.0, 0.0, 0.0); }
394 static constexpr Vector3 unitY() noexcept { return Vector3(0.0, 1.0, 0.0); }
396 static constexpr Vector3 unitZ() noexcept { return Vector3(0.0, 0.0, 1.0); }
397
405 static Vector3 tractionForce(const Vector3& normal, double frictionCoeff,
406 double normalForce) noexcept {
407 return normal * (frictionCoeff * normalForce);
408 }
409};
410
412inline Vector3 operator*(double s, const Vector3& v) noexcept {
413 return v * s;
414}
415
416} // namespace frcsim
Definition vector.hpp:13
Vector3 operator*(double s, const Vector3 &v) noexcept
Left scalar multiplication helper (s * v).
Definition vector.hpp:412
Expanded drag diagnostics for force computation.
Definition vector.hpp:249
DragVector force
Drag force vector in newtons.
Definition vector.hpp:251
double cross_section_area_m2
Effective cross-sectional area in square meters.
Definition vector.hpp:265
double drag_force_magnitude_n
Total drag magnitude in newtons.
Definition vector.hpp:273
double dynamic_pressure_pa
Dynamic pressure in pascals.
Definition vector.hpp:259
double quadratic_drag_coefficient_n_per_mps2
Quadratic drag term coefficient in N/(m/s)^2.
Definition vector.hpp:271
double linear_drag_coefficient_n_per_mps
Linear drag term coefficient in N/(m/s).
Definition vector.hpp:269
double speed_mps
Speed magnitude in meters per second.
Definition vector.hpp:255
DragVector direction
Unit direction of velocity, undefined when speed is zero.
Definition vector.hpp:253
bool valid
True when the provided inputs were valid for drag evaluation.
Definition vector.hpp:275
double air_density_kgpm3
Air density in kilograms per cubic meter.
Definition vector.hpp:267
double reference_area_m2
Reference area in square meters.
Definition vector.hpp:263
double speed_squared_mps2
Squared speed in $(m/s)^2$.
Definition vector.hpp:257
double drag_coefficient
Drag coefficient used in the calculation.
Definition vector.hpp:261
Directional drag force vector and validity metadata.
Definition vector.hpp:234
double y
Y component.
Definition vector.hpp:238
double z
Z component.
Definition vector.hpp:240
double x
X component.
Definition vector.hpp:236
bool isZero(double eps=1e-12) const noexcept
Returns true when all components are within eps of zero.
Definition vector.hpp:243
3D vector utility used throughout JSim physics.
Definition vector.hpp:22
constexpr bool operator!=(const Vector3 &o) const noexcept
Exact component-wise inequality comparison.
Definition vector.hpp:107
Vector3 clamp(const Vector3 &min, const Vector3 &max) const noexcept
Clamps each component into the inclusive [min, max] range.
Definition vector.hpp:152
constexpr Vector3() noexcept
Constructs a zero vector.
Definition vector.hpp:31
double norm() const noexcept
Returns Euclidean magnitude.
Definition vector.hpp:114
Vector3 reflect(const Vector3 &n) const noexcept
Reflects this vector across a normalized plane normal.
Definition vector.hpp:208
static constexpr Vector3 unitY() noexcept
Returns the +Y basis vector.
Definition vector.hpp:394
Vector3 normalized() const noexcept
Returns the normalized direction vector.
Definition vector.hpp:119
static double distance(const Vector3 &a, const Vector3 &b) noexcept
Returns Euclidean distance between two vectors treated as points.
Definition vector.hpp:146
Vector3 cross(const Vector3 &o) const noexcept
Returns cross product with o.
Definition vector.hpp:172
double z
Z component.
Definition vector.hpp:28
static constexpr Vector3 unitX() noexcept
Returns the +X basis vector.
Definition vector.hpp:392
friend std::ostream & operator<<(std::ostream &os, const Vector3 &v)
Streams the vector in a fixed-width bracketed format.
Definition vector.hpp:385
constexpr Vector3 operator-() const noexcept
Returns the additive inverse of this vector.
Definition vector.hpp:363
constexpr Vector3 operator-(const Vector3 &o) const noexcept
Returns component-wise difference.
Definition vector.hpp:50
static Vector3 fromArray(const double arr[3]) noexcept
Builds a vector from a 3-element array.
Definition vector.hpp:136
constexpr double norm2() const noexcept
Returns squared magnitude: $x^2+y^2+z^2$.
Definition vector.hpp:112
static constexpr Vector3 unitZ() noexcept
Returns the +Z basis vector.
Definition vector.hpp:396
static Vector3 tractionForce(const Vector3 &normal, double frictionCoeff, double normalForce) noexcept
Computes a traction/friction force aligned with the supplied normal.
Definition vector.hpp:405
constexpr double dot(const Vector3 &o) const noexcept
Returns dot product with o.
Definition vector.hpp:168
Vector3 planarDir() const noexcept
Returns normalized XY direction with z=0.
Definition vector.hpp:184
constexpr Vector3(const Vector3 &) noexcept=default
double planarSpeed() const noexcept
Returns magnitude of the XY projection.
Definition vector.hpp:177
static Vector3 dragForce(const Vector3 &v, double Cd, double A, double rho=1.225) noexcept
Computes the total drag force vector for a velocity and body.
Definition vector.hpp:337
Vector3 torque(const Vector3 &r) const noexcept
Computes torque from a force applied at offset r.
Definition vector.hpp:217
constexpr Vector3(Vector3 &&) noexcept=default
Vector3 & operator*=(double s) noexcept
Multiplies each component by s.
Definition vector.hpp:81
Vector3 & operator+=(const Vector3 &o) noexcept
Adds o component-wise into this vector.
Definition vector.hpp:67
void toArray(double arr[3]) const noexcept
Writes components to a 3-element array.
Definition vector.hpp:140
static constexpr Vector3 zero() noexcept
Returns the zero vector.
Definition vector.hpp:360
static Vector3 lerp(const Vector3 &a, const Vector3 &b, double t) noexcept
Linearly interpolates from a to b.
Definition vector.hpp:163
constexpr Vector3 xy() const noexcept
Returns this vector projected onto the XY plane (z=0).
Definition vector.hpp:179
double & operator[](size_t i)
Returns a mutable component by index.
Definition vector.hpp:370
constexpr Vector3 operator/(double s) const noexcept
Returns this vector divided by a scalar.
Definition vector.hpp:61
double x
X component.
Definition vector.hpp:24
const double & operator[](size_t i) const
Returns a const component by index.
Definition vector.hpp:379
constexpr Vector3(double x_, double y_, double z_) noexcept
Constructs a vector from component values.
Definition vector.hpp:38
constexpr bool operator==(const Vector3 &o) const noexcept
Exact component-wise equality comparison.
Definition vector.hpp:103
bool hasNaN() const noexcept
Returns true when any component is NaN.
Definition vector.hpp:132
static Vector3 dynamicGravity(const Vector3 &velocity, const Vector3 &spin, double g=9.81, double magnusCoeff=1e-4, double gravityEffect=1.0) noexcept
Combines gravity with an optional Magnus lift contribution.
Definition vector.hpp:352
constexpr bool isZero(double eps=1e-12) const noexcept
Checks whether the vector is near zero magnitude.
Definition vector.hpp:128
static DragForceDetails dragForceDetailed(const Vector3 &v, double Cd, double A, double rho=1.225, double linear_drag_coefficient_n_per_mps=0.0) noexcept
Computes drag force details for a body moving through air.
Definition vector.hpp:287
Vector3 projectOnto(const Vector3 &axis) const noexcept
Projects this vector onto another axis.
Definition vector.hpp:196
Vector3 & operator/=(double s) noexcept
Divides each component by s.
Definition vector.hpp:91
static Vector3 magnusForce(const Vector3 &velocity, const Vector3 &omega, double k=1e-4) noexcept
Computes the Magnus lift force omega x v scaled by k.
Definition vector.hpp:226
double y
Y component.
Definition vector.hpp:26
constexpr Vector3 operator*(double s) const noexcept
Returns this vector scaled by a scalar.
Definition vector.hpp:54
Vector3 & operator-=(const Vector3 &o) noexcept
Subtracts o component-wise from this vector.
Definition vector.hpp:74