1use std::{
4 fmt::Display,
5 iter::{Product, Sum},
6 ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign},
7};
8
9use geo_aid_figure::Position;
10use serde::Serialize;
11
12#[derive(Debug, Clone, Copy, Serialize)]
14pub struct Complex {
15 pub real: f64,
17 pub imaginary: f64,
19}
20
21impl Complex {
22 #[must_use]
24 #[inline]
25 pub const fn new(real: f64, imaginary: f64) -> Self {
26 Self { real, imaginary }
27 }
28
29 #[must_use]
31 pub const fn real(real: f64) -> Self {
32 Self::new(real, 0.0)
33 }
34
35 #[must_use]
37 pub fn polar(theta: f64, radius: f64) -> Self {
38 Self::new(theta.cos(), theta.sin()) * radius
39 }
40
41 #[must_use]
43 #[inline]
44 pub const fn zero() -> Self {
45 Self::new(0.0, 0.0)
46 }
47
48 #[must_use]
50 #[inline]
51 pub const fn one() -> Self {
52 Self::new(1.0, 0.0)
53 }
54
55 #[must_use]
57 pub const fn i() -> Self {
58 Self::new(0.0, 1.0)
59 }
60
61 #[must_use]
63 pub fn mul_i(self) -> Complex {
64 Complex::new(-self.imaginary, self.real)
65 }
66
67 #[must_use]
69 pub fn magnitude(self) -> f64 {
70 f64::sqrt(self.real.powi(2) + self.imaginary.powi(2))
71 }
72
73 #[must_use]
75 pub fn conjugate(self) -> Complex {
76 Complex::new(self.real, -self.imaginary)
77 }
78
79 #[must_use]
81 pub fn partial_mul(self, other: Complex) -> Complex {
82 Complex::new(self.real * other.real, self.imaginary * other.imaginary)
83 }
84
85 #[must_use]
87 pub fn partial_div(self, other: Complex) -> Complex {
88 Complex::new(self.real / other.real, self.imaginary / other.imaginary)
89 }
90
91 #[must_use]
93 pub fn arg(self) -> f64 {
94 f64::atan2(self.imaginary, self.real)
95 }
96
97 #[must_use]
99 pub fn normalize(self) -> Complex {
100 self / self.magnitude()
101 }
102
103 #[must_use]
105 pub fn len_squared(self) -> f64 {
106 self.real * self.real + self.imaginary * self.imaginary
107 }
108
109 #[must_use]
111 pub fn sqrt(self) -> Complex {
112 if self.real > 0.0 {
115 let r = self.magnitude();
117
118 r.sqrt() * (self + r).normalize()
119 } else {
120 (-self).sqrt().mul_i()
121 }
122 }
123
124 #[must_use]
126 pub fn sqrt_norm(self) -> Complex {
127 if self.real > 0.0 {
130 let r = self.magnitude();
132
133 (self + r).normalize()
135 } else {
136 (-self).sqrt_norm().mul_i() }
138 }
139
140 #[must_use]
142 pub fn inverse(self) -> Self {
143 self.conjugate() / self.len_squared()
144 }
145}
146
147impl From<Complex> for Position {
148 fn from(value: Complex) -> Self {
149 Self {
150 x: value.real,
151 y: value.imaginary,
152 }
153 }
154}
155
156impl From<Complex> for geo_aid_figure::Complex {
157 fn from(value: Complex) -> Self {
158 Self {
159 real: value.real,
160 imaginary: value.imaginary,
161 }
162 }
163}
164
165impl From<Position> for Complex {
166 fn from(value: Position) -> Self {
167 Self::new(value.x, value.y)
168 }
169}
170
171impl Mul for Complex {
172 type Output = Complex;
173
174 fn mul(self, rhs: Complex) -> Self::Output {
175 Complex::new(
176 self.real * rhs.real - self.imaginary * rhs.imaginary,
177 self.real * rhs.imaginary + rhs.real * self.imaginary,
178 )
179 }
180}
181
182impl Mul<Complex> for f64 {
183 type Output = Complex;
184
185 fn mul(self, rhs: Complex) -> Self::Output {
186 Complex::new(self * rhs.real, self * rhs.imaginary)
187 }
188}
189
190impl Mul<f64> for Complex {
191 type Output = Complex;
192
193 fn mul(self, rhs: f64) -> Self::Output {
194 Complex::new(self.real * rhs, self.imaginary * rhs)
195 }
196}
197
198impl MulAssign<f64> for Complex {
199 fn mul_assign(&mut self, rhs: f64) {
200 self.real *= rhs;
201 self.imaginary *= rhs;
202 }
203}
204
205impl Add<f64> for Complex {
206 type Output = Complex;
207
208 fn add(self, rhs: f64) -> Self::Output {
209 Complex::new(self.real + rhs, self.imaginary)
210 }
211}
212
213impl Add for Complex {
214 type Output = Complex;
215
216 fn add(self, rhs: Self) -> Self::Output {
217 Complex::new(self.real + rhs.real, self.imaginary + rhs.imaginary)
218 }
219}
220
221impl Div<f64> for Complex {
222 type Output = Complex;
223
224 fn div(self, rhs: f64) -> Self::Output {
225 Complex::new(self.real / rhs, self.imaginary / rhs)
226 }
227}
228
229impl Div for Complex {
230 type Output = Complex;
231
232 fn div(self, rhs: Complex) -> Self::Output {
233 (self * rhs.conjugate()) / (rhs.real * rhs.real + rhs.imaginary * rhs.imaginary)
234 }
235}
236
237impl Sub<f64> for Complex {
238 type Output = Complex;
239
240 fn sub(self, rhs: f64) -> Self::Output {
241 Complex::new(self.real - rhs, self.imaginary)
242 }
243}
244
245impl Sub for Complex {
246 type Output = Complex;
247
248 fn sub(self, rhs: Self) -> Self::Output {
249 Complex::new(self.real - rhs.real, self.imaginary - rhs.imaginary)
250 }
251}
252
253impl SubAssign for Complex {
254 fn sub_assign(&mut self, rhs: Self) {
255 *self = *self - rhs;
256 }
257}
258
259impl AddAssign for Complex {
260 fn add_assign(&mut self, rhs: Self) {
261 *self = *self + rhs;
262 }
263}
264
265impl MulAssign for Complex {
266 fn mul_assign(&mut self, rhs: Self) {
267 *self = *self * rhs;
268 }
269}
270
271impl Display for Complex {
272 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273 if let Some(precision) = f.precision() {
274 write!(
275 f,
276 "{2:.*} + {3:.*}i",
277 precision, precision, self.real, self.imaginary
278 )
279 } else {
280 write!(f, "{} + {}i", self.real, self.imaginary)
281 }
282 }
283}
284
285impl Neg for Complex {
286 type Output = Complex;
287
288 fn neg(self) -> Self::Output {
289 Complex::new(-self.real, -self.imaginary)
290 }
291}
292
293impl Default for Complex {
294 fn default() -> Self {
295 Self {
296 real: 0.0,
297 imaginary: 0.0,
298 }
299 }
300}
301
302impl Sum for Complex {
303 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
304 let mut v = Complex::zero();
305
306 for x in iter {
307 v += x;
308 }
309
310 v
311 }
312}
313
314impl Product for Complex {
315 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
316 let mut v = Complex::zero();
317
318 for x in iter {
319 v *= x;
320 }
321
322 v
323 }
324}
325
326#[derive(Debug, Clone, Copy, Serialize)]
328pub struct Line {
329 pub origin: Complex,
331 pub direction: Complex,
333}
334
335impl Line {
336 #[must_use]
338 pub fn new(origin: Complex, direction: Complex) -> Self {
339 Self {
340 origin,
341 direction: direction.normalize(),
342 }
343 }
344}
345
346impl From<Line> for geo_aid_figure::Line {
347 fn from(value: Line) -> Self {
348 Self {
349 origin: value.origin.into(),
350 direction: value.direction.into(),
351 }
352 }
353}
354
355#[derive(Debug, Clone, Copy, Serialize)]
357pub struct Circle {
358 pub center: Complex,
360 pub radius: f64,
362}
363
364impl From<Circle> for geo_aid_figure::Circle {
365 fn from(value: Circle) -> Self {
366 Self {
367 center: value.center.into(),
368 radius: value.radius,
369 }
370 }
371}
372
373#[derive(Debug, Clone, Copy, Serialize)]
375pub enum ValueEnum {
376 Complex(Complex),
377 Line(Line),
378 Circle(Circle),
379}
380
381impl ValueEnum {
382 #[must_use]
383 pub fn as_complex(self) -> Option<Complex> {
384 match self {
385 Self::Complex(c) => Some(c),
386 _ => None,
387 }
388 }
389
390 #[must_use]
391 pub fn as_line(self) -> Option<Line> {
392 match self {
393 Self::Line(l) => Some(l),
394 _ => None,
395 }
396 }
397
398 #[must_use]
399 pub fn as_circle(self) -> Option<Circle> {
400 match self {
401 Self::Circle(l) => Some(l),
402 _ => None,
403 }
404 }
405}
406
407impl From<ValueEnum> for geo_aid_figure::Value {
408 fn from(value: ValueEnum) -> Self {
409 match value {
410 ValueEnum::Complex(c) => Self::Complex(c.into()),
411 ValueEnum::Line(ln) => Self::Line(ln.into()),
412 ValueEnum::Circle(c) => Self::Circle(c.into()),
413 }
414 }
415}
416
417#[must_use]
419pub fn get_line(p1: Complex, p2: Complex) -> Line {
420 Line {
421 origin: p1,
422 direction: (p2 - p1).normalize(),
423 }
424}
425
426#[must_use]
428pub fn get_intersection(k_ln: Line, l_ln: Line) -> Complex {
429 let Line {
430 origin: a,
431 direction: b,
432 } = k_ln;
433 let Line {
434 origin: c,
435 direction: d,
436 } = l_ln;
437
438 a - b * ((a - c) / d).imaginary / (b / d).imaginary
439}
440
441#[must_use]
443pub fn get_angle(arm1: Complex, origin: Complex, arm2: Complex) -> f64 {
444 let arm1_vec = arm1 - origin;
446 let arm2_vec = arm2 - origin;
447
448 let dot_product = arm1_vec.real * arm2_vec.real + arm1_vec.imaginary * arm2_vec.imaginary;
450
451 f64::acos(dot_product / (arm1_vec.magnitude() * arm2_vec.magnitude()))
453}
454
455#[must_use]
457pub fn get_angle_directed(arm1: Complex, origin: Complex, arm2: Complex) -> f64 {
458 let arm1_vec = arm1 - origin;
460 let arm2_vec = arm2 - origin;
461
462 let p2_rotated = arm2_vec / arm1_vec;
464
465 p2_rotated.arg()
467}
468
469#[must_use]
471pub fn rotate_around(p: Complex, origin: Complex, angle: f64) -> Complex {
472 (p - origin) * Complex::new(angle.cos(), angle.sin()) + origin
473}
474
475#[must_use]
477pub fn distance_pt_ln(point: Complex, line: Line) -> f64 {
478 let point_rot = (point - line.origin) / line.direction;
480
481 point_rot.imaginary.abs()
483}
484
485#[must_use]
487pub fn distance_pt_pt(p1: Complex, p2: Complex) -> f64 {
488 ((p1.real - p2.real) * (p1.real - p2.real)
489 + (p1.imaginary - p2.imaginary) * (p1.imaginary - p2.imaginary))
490 .sqrt()
491}