1use pyo3::prelude::*;
3use std::sync::Arc;
4
5#[pyclass(name = "Vec2", subclass)]
6#[derive(Clone)]
7pub struct Vec2 {
8 pub(crate) x: f64,
9 pub(crate) y: f64,
10 pub(crate) target: Option<(Arc<crate::ScriptHost>, String)>,
11}
12
13impl std::fmt::Debug for Vec2 {
14 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
15 f.debug_struct("Vec2")
16 .field("x", &self.x())
17 .field("y", &self.y())
18 .finish()
19 }
20}
21
22impl Vec2 {
23 pub fn x(&self) -> f64 {
24 if let Some((host, node)) = &self.target {
25 if let Some((x, _)) = host.get_node_position(node) {
26 return x;
27 }
28 }
29 self.x
30 }
31
32 pub fn y(&self) -> f64 {
33 if let Some((host, node)) = &self.target {
34 if let Some((_, y)) = host.get_node_position(node) {
35 return y;
36 }
37 }
38 self.y
39 }
40
41 pub fn set_target(&mut self, host: Arc<crate::ScriptHost>, node: String) {
42 if let Some((x, y)) = host.get_node_position(&node) {
43 self.x = x;
44 self.y = y;
45 }
46 self.target = Some((host, node));
47 }
48}
49
50impl<'py> pyo3::FromPyObject<'_, 'py> for Vec2 {
51 type Error = PyErr;
52 fn extract(ob: pyo3::Borrowed<'_, 'py, pyo3::PyAny>) -> Result<Self, Self::Error> {
53 let b: pyo3::PyRef<'py, Vec2> = ob.extract()?;
54 Ok(b.clone())
55 }
56}
57
58#[pymethods]
59impl Vec2 {
60 #[new]
61 #[pyo3(signature = (x = 0.0, y = 0.0))]
62 pub fn new(x: f64, y: f64) -> Self {
63 Self { x, y, target: None }
64 }
65
66 #[getter]
67 pub fn get_x(&self) -> f64 {
68 self.x()
69 }
70
71 #[setter]
72 pub fn set_x(&mut self, val: f64) {
73 self.x = val;
74 if let Some((host, node)) = &self.target {
75 let cur_y = self.y();
76 self.y = cur_y;
77 host.set_node_position(node, val, cur_y);
78 }
79 }
80
81 #[getter]
82 pub fn get_y(&self) -> f64 {
83 self.y()
84 }
85
86 #[setter]
87 pub fn set_y(&mut self, val: f64) {
88 self.y = val;
89 if let Some((host, node)) = &self.target {
90 let cur_x = self.x();
91 self.x = cur_x;
92 host.set_node_position(node, cur_x, val);
93 }
94 }
95
96 fn __repr__(&self) -> String {
97 format!("Vec2({}, {})", self.x(), self.y())
98 }
99
100 fn __eq__(&self, other: &Bound<'_, PyAny>) -> bool {
101 let (ox, oy) = if let Ok(other_vec) = other.extract::<Vec2>() {
102 (other_vec.x(), other_vec.y())
103 } else if let Ok((x, y)) = other.extract::<(f64, f64)>() {
104 (x, y)
105 } else {
106 return false;
107 };
108 (self.x() - ox).abs() < 1e-6 && (self.y() - oy).abs() < 1e-6
109 }
110
111 fn __add__(&self, other: &Bound<'_, PyAny>) -> PyResult<Vec2> {
112 let (ox, oy) = if let Ok(other_vec) = other.extract::<Vec2>() {
113 (other_vec.x(), other_vec.y())
114 } else if let Ok(t) = other.extract::<(f64, f64)>() {
115 t
116 } else {
117 return Err(pyo3::exceptions::PyTypeError::new_err(
118 "unsupported operand type for +: 'Vec2' and non-vector",
119 ));
120 };
121 Ok(Vec2 {
122 x: self.x() + ox,
123 y: self.y() + oy,
124 target: None,
125 })
126 }
127
128 fn __sub__(&self, other: &Bound<'_, PyAny>) -> PyResult<Vec2> {
129 let (ox, oy) = if let Ok(other_vec) = other.extract::<Vec2>() {
130 (other_vec.x(), other_vec.y())
131 } else if let Ok(t) = other.extract::<(f64, f64)>() {
132 t
133 } else {
134 return Err(pyo3::exceptions::PyTypeError::new_err(
135 "unsupported operand type for -: 'Vec2' and non-vector",
136 ));
137 };
138 Ok(Vec2 {
139 x: self.x() - ox,
140 y: self.y() - oy,
141 target: None,
142 })
143 }
144
145 fn __mul__(&self, scalar: f64) -> Vec2 {
146 Vec2 {
147 x: self.x() * scalar,
148 y: self.y() * scalar,
149 target: None,
150 }
151 }
152
153 fn __rmul__(&self, scalar: f64) -> Vec2 {
154 Vec2 {
155 x: self.x() * scalar,
156 y: self.y() * scalar,
157 target: None,
158 }
159 }
160
161 fn __truediv__(&self, scalar: f64) -> PyResult<Vec2> {
162 if scalar == 0.0 {
163 return Err(pyo3::exceptions::PyZeroDivisionError::new_err(
164 "division by zero",
165 ));
166 }
167 Ok(Vec2 {
168 x: self.x() / scalar,
169 y: self.y() / scalar,
170 target: None,
171 })
172 }
173
174 fn __iadd__(&mut self, other: &Bound<'_, PyAny>) -> PyResult<()> {
175 let (ox, oy) = if let Ok(other_vec) = other.extract::<Vec2>() {
176 (other_vec.x(), other_vec.y())
177 } else if let Ok(t) = other.extract::<(f64, f64)>() {
178 t
179 } else {
180 return Err(pyo3::exceptions::PyTypeError::new_err(
181 "unsupported operand type for +=: 'Vec2' and non-vector",
182 ));
183 };
184 let cur_x = self.x();
185 let cur_y = self.y();
186 self.set_x(cur_x + ox);
187 self.set_y(cur_y + oy);
188 Ok(())
189 }
190
191 fn __isub__(&mut self, other: &Bound<'_, PyAny>) -> PyResult<()> {
192 let (ox, oy) = if let Ok(other_vec) = other.extract::<Vec2>() {
193 (other_vec.x(), other_vec.y())
194 } else if let Ok(t) = other.extract::<(f64, f64)>() {
195 t
196 } else {
197 return Err(pyo3::exceptions::PyTypeError::new_err(
198 "unsupported operand type for -=: 'Vec2' and non-vector",
199 ));
200 };
201 let cur_x = self.x();
202 let cur_y = self.y();
203 self.set_x(cur_x - ox);
204 self.set_y(cur_y - oy);
205 Ok(())
206 }
207
208 fn __imul__(&mut self, scalar: f64) {
209 let cur_x = self.x();
210 let cur_y = self.y();
211 self.set_x(cur_x * scalar);
212 self.set_y(cur_y * scalar);
213 }
214
215 fn __itruediv__(&mut self, scalar: f64) -> PyResult<()> {
216 if scalar == 0.0 {
217 return Err(pyo3::exceptions::PyZeroDivisionError::new_err(
218 "division by zero",
219 ));
220 }
221 let cur_x = self.x();
222 let cur_y = self.y();
223 self.set_x(cur_x / scalar);
224 self.set_y(cur_y / scalar);
225 Ok(())
226 }
227
228 fn __len__(&self) -> usize {
229 2
230 }
231
232 fn __getitem__(&self, idx: isize) -> PyResult<f64> {
233 match idx {
234 0 | -2 => Ok(self.x()),
235 1 | -1 => Ok(self.y()),
236 _ => Err(pyo3::exceptions::PyIndexError::new_err(
237 "Vec2 index out of range",
238 )),
239 }
240 }
241
242 fn __setitem__(&mut self, idx: isize, val: f64) -> PyResult<()> {
243 match idx {
244 0 | -2 => {
245 self.set_x(val);
246 Ok(())
247 }
248 1 | -1 => {
249 self.set_y(val);
250 Ok(())
251 }
252 _ => Err(pyo3::exceptions::PyIndexError::new_err(
253 "Vec2 index out of range",
254 )),
255 }
256 }
257
258 fn __iter__(slf: Bound<'_, Self>) -> PyResult<Bound<'_, pyo3::types::PyIterator>> {
259 let x = slf.borrow().x();
260 let y = slf.borrow().y();
261 let tuple = pyo3::types::PyTuple::new(slf.py(), [x, y])?;
262 tuple.try_iter()
263 }
264
265 fn length(&self) -> f64 {
266 let x = self.x();
267 let y = self.y();
268 (x * x + y * y).sqrt()
269 }
270
271 fn normalized(&self) -> Vec2 {
272 let len = self.length();
273 if len > 1e-6 {
274 let x = self.x();
275 let y = self.y();
276 Vec2 {
277 x: x / len,
278 y: y / len,
279 target: None,
280 }
281 } else {
282 Vec2 {
283 x: 0.0,
284 y: 0.0,
285 target: None,
286 }
287 }
288 }
289
290 fn to_tuple(&self) -> (f64, f64) {
291 (self.x(), self.y())
292 }
293}
294
295impl From<(f64, f64)> for Vec2 {
296 fn from(t: (f64, f64)) -> Self {
297 Self {
298 x: t.0,
299 y: t.1,
300 target: None,
301 }
302 }
303}