|
1 | 1 | use std::hash::{Hash, Hasher}; |
2 | 2 |
|
3 | | -use bevy::math::{EulerRot, Quat, Vec2, Vec3, Vec4}; |
| 3 | +use bevy::math::{Affine2, EulerRot, Mat2, Quat, Vec2, Vec3, Vec4}; |
4 | 4 | use pyo3::{ |
5 | 5 | exceptions::{PyAttributeError, PyTypeError}, |
6 | 6 | prelude::*, |
@@ -771,6 +771,174 @@ impl PyVecIter { |
771 | 771 | } |
772 | 772 | } |
773 | 773 |
|
| 774 | +#[pyclass(name = "Mat2", from_py_object)] |
| 775 | +#[derive(Clone, Debug)] |
| 776 | +pub struct PyMat2(pub(crate) Mat2); |
| 777 | + |
| 778 | +impl From<Mat2> for PyMat2 { |
| 779 | + fn from(m: Mat2) -> Self { |
| 780 | + Self(m) |
| 781 | + } |
| 782 | +} |
| 783 | + |
| 784 | +#[pymethods] |
| 785 | +impl PyMat2 { |
| 786 | + #[new] |
| 787 | + #[pyo3(signature = (*args))] |
| 788 | + pub fn py_new(args: &Bound<'_, PyTuple>) -> PyResult<Self> { |
| 789 | + match args.len() { |
| 790 | + 0 => Ok(Self(Mat2::IDENTITY)), |
| 791 | + 4 => { |
| 792 | + let m00: f32 = args.get_item(0)?.extract()?; |
| 793 | + let m01: f32 = args.get_item(1)?.extract()?; |
| 794 | + let m10: f32 = args.get_item(2)?.extract()?; |
| 795 | + let m11: f32 = args.get_item(3)?.extract()?; |
| 796 | + Ok(Self(Mat2::from_cols(Vec2::new(m00, m01), Vec2::new(m10, m11)))) |
| 797 | + } |
| 798 | + _ => Err(PyTypeError::new_err("Mat2 takes 0 or 4 arguments")), |
| 799 | + } |
| 800 | + } |
| 801 | + |
| 802 | + #[staticmethod] |
| 803 | + fn from_scale(scale: PyVec2) -> Self { |
| 804 | + Self(Mat2::from_diagonal(scale.0)) |
| 805 | + } |
| 806 | + |
| 807 | + #[staticmethod] |
| 808 | + fn from_angle(angle: f32) -> Self { |
| 809 | + Self(Mat2::from_angle(angle)) |
| 810 | + } |
| 811 | + |
| 812 | + fn __mul__(&self, rhs: &Bound<'_, PyAny>) -> PyResult<Py<PyAny>> { |
| 813 | + let py = rhs.py(); |
| 814 | + if let Ok(other) = rhs.extract::<PyRef<PyMat2>>() { |
| 815 | + return Ok(PyMat2(self.0 * other.0) |
| 816 | + .into_pyobject(py)? |
| 817 | + .into_any() |
| 818 | + .unbind()); |
| 819 | + } |
| 820 | + if let Ok(v) = rhs.extract::<PyRef<PyVec2>>() { |
| 821 | + return Ok(PyVec2(self.0 * v.0) |
| 822 | + .into_pyobject(py)? |
| 823 | + .into_any() |
| 824 | + .unbind()); |
| 825 | + } |
| 826 | + Err(PyTypeError::new_err( |
| 827 | + "unsupported operand type(s) for *: 'Mat2'", |
| 828 | + )) |
| 829 | + } |
| 830 | + |
| 831 | + fn determinant(&self) -> f32 { |
| 832 | + self.0.determinant() |
| 833 | + } |
| 834 | + |
| 835 | + fn inverse(&self) -> Self { |
| 836 | + Self(self.0.inverse()) |
| 837 | + } |
| 838 | + |
| 839 | + fn transpose(&self) -> Self { |
| 840 | + Self(self.0.transpose()) |
| 841 | + } |
| 842 | + |
| 843 | + fn __repr__(&self) -> String { |
| 844 | + let c = self.0.to_cols_array(); |
| 845 | + format!("Mat2({}, {}, {}, {})", c[0], c[1], c[2], c[3]) |
| 846 | + } |
| 847 | + |
| 848 | + fn __str__(&self) -> String { |
| 849 | + self.__repr__() |
| 850 | + } |
| 851 | + |
| 852 | + fn __eq__(&self, other: &Self) -> bool { |
| 853 | + self.0 == other.0 |
| 854 | + } |
| 855 | + |
| 856 | + fn __hash__(&self) -> u64 { |
| 857 | + let mut hasher = std::collections::hash_map::DefaultHasher::new(); |
| 858 | + for &c in self.0.to_cols_array().iter() { |
| 859 | + hash_f32(c, &mut hasher); |
| 860 | + } |
| 861 | + std::hash::Hasher::finish(&hasher) |
| 862 | + } |
| 863 | +} |
| 864 | + |
| 865 | +#[pyclass(name = "Affine2", from_py_object)] |
| 866 | +#[derive(Clone, Debug)] |
| 867 | +pub struct PyAffine2(pub(crate) Affine2); |
| 868 | + |
| 869 | +impl From<Affine2> for PyAffine2 { |
| 870 | + fn from(a: Affine2) -> Self { |
| 871 | + Self(a) |
| 872 | + } |
| 873 | +} |
| 874 | + |
| 875 | +#[pymethods] |
| 876 | +impl PyAffine2 { |
| 877 | + #[new] |
| 878 | + #[pyo3(signature = (matrix=None, translation=None))] |
| 879 | + pub fn py_new(matrix: Option<PyRef<PyMat2>>, translation: Option<PyRef<PyVec2>>) -> Self { |
| 880 | + Self(Affine2 { |
| 881 | + matrix2: matrix.map(|m| m.0).unwrap_or(Mat2::IDENTITY), |
| 882 | + translation: translation.map(|t| t.0).unwrap_or(Vec2::ZERO), |
| 883 | + }) |
| 884 | + } |
| 885 | + |
| 886 | + #[staticmethod] |
| 887 | + fn from_scale(scale: PyVec2) -> Self { |
| 888 | + Self(Affine2::from_scale(scale.0)) |
| 889 | + } |
| 890 | + |
| 891 | + #[staticmethod] |
| 892 | + fn from_scale_angle_translation(scale: PyVec2, angle: f32, translation: PyVec2) -> Self { |
| 893 | + Self(Affine2::from_scale_angle_translation( |
| 894 | + scale.0, |
| 895 | + angle, |
| 896 | + translation.0, |
| 897 | + )) |
| 898 | + } |
| 899 | + |
| 900 | + #[getter] |
| 901 | + fn matrix(&self) -> PyMat2 { |
| 902 | + PyMat2(self.0.matrix2) |
| 903 | + } |
| 904 | + |
| 905 | + #[getter] |
| 906 | + fn translation(&self) -> PyVec2 { |
| 907 | + PyVec2(self.0.translation) |
| 908 | + } |
| 909 | + |
| 910 | + fn inverse(&self) -> Self { |
| 911 | + Self(self.0.inverse()) |
| 912 | + } |
| 913 | + |
| 914 | + fn __repr__(&self) -> String { |
| 915 | + let m = self.0.matrix2.to_cols_array(); |
| 916 | + let t = self.0.translation; |
| 917 | + format!( |
| 918 | + "Affine2(Mat2({}, {}, {}, {}), Vec2({}, {}))", |
| 919 | + m[0], m[1], m[2], m[3], t.x, t.y |
| 920 | + ) |
| 921 | + } |
| 922 | + |
| 923 | + fn __str__(&self) -> String { |
| 924 | + self.__repr__() |
| 925 | + } |
| 926 | + |
| 927 | + fn __eq__(&self, other: &Self) -> bool { |
| 928 | + self.0 == other.0 |
| 929 | + } |
| 930 | + |
| 931 | + fn __hash__(&self) -> u64 { |
| 932 | + let mut hasher = std::collections::hash_map::DefaultHasher::new(); |
| 933 | + for &c in self.0.matrix2.to_cols_array().iter() { |
| 934 | + hash_f32(c, &mut hasher); |
| 935 | + } |
| 936 | + hash_f32(self.0.translation.x, &mut hasher); |
| 937 | + hash_f32(self.0.translation.y, &mut hasher); |
| 938 | + std::hash::Hasher::finish(&hasher) |
| 939 | + } |
| 940 | +} |
| 941 | + |
774 | 942 | #[cfg(test)] |
775 | 943 | mod tests { |
776 | 944 | use super::*; |
|
0 commit comments