From 4074267844733949556af129550dfc42fc81da76 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tomas=20Wenstr=C3=B6m?= Date: Mon, 8 Feb 2021 19:10:21 +0100 Subject: [PATCH] Replaced Degrees and Radians with a single Angle type --- src/common/geometry.rs | 143 +++++++++++++++++++++++++++++++++++-------------- src/common/mod.rs | 4 +- src/core/controller.rs | 7 ++- src/core/game.rs | 6 +-- src/core/level/mod.rs | 13 ++--- 5 files changed, 117 insertions(+), 56 deletions(-) diff --git a/src/common/geometry.rs b/src/common/geometry.rs index 3fee2ad..d767d8e 100644 --- a/src/common/geometry.rs +++ b/src/common/geometry.rs @@ -28,12 +28,8 @@ impl Point { } } - pub fn to_radians(&self) -> Radians { - Radians(self.y.atan2(self.x)) - } - - pub fn to_degrees(&self) -> Degrees { - self.to_radians().to_degrees() + pub fn to_angle(&self) -> Angle { + self.y.atan2(self.x).radians() } pub fn to_i32(self) -> Point { @@ -147,46 +143,115 @@ impl From> for (T, T) { } } -impl From for Point { - fn from(item: Degrees) -> Self { - let r = item.0.to_radians(); - Point { - x: r.cos(), - y: r.sin(), - } +impl From for Point { + fn from(item: Angle) -> Self { + Point { + x: item.0.cos(), + y: item.0.sin(), + } } } -impl From for Point { - fn from(item: Radians) -> Self { - Point { - x: item.0.cos(), - y: item.0.sin(), - } - } -} +////////// ANGLE /////////////////////////////////////////////////////////////// #[derive(Debug, Default, PartialEq, Clone, Copy)] -pub struct Degrees(pub f64); -#[derive(Debug, Default, PartialEq, Clone, Copy)] -pub struct Radians(pub f64); +pub struct Angle(pub f64); -impl Degrees { - #[allow(dead_code)] - pub fn to_radians(&self) -> Radians { - Radians(self.0.to_radians()) +pub trait ToAngle { + fn radians(self) -> Angle; + fn degrees(self) -> Angle; +} + +macro_rules! impl_angle { + ($($type:ty),*) => { + $( + impl ToAngle for $type { + fn radians(self) -> Angle { + Angle(self as f64) + } + + fn degrees(self) -> Angle { + Angle((self as f64).to_radians()) + } + } + + impl Mul<$type> for Angle { + type Output = Self; + + fn mul(self, rhs: $type) -> Self { + Angle(self.0 * (rhs as f64)) + } + } + + impl MulAssign<$type> for Angle { + fn mul_assign(&mut self, rhs: $type) { + self.0 *= rhs as f64; + } + } + + impl Div<$type> for Angle { + type Output = Self; + + fn div(self, rhs: $type) -> Self { + Angle(self.0 / (rhs as f64)) + } + } + + impl DivAssign<$type> for Angle { + fn div_assign(&mut self, rhs: $type) { + self.0 /= rhs as f64; + } + } + )* } } -impl Radians { - #[allow(dead_code)] - pub fn to_degrees(&self) -> Degrees { - Degrees(self.0.to_degrees()) +impl_angle!(f32, f64, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); + +impl Angle { + pub fn to_radians(self) -> f64 { + self.0 + } + + pub fn to_degrees(self) -> f64 { + self.0.to_degrees() } /// Returns the reflection of the incident when mirrored along this angle. - pub fn mirror(&self, incidence: Radians) -> Radians { - Radians((std::f64::consts::PI + self.0 * 2.0 - incidence.0) % std::f64::consts::TAU) + pub fn mirror(&self, incidence: Angle) -> Angle { + Angle((std::f64::consts::PI + self.0 * 2.0 - incidence.0) % std::f64::consts::TAU) + } +} + +// TODO override eq, 0==360 osv + +// addition and subtraction of angles + +impl Add for Angle { + type Output = Self; + + fn add(self, rhs: Angle) -> Self { + Angle(self.0 + rhs.0) + } +} + +impl AddAssign for Angle { + fn add_assign(&mut self, rhs: Angle) { + self.0 += rhs.0; + } +} + +impl Sub for Angle { + type Output = Self; + + fn sub(self, rhs: Angle) -> Self { + Angle(self.0 - rhs.0) + } +} + +impl SubAssign for Angle { + fn sub_assign(&mut self, rhs: Angle) { + self.0 -= rhs.0; } } @@ -402,11 +467,11 @@ mod tests { #[test] fn angles() { - assert_eq!(Radians(0.0).to_degrees(), Degrees(0.0)); - assert_eq!(Radians(std::f64::consts::PI).to_degrees(), Degrees(180.0)); - assert_eq!(Degrees(180.0).to_radians(), Radians(std::f64::consts::PI)); - assert!((Point::from(Degrees(90.0)) - point!(0.0, 1.0)).length() < 0.001); - assert!((Point::from(Radians(std::f64::consts::FRAC_PI_2)) - point!(0.0, 1.0)).length() < 0.001); + assert_eq!(0.radians(), 0.degrees()); + assert_eq!(180.degrees(), std::f64::consts::PI.radians()); + assert_eq!(std::f64::consts::PI.radians().to_degrees(), 180.0); + assert!((Point::from(90.degrees()) - point!(0.0, 1.0)).length() < 0.001); + assert!((Point::from(std::f64::consts::FRAC_PI_2.radians()) - point!(0.0, 1.0)).length() < 0.001); } #[test] diff --git a/src/common/mod.rs b/src/common/mod.rs index 675d973..592bdbb 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -2,8 +2,8 @@ mod geometry; pub use common::geometry::{ Point, Dimension, - Radians, - Degrees, + Angle, + ToAngle, Intersection, supercover_line, }; diff --git a/src/core/controller.rs b/src/core/controller.rs index 54dae94..3cbe391 100644 --- a/src/core/controller.rs +++ b/src/core/controller.rs @@ -1,6 +1,5 @@ -use common::Point; +use common::{Angle, Point}; use {hashmap, point}; -use common::Radians; use sdl2::HapticSubsystem; use sdl2::JoystickSubsystem; use sdl2::event::Event; @@ -67,7 +66,7 @@ pub struct Stick { idy: u8, pub x: f32, pub y: f32, - pub a: Radians, + pub a: Angle, } impl Stick { @@ -80,7 +79,7 @@ impl Stick { Ok(val) => val as f32 / 32768.0, Err(_) => panic!("invalid y axis {}", self.idy), }; - self.a = Radians(self.y.atan2(self.x) as f64); + self.a = point!(self.x as f64, self.y as f64).to_angle(); } #[inline(always)] #[allow(dead_code)] pub fn up(&self) -> bool { self.y < -0.99 } diff --git a/src/core/game.rs b/src/core/game.rs index 39af2e1..2fa7ddd 100644 --- a/src/core/game.rs +++ b/src/core/game.rs @@ -1,6 +1,6 @@ use teststate::TestState; use AppState; -use common::{Point, Radians}; +use common::{Point, ToAngle}; use core::app::StateChange; use core::controller::Controller; use core::controller::ControllerManager; @@ -276,7 +276,7 @@ impl Object for Boll { return Dead } self.bounces -= 1; - let mut a = wall.normal().mirror(self.vel.to_radians()); // TODO interpolera normalen mellan närliggande väggdelar? bollarna studsar väldigt "kantigt" nu + let mut a = wall.normal().mirror(self.vel.to_angle()); // TODO interpolera normalen mellan närliggande väggdelar? bollarna studsar väldigt "kantigt" nu self.pos = pos; self.vel = Point::from(a) * self.vel.length() * 0.35; self.pos += self.vel; // TODO det här kan få bollen att åka igenom en närliggande vägg utan att kollisionstestas, men behövs just nu för att inte kollidera med samma vägg bakifrån @@ -284,7 +284,7 @@ impl Object for Boll { // create another boll use rand::distributions::{Distribution, Normal}; let mut rng = rand::thread_rng(); - a.0 += Normal::new(0.0, 0.1).sample(&mut rng); // TODO slumpen kan ge en vinkel som är under tangenten. vinkel-metoder på väggen istället kanske? + a += Normal::new(0.0, 0.1).sample(&mut rng).radians(); // TODO slumpen kan ge en vinkel som är under tangenten. vinkel-metoder på väggen istället kanske? use rand::Rng; objects.push(Box::new(Boll { vel: Point::from(a) * Normal::new(1.0, 0.25).sample(&mut rng) * self.vel.length() * rng.gen_range(0.25, 1.0), diff --git a/src/core/level/mod.rs b/src/core/level/mod.rs index cccd253..00f3009 100644 --- a/src/core/level/mod.rs +++ b/src/core/level/mod.rs @@ -1,4 +1,4 @@ -use common::{Point, Dimension, Intersection, Radians, supercover_line}; +use common::{Point, Dimension, Intersection, Angle, ToAngle, supercover_line}; use core::render::Renderer; use sprites::SpriteManager; use std::rc::Rc; @@ -90,12 +90,11 @@ impl Level { for wall in &self.walls { for e in &wall.edges { let c = (e.p1 + e.p2) / 2.0; - let mut rad = (e.p2 - e.p1).to_radians(); - rad.0 += std::f64::consts::FRAC_PI_2; + let a = (e.p2 - e.p1).to_angle() + std::f64::consts::FRAC_PI_2.radians(); renderer.draw_line( <(i32, i32)>::from(c.to_i32()), - <(i32, i32)>::from((c + Point::from(rad) * 10.0).to_i32()), + <(i32, i32)>::from((c + Point::from(a) * 10.0).to_i32()), (255, 128, 0)); renderer.draw_line( @@ -248,9 +247,7 @@ impl<'a> Wall<'a> { } } - pub fn normal(&self) -> Radians { - let mut rad = (self.edge.p2 - self.edge.p1).to_radians(); - rad.0 += std::f64::consts::FRAC_PI_2; - rad + pub fn normal(&self) -> Angle { + (self.edge.p2 - self.edge.p1).to_angle() + std::f64::consts::FRAC_PI_2.radians() } } -- 2.11.0