dynamics_spatial/
vector3d.rs1use nalgebra::{Matrix3, Vector3};
4use std::ops::{Add, Mul, Neg, Sub};
5
6#[cfg(feature = "python")]
7use numpy::{PyReadonlyArrayDyn, ToPyArray, ndarray::Array1};
8#[cfg(feature = "python")]
9use pyo3::prelude::*;
10
11#[derive(Debug, Clone, Copy, PartialEq, Default)]
12pub struct Vector3D(pub(crate) Vector3<f64>);
14
15impl Vector3D {
16 #[must_use]
18 pub fn new(x: f64, y: f64, z: f64) -> Self {
19 Self(Vector3::new(x, y, z))
20 }
21
22 #[must_use]
24 pub fn zeros() -> Self {
25 Self(Vector3::zeros())
26 }
27
28 #[must_use]
29 pub fn as_slice(&self) -> &[f64; 3] {
30 self.0.as_slice().try_into().unwrap()
31 }
32
33 #[must_use]
35 pub fn norm(&self) -> f64 {
36 self.0.norm()
37 }
38
39 #[must_use]
41 pub fn x() -> Self {
42 Self(Vector3::x())
43 }
44
45 #[must_use]
47 pub fn y() -> Self {
48 Self(Vector3::y())
49 }
50
51 #[must_use]
53 pub fn z() -> Self {
54 Self(Vector3::z())
55 }
56
57 #[must_use]
59 pub fn cross(&self, other: &Vector3D) -> Vector3D {
60 Vector3D(self.0.cross(&other.0))
61 }
62
63 #[must_use]
64 #[cfg(feature = "python")]
65 pub fn to_numpy(&self, py: Python) -> Py<PyAny> {
67 Array1::from_iter(self.0.iter().copied())
68 .to_pyarray(py)
69 .into_any()
70 .unbind()
71 }
72
73 #[cfg(feature = "python")]
74 pub fn from_pyarray(array: &PyReadonlyArrayDyn<f64>) -> Result<Self, PyErr> {
79 let array = array.as_array();
81 if array.ndim() != 1 || array.len() != 3 {
82 return Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
83 "Input array must be one-dimensional with length 3.",
84 ));
85 }
86 Ok(Vector3D(Vector3::new(array[0], array[1], array[2])))
87 }
88
89 pub fn dot(&self, other: &Vector3D) -> f64 {
90 self.0.dot(&other.0)
91 }
92
93 pub fn skew(&self) -> Matrix3<f64> {
94 let x = self.0[0];
95 let y = self.0[1];
96 let z = self.0[2];
97 Matrix3::new(0.0, -z, y, z, 0.0, -x, -y, x, 0.0)
98 }
99}
100
101impl From<&[f64; 3]> for Vector3D {
102 fn from(array: &[f64; 3]) -> Self {
103 Vector3D(Vector3::new(array[0], array[1], array[2]))
104 }
105}
106
107impl Add for Vector3D {
108 type Output = Vector3D;
109
110 fn add(self, rhs: Self) -> Self::Output {
111 Vector3D(self.0 + rhs.0)
112 }
113}
114
115impl Sub for Vector3D {
116 type Output = Vector3D;
117
118 fn sub(self, rhs: Self) -> Self::Output {
119 Vector3D(self.0 - rhs.0)
120 }
121}
122
123impl Mul for Vector3D {
124 type Output = Vector3D;
125
126 fn mul(self, rhs: Self) -> Self::Output {
127 Vector3D(self.0.component_mul(&rhs.0))
128 }
129}
130
131impl Mul<f64> for Vector3D {
132 type Output = Vector3D;
133
134 fn mul(self, rhs: f64) -> Self::Output {
135 Vector3D(self.0 * rhs)
136 }
137}
138
139impl Mul<f64> for &Vector3D {
140 type Output = Vector3D;
141
142 fn mul(self, rhs: f64) -> Self::Output {
143 Vector3D(self.0 * rhs)
144 }
145}
146
147impl Mul<&Vector3D> for f64 {
148 type Output = Vector3D;
149
150 fn mul(self, rhs: &Vector3D) -> Self::Output {
151 Vector3D(rhs.0 * self)
152 }
153}
154
155impl Mul<Vector3D> for f64 {
156 type Output = Vector3D;
157
158 fn mul(self, rhs: Vector3D) -> Self::Output {
159 Vector3D(rhs.0 * self)
160 }
161}
162
163impl Neg for Vector3D {
164 type Output = Vector3D;
165
166 fn neg(self) -> Self::Output {
167 Vector3D(-self.0)
168 }
169}