1use crate::{f32::math, swizzles::*, DMat2, Mat3, Mat3A, Vec2};
4use core::fmt;
5use core::iter::{Product, Sum};
6use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7
8use core::arch::aarch64::*;
9
10#[cfg(feature = "zerocopy")]
11use zerocopy_derive::*;
12
13#[repr(C)]
14union UnionCast {
15 a: [f32; 4],
16 v: Mat2,
17}
18
19#[inline(always)]
21#[must_use]
22pub const fn mat2(x_axis: Vec2, y_axis: Vec2) -> Mat2 {
23 Mat2::from_cols(x_axis, y_axis)
24}
25
26#[derive(Clone, Copy)]
32#[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
33#[cfg_attr(
34 feature = "zerocopy",
35 derive(FromBytes, Immutable, IntoBytes, KnownLayout)
36)]
37#[repr(transparent)]
38pub struct Mat2(pub(crate) float32x4_t);
39
40impl Mat2 {
41 pub const ZERO: Self = Self::from_cols(Vec2::ZERO, Vec2::ZERO);
43
44 pub const IDENTITY: Self = Self::from_cols(Vec2::X, Vec2::Y);
46
47 pub const NAN: Self = Self::from_cols(Vec2::NAN, Vec2::NAN);
49
50 #[allow(clippy::too_many_arguments)]
51 #[inline(always)]
52 #[must_use]
53 const fn new(m00: f32, m01: f32, m10: f32, m11: f32) -> Self {
54 unsafe {
55 UnionCast {
56 a: [m00, m01, m10, m11],
57 }
58 .v
59 }
60 }
61
62 #[inline(always)]
64 #[must_use]
65 pub const fn from_cols(x_axis: Vec2, y_axis: Vec2) -> Self {
66 unsafe {
67 UnionCast {
68 a: [x_axis.x, x_axis.y, y_axis.x, y_axis.y],
69 }
70 .v
71 }
72 }
73
74 #[inline]
78 #[must_use]
79 pub const fn from_cols_array(m: &[f32; 4]) -> Self {
80 Self::new(m[0], m[1], m[2], m[3])
81 }
82
83 #[inline]
86 #[must_use]
87 pub const fn to_cols_array(&self) -> [f32; 4] {
88 unsafe { *(self as *const Self as *const [f32; 4]) }
89 }
90
91 #[inline]
95 #[must_use]
96 pub const fn from_cols_array_2d(m: &[[f32; 2]; 2]) -> Self {
97 Self::from_cols(Vec2::from_array(m[0]), Vec2::from_array(m[1]))
98 }
99
100 #[inline]
103 #[must_use]
104 pub const fn to_cols_array_2d(&self) -> [[f32; 2]; 2] {
105 unsafe { *(self as *const Self as *const [[f32; 2]; 2]) }
106 }
107
108 #[doc(alias = "scale")]
110 #[inline]
111 #[must_use]
112 pub const fn from_diagonal(diagonal: Vec2) -> Self {
113 Self::new(diagonal.x, 0.0, 0.0, diagonal.y)
114 }
115
116 #[inline]
119 #[must_use]
120 pub fn from_scale_angle(scale: Vec2, angle: f32) -> Self {
121 let (sin, cos) = math::sin_cos(angle);
122 Self::new(cos * scale.x, sin * scale.x, -sin * scale.y, cos * scale.y)
123 }
124
125 #[inline]
127 #[must_use]
128 pub fn from_angle(angle: f32) -> Self {
129 let (sin, cos) = math::sin_cos(angle);
130 Self::new(cos, sin, -sin, cos)
131 }
132
133 #[inline]
135 #[must_use]
136 pub fn from_mat3(m: Mat3) -> Self {
137 Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
138 }
139
140 #[inline]
147 #[must_use]
148 pub fn from_mat3_minor(m: Mat3, i: usize, j: usize) -> Self {
149 match (i, j) {
150 (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
151 (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
152 (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
153 (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
154 (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
155 (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
156 (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
157 (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
158 (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
159 _ => panic!("index out of bounds"),
160 }
161 }
162
163 #[inline]
165 #[must_use]
166 pub fn from_mat3a(m: Mat3A) -> Self {
167 Self::from_cols(m.x_axis.xy(), m.y_axis.xy())
168 }
169
170 #[inline]
177 #[must_use]
178 pub fn from_mat3a_minor(m: Mat3A, i: usize, j: usize) -> Self {
179 match (i, j) {
180 (0, 0) => Self::from_cols(m.y_axis.yz(), m.z_axis.yz()),
181 (0, 1) => Self::from_cols(m.y_axis.xz(), m.z_axis.xz()),
182 (0, 2) => Self::from_cols(m.y_axis.xy(), m.z_axis.xy()),
183 (1, 0) => Self::from_cols(m.x_axis.yz(), m.z_axis.yz()),
184 (1, 1) => Self::from_cols(m.x_axis.xz(), m.z_axis.xz()),
185 (1, 2) => Self::from_cols(m.x_axis.xy(), m.z_axis.xy()),
186 (2, 0) => Self::from_cols(m.x_axis.yz(), m.y_axis.yz()),
187 (2, 1) => Self::from_cols(m.x_axis.xz(), m.y_axis.xz()),
188 (2, 2) => Self::from_cols(m.x_axis.xy(), m.y_axis.xy()),
189 _ => panic!("index out of bounds"),
190 }
191 }
192
193 #[inline]
199 #[must_use]
200 pub const fn from_cols_slice(slice: &[f32]) -> Self {
201 Self::new(slice[0], slice[1], slice[2], slice[3])
202 }
203
204 #[inline]
210 pub fn write_cols_to_slice(self, slice: &mut [f32]) {
211 slice[0] = self.x_axis.x;
212 slice[1] = self.x_axis.y;
213 slice[2] = self.y_axis.x;
214 slice[3] = self.y_axis.y;
215 }
216
217 #[inline]
223 #[must_use]
224 pub fn col(&self, index: usize) -> Vec2 {
225 match index {
226 0 => self.x_axis,
227 1 => self.y_axis,
228 _ => panic!("index out of bounds"),
229 }
230 }
231
232 #[inline]
238 pub fn col_mut(&mut self, index: usize) -> &mut Vec2 {
239 match index {
240 0 => &mut self.x_axis,
241 1 => &mut self.y_axis,
242 _ => panic!("index out of bounds"),
243 }
244 }
245
246 #[inline]
252 #[must_use]
253 pub fn row(&self, index: usize) -> Vec2 {
254 match index {
255 0 => Vec2::new(self.x_axis.x, self.y_axis.x),
256 1 => Vec2::new(self.x_axis.y, self.y_axis.y),
257 _ => panic!("index out of bounds"),
258 }
259 }
260
261 #[inline]
264 #[must_use]
265 pub fn is_finite(&self) -> bool {
266 self.x_axis.is_finite() && self.y_axis.is_finite()
267 }
268
269 #[inline]
271 #[must_use]
272 pub fn is_nan(&self) -> bool {
273 self.x_axis.is_nan() || self.y_axis.is_nan()
274 }
275
276 #[inline]
278 #[must_use]
279 pub fn transpose(&self) -> Self {
280 Self(unsafe {
281 vsetq_lane_f32(
282 vgetq_lane_f32(self.0, 2),
283 vsetq_lane_f32(vgetq_lane_f32(self.0, 1), self.0, 2),
284 1,
285 )
286 })
287 }
288
289 #[inline]
291 #[must_use]
292 pub fn determinant(&self) -> f32 {
293 unsafe {
294 let abcd = self.0;
295 let badc = vrev64q_f32(abcd);
296 let dcba = vextq_f32(badc, badc, 2);
297 let prod = vmulq_f32(abcd, dcba);
298 let det = vsubq_f32(prod, vdupq_laneq_f32(prod, 1));
299 vgetq_lane_f32(det, 0)
300 }
301 }
302
303 #[inline]
311 #[must_use]
312 pub fn inverse(&self) -> Self {
313 unsafe {
314 const SIGN: float32x4_t = crate::neon::f32x4_from_array([1.0, -1.0, -1.0, 1.0]);
315 let abcd = self.0;
316 let badc = vrev64q_f32(abcd);
317 let dcba = vextq_f32(badc, badc, 2);
318 let prod = vmulq_f32(abcd, dcba);
319 let sub = vsubq_f32(prod, vdupq_laneq_f32(prod, 1));
320 let det = vdupq_laneq_f32(sub, 0);
321 let tmp = vdivq_f32(SIGN, det);
322 glam_assert!(Mat2(tmp).is_finite());
323 let dbca = vsetq_lane_f32(
325 vgetq_lane_f32(abcd, 0),
326 vsetq_lane_f32(vgetq_lane_f32(abcd, 3), abcd, 0),
327 3,
328 );
329 Self(vmulq_f32(dbca, tmp))
330 }
331 }
332
333 #[inline]
335 #[must_use]
336 pub fn mul_vec2(&self, rhs: Vec2) -> Vec2 {
337 unsafe {
338 let abcd = self.0;
339 let xxyy = vld1q_f32([rhs.x, rhs.x, rhs.y, rhs.y].as_ptr());
340 let axbxcydy = vmulq_f32(abcd, xxyy);
341 let cydyaxbx = vextq_f32(axbxcydy, axbxcydy, 2);
343 let result = vaddq_f32(axbxcydy, cydyaxbx);
344 *(&result as *const float32x4_t as *const Vec2)
345 }
346 }
347
348 #[inline]
350 #[must_use]
351 pub fn mul_mat2(&self, rhs: &Self) -> Self {
352 self.mul(rhs)
353 }
354
355 #[inline]
357 #[must_use]
358 pub fn add_mat2(&self, rhs: &Self) -> Self {
359 self.add(rhs)
360 }
361
362 #[inline]
364 #[must_use]
365 pub fn sub_mat2(&self, rhs: &Self) -> Self {
366 self.sub(rhs)
367 }
368
369 #[inline]
371 #[must_use]
372 pub fn mul_scalar(&self, rhs: f32) -> Self {
373 Self(unsafe { vmulq_f32(self.0, vld1q_dup_f32(&rhs)) })
374 }
375
376 #[inline]
378 #[must_use]
379 pub fn div_scalar(&self, rhs: f32) -> Self {
380 Self(unsafe { vdivq_f32(self.0, vld1q_dup_f32(&rhs)) })
381 }
382
383 #[inline]
393 #[must_use]
394 pub fn abs_diff_eq(&self, rhs: Self, max_abs_diff: f32) -> bool {
395 self.x_axis.abs_diff_eq(rhs.x_axis, max_abs_diff)
396 && self.y_axis.abs_diff_eq(rhs.y_axis, max_abs_diff)
397 }
398
399 #[inline]
401 #[must_use]
402 pub fn abs(&self) -> Self {
403 Self::from_cols(self.x_axis.abs(), self.y_axis.abs())
404 }
405
406 #[inline]
407 pub fn as_dmat2(&self) -> DMat2 {
408 DMat2::from_cols(self.x_axis.as_dvec2(), self.y_axis.as_dvec2())
409 }
410}
411
412impl Default for Mat2 {
413 #[inline]
414 fn default() -> Self {
415 Self::IDENTITY
416 }
417}
418
419impl Add for Mat2 {
420 type Output = Self;
421 #[inline]
422 fn add(self, rhs: Self) -> Self {
423 Self(unsafe { vaddq_f32(self.0, rhs.0) })
424 }
425}
426
427impl Add<&Self> for Mat2 {
428 type Output = Self;
429 #[inline]
430 fn add(self, rhs: &Self) -> Self {
431 self.add(*rhs)
432 }
433}
434
435impl Add<&Mat2> for &Mat2 {
436 type Output = Mat2;
437 #[inline]
438 fn add(self, rhs: &Mat2) -> Mat2 {
439 (*self).add(*rhs)
440 }
441}
442
443impl Add<Mat2> for &Mat2 {
444 type Output = Mat2;
445 #[inline]
446 fn add(self, rhs: Mat2) -> Mat2 {
447 (*self).add(rhs)
448 }
449}
450
451impl AddAssign for Mat2 {
452 #[inline]
453 fn add_assign(&mut self, rhs: Self) {
454 *self = self.add(rhs);
455 }
456}
457
458impl AddAssign<&Self> for Mat2 {
459 #[inline]
460 fn add_assign(&mut self, rhs: &Self) {
461 self.add_assign(*rhs);
462 }
463}
464
465impl Sub for Mat2 {
466 type Output = Self;
467 #[inline]
468 fn sub(self, rhs: Self) -> Self {
469 Self(unsafe { vsubq_f32(self.0, rhs.0) })
470 }
471}
472
473impl Sub<&Self> for Mat2 {
474 type Output = Self;
475 #[inline]
476 fn sub(self, rhs: &Self) -> Self {
477 self.sub(*rhs)
478 }
479}
480
481impl Sub<&Mat2> for &Mat2 {
482 type Output = Mat2;
483 #[inline]
484 fn sub(self, rhs: &Mat2) -> Mat2 {
485 (*self).sub(*rhs)
486 }
487}
488
489impl Sub<Mat2> for &Mat2 {
490 type Output = Mat2;
491 #[inline]
492 fn sub(self, rhs: Mat2) -> Mat2 {
493 (*self).sub(rhs)
494 }
495}
496
497impl SubAssign for Mat2 {
498 #[inline]
499 fn sub_assign(&mut self, rhs: Self) {
500 *self = self.sub(rhs);
501 }
502}
503
504impl SubAssign<&Self> for Mat2 {
505 #[inline]
506 fn sub_assign(&mut self, rhs: &Self) {
507 self.sub_assign(*rhs);
508 }
509}
510
511impl Neg for Mat2 {
512 type Output = Self;
513 #[inline]
514 fn neg(self) -> Self::Output {
515 Self(unsafe { vnegq_f32(self.0) })
516 }
517}
518
519impl Neg for &Mat2 {
520 type Output = Mat2;
521 #[inline]
522 fn neg(self) -> Mat2 {
523 (*self).neg()
524 }
525}
526
527impl Mul for Mat2 {
528 type Output = Self;
529 #[inline]
530 fn mul(self, rhs: Self) -> Self {
531 unsafe {
532 let abcd = self.0;
533 let xxyy0 = vzip1q_f32(rhs.0, rhs.0);
534 let xxyy1 = vzip2q_f32(rhs.0, rhs.0);
535 let axbxcydy0 = vmulq_f32(abcd, xxyy0);
536 let axbxcydy1 = vmulq_f32(abcd, xxyy1);
537 let cydyaxbx0 = vextq_f32(axbxcydy0, axbxcydy0, 2);
538 let cydyaxbx1 = vextq_f32(axbxcydy1, axbxcydy1, 2);
539 let result0 = vaddq_f32(axbxcydy0, cydyaxbx0);
540 let result1 = vaddq_f32(axbxcydy1, cydyaxbx1);
541 Self(vreinterpretq_f32_u64(vsetq_lane_u64(
542 vgetq_lane_u64(vreinterpretq_u64_f32(result1), 0),
543 vreinterpretq_u64_f32(result0),
544 1,
545 )))
546 }
547 }
548}
549
550impl Mul<&Self> for Mat2 {
551 type Output = Self;
552 #[inline]
553 fn mul(self, rhs: &Self) -> Self {
554 self.mul(*rhs)
555 }
556}
557
558impl Mul<&Mat2> for &Mat2 {
559 type Output = Mat2;
560 #[inline]
561 fn mul(self, rhs: &Mat2) -> Mat2 {
562 (*self).mul(*rhs)
563 }
564}
565
566impl Mul<Mat2> for &Mat2 {
567 type Output = Mat2;
568 #[inline]
569 fn mul(self, rhs: Mat2) -> Mat2 {
570 (*self).mul(rhs)
571 }
572}
573
574impl MulAssign for Mat2 {
575 #[inline]
576 fn mul_assign(&mut self, rhs: Self) {
577 *self = self.mul(rhs);
578 }
579}
580
581impl MulAssign<&Self> for Mat2 {
582 #[inline]
583 fn mul_assign(&mut self, rhs: &Self) {
584 self.mul_assign(*rhs);
585 }
586}
587
588impl Mul<Vec2> for Mat2 {
589 type Output = Vec2;
590 #[inline]
591 fn mul(self, rhs: Vec2) -> Self::Output {
592 self.mul_vec2(rhs)
593 }
594}
595
596impl Mul<&Vec2> for Mat2 {
597 type Output = Vec2;
598 #[inline]
599 fn mul(self, rhs: &Vec2) -> Vec2 {
600 self.mul(*rhs)
601 }
602}
603
604impl Mul<&Vec2> for &Mat2 {
605 type Output = Vec2;
606 #[inline]
607 fn mul(self, rhs: &Vec2) -> Vec2 {
608 (*self).mul(*rhs)
609 }
610}
611
612impl Mul<Vec2> for &Mat2 {
613 type Output = Vec2;
614 #[inline]
615 fn mul(self, rhs: Vec2) -> Vec2 {
616 (*self).mul(rhs)
617 }
618}
619
620impl Mul<Mat2> for f32 {
621 type Output = Mat2;
622 #[inline]
623 fn mul(self, rhs: Mat2) -> Self::Output {
624 rhs.mul_scalar(self)
625 }
626}
627
628impl Mul<&Mat2> for f32 {
629 type Output = Mat2;
630 #[inline]
631 fn mul(self, rhs: &Mat2) -> Mat2 {
632 self.mul(*rhs)
633 }
634}
635
636impl Mul<&Mat2> for &f32 {
637 type Output = Mat2;
638 #[inline]
639 fn mul(self, rhs: &Mat2) -> Mat2 {
640 (*self).mul(*rhs)
641 }
642}
643
644impl Mul<Mat2> for &f32 {
645 type Output = Mat2;
646 #[inline]
647 fn mul(self, rhs: Mat2) -> Mat2 {
648 (*self).mul(rhs)
649 }
650}
651
652impl Mul<f32> for Mat2 {
653 type Output = Self;
654 #[inline]
655 fn mul(self, rhs: f32) -> Self {
656 self.mul_scalar(rhs)
657 }
658}
659
660impl Mul<&f32> for Mat2 {
661 type Output = Self;
662 #[inline]
663 fn mul(self, rhs: &f32) -> Self {
664 self.mul(*rhs)
665 }
666}
667
668impl Mul<&f32> for &Mat2 {
669 type Output = Mat2;
670 #[inline]
671 fn mul(self, rhs: &f32) -> Mat2 {
672 (*self).mul(*rhs)
673 }
674}
675
676impl Mul<f32> for &Mat2 {
677 type Output = Mat2;
678 #[inline]
679 fn mul(self, rhs: f32) -> Mat2 {
680 (*self).mul(rhs)
681 }
682}
683
684impl MulAssign<f32> for Mat2 {
685 #[inline]
686 fn mul_assign(&mut self, rhs: f32) {
687 *self = self.mul(rhs);
688 }
689}
690
691impl MulAssign<&f32> for Mat2 {
692 #[inline]
693 fn mul_assign(&mut self, rhs: &f32) {
694 self.mul_assign(*rhs);
695 }
696}
697
698impl Div<Mat2> for f32 {
699 type Output = Mat2;
700 #[inline]
701 fn div(self, rhs: Mat2) -> Self::Output {
702 rhs.div_scalar(self)
703 }
704}
705
706impl Div<&Mat2> for f32 {
707 type Output = Mat2;
708 #[inline]
709 fn div(self, rhs: &Mat2) -> Mat2 {
710 self.div(*rhs)
711 }
712}
713
714impl Div<&Mat2> for &f32 {
715 type Output = Mat2;
716 #[inline]
717 fn div(self, rhs: &Mat2) -> Mat2 {
718 (*self).div(*rhs)
719 }
720}
721
722impl Div<Mat2> for &f32 {
723 type Output = Mat2;
724 #[inline]
725 fn div(self, rhs: Mat2) -> Mat2 {
726 (*self).div(rhs)
727 }
728}
729
730impl Div<f32> for Mat2 {
731 type Output = Self;
732 #[inline]
733 fn div(self, rhs: f32) -> Self {
734 self.div_scalar(rhs)
735 }
736}
737
738impl Div<&f32> for Mat2 {
739 type Output = Self;
740 #[inline]
741 fn div(self, rhs: &f32) -> Self {
742 self.div(*rhs)
743 }
744}
745
746impl Div<&f32> for &Mat2 {
747 type Output = Mat2;
748 #[inline]
749 fn div(self, rhs: &f32) -> Mat2 {
750 (*self).div(*rhs)
751 }
752}
753
754impl Div<f32> for &Mat2 {
755 type Output = Mat2;
756 #[inline]
757 fn div(self, rhs: f32) -> Mat2 {
758 (*self).div(rhs)
759 }
760}
761
762impl DivAssign<f32> for Mat2 {
763 #[inline]
764 fn div_assign(&mut self, rhs: f32) {
765 *self = self.div(rhs);
766 }
767}
768
769impl DivAssign<&f32> for Mat2 {
770 #[inline]
771 fn div_assign(&mut self, rhs: &f32) {
772 self.div_assign(*rhs);
773 }
774}
775
776impl Sum<Self> for Mat2 {
777 fn sum<I>(iter: I) -> Self
778 where
779 I: Iterator<Item = Self>,
780 {
781 iter.fold(Self::ZERO, Self::add)
782 }
783}
784
785impl<'a> Sum<&'a Self> for Mat2 {
786 fn sum<I>(iter: I) -> Self
787 where
788 I: Iterator<Item = &'a Self>,
789 {
790 iter.fold(Self::ZERO, |a, &b| Self::add(a, b))
791 }
792}
793
794impl Product for Mat2 {
795 fn product<I>(iter: I) -> Self
796 where
797 I: Iterator<Item = Self>,
798 {
799 iter.fold(Self::IDENTITY, Self::mul)
800 }
801}
802
803impl<'a> Product<&'a Self> for Mat2 {
804 fn product<I>(iter: I) -> Self
805 where
806 I: Iterator<Item = &'a Self>,
807 {
808 iter.fold(Self::IDENTITY, |a, &b| Self::mul(a, b))
809 }
810}
811
812impl PartialEq for Mat2 {
813 #[inline]
814 fn eq(&self, rhs: &Self) -> bool {
815 self.x_axis.eq(&rhs.x_axis) && self.y_axis.eq(&rhs.y_axis)
816 }
817}
818
819impl AsRef<[f32; 4]> for Mat2 {
820 #[inline]
821 fn as_ref(&self) -> &[f32; 4] {
822 unsafe { &*(self as *const Self as *const [f32; 4]) }
823 }
824}
825
826impl AsMut<[f32; 4]> for Mat2 {
827 #[inline]
828 fn as_mut(&mut self) -> &mut [f32; 4] {
829 unsafe { &mut *(self as *mut Self as *mut [f32; 4]) }
830 }
831}
832
833impl core::ops::Deref for Mat2 {
834 type Target = crate::deref::Cols2<Vec2>;
835 #[inline]
836 fn deref(&self) -> &Self::Target {
837 unsafe { &*(self as *const Self as *const Self::Target) }
838 }
839}
840
841impl core::ops::DerefMut for Mat2 {
842 #[inline]
843 fn deref_mut(&mut self) -> &mut Self::Target {
844 unsafe { &mut *(self as *mut Self as *mut Self::Target) }
845 }
846}
847
848impl fmt::Debug for Mat2 {
849 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
850 fmt.debug_struct(stringify!(Mat2))
851 .field("x_axis", &self.x_axis)
852 .field("y_axis", &self.y_axis)
853 .finish()
854 }
855}
856
857impl fmt::Display for Mat2 {
858 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
859 if let Some(p) = f.precision() {
860 write!(f, "[{:.*}, {:.*}]", p, self.x_axis, p, self.y_axis)
861 } else {
862 write!(f, "[{}, {}]", self.x_axis, self.y_axis)
863 }
864 }
865}