1use chematic_core::AtomIdx;
4
5#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Point3 {
8 pub x: f64,
9 pub y: f64,
10 pub z: f64,
11}
12
13impl Point3 {
14 #[inline]
16 pub fn new(x: f64, y: f64, z: f64) -> Self {
17 Self { x, y, z }
18 }
19
20 #[inline]
22 pub fn zero() -> Self {
23 Self::new(0.0, 0.0, 0.0)
24 }
25
26 #[inline]
28 pub fn distance(&self, other: &Self) -> f64 {
29 let dx = self.x - other.x;
30 let dy = self.y - other.y;
31 let dz = self.z - other.z;
32 (dx * dx + dy * dy + dz * dz).sqrt()
33 }
34
35 #[inline]
37 pub fn add(&self, other: &Self) -> Self {
38 Self::new(self.x + other.x, self.y + other.y, self.z + other.z)
39 }
40
41 #[inline]
43 pub fn sub(&self, other: &Self) -> Self {
44 Self::new(self.x - other.x, self.y - other.y, self.z - other.z)
45 }
46
47 #[inline]
49 pub fn scale(&self, s: f64) -> Self {
50 Self::new(self.x * s, self.y * s, self.z * s)
51 }
52
53 #[inline]
55 pub fn dot(&self, other: &Self) -> f64 {
56 self.x * other.x + self.y * other.y + self.z * other.z
57 }
58
59 #[inline]
61 pub fn cross(&self, other: &Self) -> Self {
62 Self::new(
63 self.y * other.z - self.z * other.y,
64 self.z * other.x - self.x * other.z,
65 self.x * other.y - self.y * other.x,
66 )
67 }
68
69 #[inline]
71 pub fn norm(&self) -> f64 {
72 (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
73 }
74
75 pub fn normalize(&self) -> Self {
80 let n = self.norm();
81 assert!(n > 0.0, "cannot normalize a zero-length vector");
82 self.scale(1.0 / n)
83 }
84
85 pub fn try_normalize(&self) -> Option<Self> {
87 let n = self.norm();
88 if n > 0.0 {
89 Some(self.scale(1.0 / n))
90 } else {
91 None
92 }
93 }
94}
95
96#[derive(Debug, Clone)]
100pub struct Coords3D {
101 pub points: Vec<Point3>,
102}
103
104impl Coords3D {
105 pub fn new_zeroed(n: usize) -> Self {
107 Self {
108 points: vec![Point3::zero(); n],
109 }
110 }
111
112 pub fn get(&self, idx: AtomIdx) -> Point3 {
114 self.points[idx.0 as usize]
115 }
116
117 pub fn set(&mut self, idx: AtomIdx, p: Point3) {
119 self.points[idx.0 as usize] = p;
120 }
121
122 pub fn atom_count(&self) -> usize {
124 self.points.len()
125 }
126}