Skip to main content

geop_core_math/vector/
linalg.rs

1use crate::{
2    geop_error::{GeopError, GeopResult},
3    scalars::Scalar,
4    vector::{Vector, Vector3},
5};
6
7impl<S: Scalar, const N: usize> Vector<S, N> {
8    pub fn add(&self, other: &Self) -> Self {
9        let mut out = Self::new();
10        for i in 0..self.size() {
11            out[i] = self[i].add(other[i]);
12        }
13        out
14    }
15
16    pub fn sub(&self, other: &Self) -> Self {
17        let mut out = Self::new();
18        for i in 0..self.size() {
19            out[i] = self[i].sub(other[i]);
20        }
21        out
22    }
23
24    pub fn neg(&self) -> Self {
25        let mut out = Self::new();
26        for i in 0..self.size() {
27            out[i] = self[i].neg();
28        }
29        out
30    }
31
32    /// Componentwise [`Scalar::sharpen`] — see that method's own doc
33    /// comment for when collapsing a value to a single representative
34    /// point is a safe, free choice (you only ever needed *some* point
35    /// within the interval) versus a silent loss of real uncertainty.
36    pub fn sharpen(&self) -> Self {
37        let mut out = Self::new();
38        for i in 0..self.size() {
39            out[i] = self[i].sharpen();
40        }
41        out
42    }
43
44    /// Componentwise [`Scalar::interpolate`]: `a` at `alpha=0`, `b` at
45    /// `alpha=1`. See that method's doc comment for why this beats a manual
46    /// `a*(1-alpha) + b*alpha` when components of `a`/`b` may coincide.
47    pub fn interpolate(a: &Self, b: &Self, alpha: S) -> Self {
48        let mut out = Self::new();
49        for i in 0..a.size() {
50            out[i] = S::interpolate(a[i], b[i], alpha);
51        }
52        out
53    }
54
55    pub fn prod_scalar(&self, s: S) -> Self {
56        let mut out = Self::new();
57        for i in 0..self.size() {
58            out[i] = self[i].mul(s);
59        }
60        out
61    }
62
63    pub fn prod_dot(&self, other: &Self) -> S {
64        let mut acc = S::ZERO;
65        for i in 0..self.size() {
66            acc = acc.add(self[i].mul(other[i]));
67        }
68        acc
69    }
70
71    pub fn norm_sq(&self) -> S {
72        self.prod_dot(self)
73    }
74
75    pub fn norm(&self) -> S {
76        self.norm_sq().sqrt().expect("Norm cannot be negative")
77    }
78
79    pub fn normalize(&self) -> GeopResult<Self> {
80        let n = self.norm();
81        if n.could_be_equal(S::ZERO) {
82            return Err(GeopError::new("Cannot normalize zero-length vector"));
83        }
84        Ok(self.prod_scalar(S::ONE.div(n)?))
85    }
86
87    /// True if every component `could_be_equal` `other`'s.
88    pub fn could_be_equal(&self, other: &Self) -> bool {
89        (0..self.size()).all(|i| self[i].could_be_equal(other[i]))
90    }
91
92    /// The componentwise [`Scalar::union`] of `self` and `other`.
93    pub fn union(&self, other: &Self) -> Self {
94        let mut out = Self::new();
95        for i in 0..self.size() {
96            out[i] = self[i].union(other[i]);
97        }
98        out
99    }
100}
101
102impl<S: Scalar> Vector3<S> {
103    pub fn prod_cross(&self, other: &Self) -> Self {
104        let mut out = Self::new();
105        out[0] = self[1].mul(other[2]).sub(self[2].mul(other[1]));
106        out[1] = self[2].mul(other[0]).sub(self[0].mul(other[2]));
107        out[2] = self[0].mul(other[1]).sub(self[1].mul(other[0]));
108        out
109    }
110}