iron_shapes/
types.rs

1// Copyright (c) 2018-2020 Thomas Kramer.
2// SPDX-FileCopyrightText: 2018-2022 Thomas Kramer
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! Commonly used type definitions and constants.
7
8use std::ops::{Add, Neg, Sub};
9
10/// Precision for distance related decisions.
11pub const PREC_DISTANCE: DistanceType = 1e-5;
12
13/// Default floating point type.
14pub type FloatType = f64;
15
16/// Default type for euclidean distances.
17pub type DistanceType = FloatType;
18
19/// Angle expressed as a multiple of 90 degrees.
20#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Default)]
21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22pub enum Angle {
23    /// 0 Degrees.
24    #[default]
25    R0,
26    /// 90 Degrees.
27    R90,
28    /// 180 Degrees.
29    R180,
30    /// 270 Degrees.
31    R270,
32}
33
34impl Angle {
35    /// Describe the angle as a integer multiple of 90 degrees.
36    pub fn as_int(&self) -> u32 {
37        match self {
38            Angle::R0 => 0,
39            Angle::R90 => 1,
40            Angle::R180 => 2,
41            Angle::R270 => 3,
42        }
43    }
44
45    /// Convert an integer to an angle.
46    /// The integer specifies the number of 90 degree rotations.
47    pub fn from_u32(a: u32) -> Self {
48        match a % 4 {
49            0 => Angle::R0,
50            1 => Angle::R90,
51            2 => Angle::R180,
52            3 => Angle::R270,
53            _ => unreachable!(),
54        }
55    }
56}
57
58impl Add for Angle {
59    type Output = Self;
60
61    fn add(self, rhs: Self) -> Self::Output {
62        Self::from_u32(self.as_int() + rhs.as_int())
63    }
64}
65
66impl Sub for Angle {
67    type Output = Self;
68
69    fn sub(self, rhs: Self) -> Self::Output {
70        Self::from_u32(self.as_int() + 4 - rhs.as_int())
71    }
72}
73
74impl Neg for Angle {
75    type Output = Self;
76
77    fn neg(self) -> Self::Output {
78        Self::from_u32(4 - self.as_int())
79    }
80}
81
82/// Location relative to a directed line or edge.
83/// Something can be on the left of the line, right of the line or on top of the line (center).
84#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
85pub enum Side {
86    /// Location on the left side.
87    Left,
88    /// Neither on the left nor right, but on top.
89    Center,
90    /// Location on the right side.
91    Right,
92}
93
94impl Side {
95    /// Test if this is the left side.
96    pub fn is_left(&self) -> bool {
97        *self == Side::Left
98    }
99    /// Test if this is the right side.
100    pub fn is_right(&self) -> bool {
101        *self == Side::Right
102    }
103    /// Test if this is `Center`.
104    pub fn is_center(&self) -> bool {
105        *self == Side::Center
106    }
107
108    /// Get the other side.
109    pub fn other(&self) -> Self {
110        match self {
111            Side::Left => Side::Right,
112            Side::Center => Side::Center,
113            Side::Right => Side::Left,
114        }
115    }
116}
117
118/// Relative orientation of two geometrical objects such as vectors.
119#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
120pub enum Orientation {
121    /// Clock-wise orientation.
122    ClockWise,
123    /// Counter-clock-wise orientation.
124    CounterClockWise,
125    /// Neither clock-wise nor counter-clock-wise.
126    Straight,
127}
128
129impl Orientation {
130    /// Test if the orientation is equal to `ClockWise`.
131    pub fn is_clock_wise(self) -> bool {
132        self == Self::ClockWise
133    }
134    /// Test if the orientation is equal to `CounterClockWise`.
135    pub fn is_counter_clock_wise(self) -> bool {
136        self == Self::CounterClockWise
137    }
138    /// Test if the orientation is equal to `Straight`.
139    pub fn is_straight(self) -> bool {
140        self == Self::Straight
141    }
142}
143
144/// This is a result type for containment checks.
145/// * `No` Not inside.
146/// * `OnBounds` Lies on the boundaries.
147/// * `WithinBounds` Fully inside.
148#[derive(Clone, Copy, PartialEq, Eq, Debug)]
149pub enum ContainsResult {
150    /// Does not contain the point.
151    No,
152    /// Contains the point but on the borders/end-points.
153    OnBounds,
154    /// Fully contains the point.
155    WithinBounds,
156}
157
158impl ContainsResult {
159    /// Tells if the point is contained but does not lie on the bounds.
160    pub fn is_within_bounds(&self) -> bool {
161        matches!(self, ContainsResult::WithinBounds)
162    }
163
164    /// Tells if the point is contained or lies on the bounds.
165    pub fn inclusive_bounds(&self) -> bool {
166        matches!(
167            self,
168            ContainsResult::WithinBounds | ContainsResult::OnBounds
169        )
170    }
171
172    /// Check if the point neither is on the bounds nor within the bounds.
173    pub fn on_bounds(&self) -> bool {
174        matches!(self, ContainsResult::OnBounds)
175    }
176
177    /// Check if the point lies on the bounds.
178    pub fn is_no(&self) -> bool {
179        matches!(self, ContainsResult::No)
180    }
181
182    /// Returns the stronger result of the both.
183    /// Ordering from weak to strong is `No`, `OnBounds`, `WithinBounds`
184    pub fn max(self, other: Self) -> Self {
185        match (self, other) {
186            (ContainsResult::WithinBounds, _) => ContainsResult::WithinBounds,
187            (_, ContainsResult::WithinBounds) => ContainsResult::WithinBounds,
188            (ContainsResult::OnBounds, _) => ContainsResult::OnBounds,
189            (_, ContainsResult::OnBounds) => ContainsResult::OnBounds,
190            (ContainsResult::No, _) => ContainsResult::No,
191        }
192    }
193
194    /// Returns the weaker result of the both.
195    /// Ordering from weak to strong is `No`, `OnBounds`, `WithinBounds`
196    pub fn min(self, other: Self) -> Self {
197        match (self, other) {
198            (ContainsResult::No, _) => ContainsResult::No,
199            (_, ContainsResult::No) => ContainsResult::No,
200            (ContainsResult::OnBounds, _) => ContainsResult::OnBounds,
201            (_, ContainsResult::OnBounds) => ContainsResult::OnBounds,
202            (ContainsResult::WithinBounds, _) => ContainsResult::WithinBounds,
203        }
204    }
205}