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
use num::Num;
use basics::{pythagoras2d, pythagoras3d};
use basics::convert_trait::Convert;
use basics::amount_trait::Amount;
use std::fmt::Debug;
use std::cmp::PartialOrd;
/// Struct for three-dimensional vectors
/// # Usage
/// ```
/// use mathol::vectoroperations::vector3d::Vector3D;
/// ```
#[derive(Debug, Copy, Clone)]
pub struct Vector3D<T>
where T: Num + Copy + Convert + Amount<T> + PartialOrd
{
pub x: T,
pub y: T,
pub z: T,
}
impl<T> Vector3D<T>
where T: Num + Copy + Convert + Amount<T> + Debug + PartialOrd
{
/// Takes x, y and z values and returns a Vector3D instance
/// # Examples
/// ```
/// let vector = Vector3D::build_vector(2, 2, 1);
/// ```
pub fn build_vector(x: T, y: T, z: T) -> Vector3D<T> {
Vector3D {x, y, z}
}
/// Transforms cartesic coordinates to cylindrical coordinates.
/// # Return value
/// Returns an instance of the struct Cylindrical
/// # Examples
/// ```
/// let cart = Vector3D {x: 3.0, y: 4.0, z: 5.0};
/// let cyl = cart.transform_to_cylindrical();
/// assert_eq!(5.0, cyl.rho);
/// assert_eq!(53.13010235415598, cyl.phi);
/// assert_eq!(5.0, cyl.z);
/// ```
pub fn transform_to_cylindrical(self) -> Cylindrical<f64> {
Cylindrical {
rho: pythagoras2d(self.x, self.y),
phi: self.get_angle(),
z: self.z.to_f64(),
}
}
/// Transforms cartesic coordinates to spherical coordinates.
/// # Return value
/// Returns an instance of the struct Spherical
/// # Examples
/// ```
/// let cart = Vector3D {x: 3.0, y: 4.0, z: 5.0};
/// let sph = cart.transform_to_spherical();
/// assert_eq!(7.0710678118654755, sph.r);
/// assert_eq!(45.00000000000001, sph.theta);
/// assert_eq!(53.13010235415598, sph.phi);
/// ```
pub fn transform_to_spherical(self) -> Spherical<f64> {
let r = pythagoras3d(self.x, self.y, self.z);
Spherical {
r,
theta: (self.z.to_f64() / r).acos().to_degrees(),
phi: (self.y / self.x).to_f64().atan().to_degrees(),
}
}
/// Calculate the angle of the polar axis in relaion to the x-axis
/// # Return value
/// Returns the angle as f64 degree value
/// # Examples
pub fn get_angle(self) -> f64 {
if self.x == T::zero() {
if self.y < T::zero(){
270.0
} else if self.y > T::zero() {
90.0
} else {
0.0
}
} else {
(self.y / self.x).to_f64().atan().to_degrees()
}
}
/// Calculates the distance between two points
/// # Parameters
/// other: The second point
/// # Return values
/// Returns the distance as f64 value
/// # Examples
/// ```
/// let p = Vector3D::build_vector(1, 4, 9);
/// let q = Vector3D::build_vector(3, 7, 13);
/// assert_eq!(5.385164807, p.get_distance(q);
/// ```
pub fn get_distance(self, other: Vector3D<T>) -> f64 {
pythagoras3d(self.x - other.x, self.y - other.y, self.z - other.z)
}
/// Adds a vector to another vector
/// # Remarks
/// Returns the result of the addition as a new vector
/// # Examples
/// ```
/// let vector_1 = Vector3D::build_vector(2, 2, 1);
/// let vector_2 = Vector3D::build_vector(2, 3, 5);
/// let vector_3 = vector_1.add_vector(vector_2);
/// assert_eq!(4, vector_3.x);
/// assert_eq!(5, vector_3.y);
/// assert_eq!(6, vector_3.z);
/// ```
pub fn add_vector(self, vec: Vector3D<T>) -> Vector3D<T> {
Vector3D::build_vector(self.x + vec.x, self.y + vec.y, self.z + vec.z)
}
/// Subtracts a vector from another vector
/// # Remarks
/// Returns the result of the subtraction as a new vector
/// # Examples
/// ```
/// let vector_1 = Vector3D::build_vector(2, 2, 1);
/// let vector_2 = Vector3D::build_vector(2, 3, 5);
/// let vector_3 = vector_1.sub_vector(vector_2);
/// assert_eq!(0, vector_3.x);
/// assert_eq!(-1, vector_3.y);
/// assert_eq!(-4, vector_3.z);
/// ```
pub fn sub_vector(self, vec: Vector3D<T>) -> Vector3D<T> {
Vector3D::build_vector(self.x - vec.x, self.y - vec.y, self.z - vec.z)
}
/// Calculates the length of a vector
/// # Remarks
/// Returns the length as an f64 value
/// # Examples
/// ```
/// let vector_1 = Vector3D::build_vector(2, 3, 4);
/// assert_eq!(5.385164807134504, vector_1.get_length());
///
/// let vector_2 = Vector3D::build_vector(2.7, 3.6, 4.5);
/// assert_eq!(6.363961030678928, vector_2.get_length());
/// ```
pub fn get_length(self) -> f64 {
pythagoras3d(self.x, self.y, self.z)
}
/// Calculates the three direction angles alpha, beta and gamma of a three-dimensional vector
/// # Remarks
/// Returns a tuple with the three angles as radians
///
/// alpha is the angle of the vector to the x-axis
///
/// beta is the angle of the vector to the y-axis
///
/// gamma is the angle of the vector to the z-axis
/// # Examples
/// ```
/// let vector = Vector3D::build_vector(4, -2, 5);
/// (alpha, beta, gamma) = vector.get_direction_angle();
/// assert_eq!(0.9319311825594854, alpha);
/// assert_eq!(1.873542278417901, beta);
/// assert_eq!(0.7297276562269663, gamma);
/// ```
pub fn get_direction_angle(self) -> (f64, f64, f64) {
let n = self.get_length().to_f64();
let alpha = (self.x.to_f64() / n).acos();
let beta = (self.y.to_f64() / n).acos();
let gamma = (self.z.to_f64() / n).acos();
(alpha, beta, gamma)
}
/// Multiplies a vector with a scalar value
/// # Remarks
/// Returns the result of the multiplication as a new vector
/// # Examples
/// ```
/// let vector_1 = Vector3D::build_vector(2.7, 3.6, 4.5);
/// let vector_2 = vector_1.multiply_with_scalar(2.0)
/// assert_eq!(5.4, vector_2.x);
/// assert_eq!(7.2, vector_2.y);
/// assert_eq!(9.0, vector_2.z);
/// ```
pub fn multiply_with_scalar(self, lambda: T) -> Vector3D<T> {
Vector3D::build_vector(lambda * self.x, lambda * self.y, lambda * self.z)
}
/// Calculates the scalar product of two vectors
/// # Remarks
/// Returns the result as numeric value
/// # Examples
/// ```
/// let vector_1 = Vector3D::build_vector(2, 3, 4);
/// let vector_2 = Vector3D::build_vector(5, 6, 7);
/// assert_eq!(56, vector_1.get_scalar_product(vector_2));
/// ```
pub fn get_scalar_product(self, vec: Vector3D<T>) -> T {
self.x * vec.x + self.y * vec.y + self.z * vec.z
}
/// Calculates the angle between two crossing vectors
/// # Remarks
/// Returns the cut angle as radian value
/// # Examples
/// ```
/// let vector_1 = Vector3D::build_vector(1, 2, -3);
/// let vector_2 = Vector3D::build_vector(5, -1, -5);
/// assert_eq!(0.6736330697086078, vector_1.get_cut_angle(vector_2));
/// ```
pub fn get_cut_angle(self, vec: Vector3D<T>) -> f64 {
self.get_scalar_product(vec).to_f64() / (self.get_length().to_f64() * vec.get_length().to_f64())
}
/// Calculates the vector product of two vectors
/// # Remarks
/// Returns the result as a new vector
/// # Examples
/// ```
/// let vector_1 = Vector3D::build_vector(1, 4, 0);
/// let vector_2 = Vector3D::build_vector(-2, 5, 3);
/// let vec_product = vector_1.get_vector_product(vector_2);
/// assert_eq!(12, vec_product.x);
/// assert_eq!(-3, vec_product.y);
/// assert_eq!(13, vec_product.z);
/// ```
pub fn get_vector_product(self, vec: Vector3D<T>) -> Vector3D<T> {
Vector3D::build_vector(self.y * vec.z - self.z * vec.y, self.z * vec.x - self.x * vec.z, self.x * vec.y - self.y * vec.x)
}
/// Calculates the triple product of three vectors
/// # Remarks
/// Returns the result as numeric value
/// # Examples
/// ```
/// let vector_1 = Vector3D::build_vector(1, -2, 4);
/// let vector_2 = Vector3D::build_vector(4, 1, 2);
/// let vector_3 = Vector3D::build_vector(-2, -5, -6);
/// assert_eq!(0, vector_1.get_triple_product(vector_2, vector_3));
/// ```
pub fn get_triple_product(self, vec_1: Vector3D<T>, vec_2: Vector3D<T>) -> T {
self.x * (vec_1.y * vec_2.z - vec_1.z * vec_2.y) + self.y * (vec_1.z * vec_2.x - vec_1.x * vec_2.z) + self.z * (vec_1.x * vec_2.y - vec_1.y * vec_2.x)
}
}
/// Rust struct for points in the cylindrical coordinate system.
#[derive(Debug, Copy, Clone)]
pub struct Cylindrical<T>
where T: Num + Copy + Convert + Amount<T>
{
/// Distance from z-axis to the point
pub rho: T,
/// Angle between the reference direction on the chosen plane and the line from the origin to the projection of P on the plane
pub phi: T,
/// Signed distance from the chosen plane to the point P
pub z: T,
}
impl<T> Cylindrical<T>
where T: Num + Copy + Convert + Amount<T>
{
/// Transforms cylindrical coordinates to cartesic coordinates.
/// Returns an instance of the struct Cartesic
pub fn transform_to_vector3d(&self) -> Vector3D<f64> {
Vector3D {
x: self.rho.to_f64() * self.phi.to_f64().to_radians().cos(),
y: self.rho.to_f64() * self.phi.to_f64().to_radians().sin(),
z: self.z.to_f64(),
}
}
}
/// Rust struct for points in the spherical coordinate system.
#[derive(Debug, Copy, Clone)]
pub struct Spherical<T>
where T: Num + Copy + Convert + Amount<T>
{
/// Distance from the origin point
pub r: T,
/// Signed angle measured from the azimuth reference direction to the orthogonal projection of the line segment on the reference plane
pub theta: T,
/// Angle between the zenith direction and the line segment
pub phi: T,
}
impl<T> Spherical<T>
where T: Num + Copy + Convert + Amount<T>
{
/// Transforms spherical coordinates to cartesic coordinates.
/// Returns an instance of the struct Cartesic
pub fn transform_to_vector3d(&self) -> Vector3D<f64> {
Vector3D {
x: self.r.to_f64() * self.theta.to_f64().to_radians().sin() * self.phi.to_f64().to_radians().cos(),
y: self.r.to_f64() * self.theta.to_f64().to_radians().sin() * self.phi.to_f64().to_radians().sin(),
z: self.r.to_f64() * self.theta.to_f64().to_radians().cos(),
}
}
}