aboutsummaryrefslogtreecommitdiff
path: root/src/math/line_segment.rs
diff options
context:
space:
mode:
authorArne Dußin2020-11-18 21:54:41 +0100
committerArne Dußin2020-11-18 21:54:41 +0100
commit8d99501918393ea0c046d721e6fa6015fe43b70f (patch)
tree17a15dfb135093163622b61631661e8d4551fdf3 /src/math/line_segment.rs
parentaf4f4b91d013384a4af82f48d768ac041662eb20 (diff)
downloadgraf_karto-8d99501918393ea0c046d721e6fa6015fe43b70f.tar.gz
graf_karto-8d99501918393ea0c046d721e6fa6015fe43b70f.zip
Implement bounding box function
Diffstat (limited to 'src/math/line_segment.rs')
-rw-r--r--src/math/line_segment.rs74
1 files changed, 72 insertions, 2 deletions
diff --git a/src/math/line_segment.rs b/src/math/line_segment.rs
index 2b67783..e6ca70f 100644
--- a/src/math/line_segment.rs
+++ b/src/math/line_segment.rs
@@ -192,15 +192,57 @@ where
* they are the same it follows that the three points are collinear.
*/
match (b.y - a.y) * (c.x - b.x) - (b.x - a.x) * (c.y - b.y) {
- q if q > T::zero() => TripletOrientation::Clockwise,
- q if q < T::zero() => TripletOrientation::Counterclockwise,
+ q if q > T::zero() => TripletOrientation::Counterclockwise,
+ q if q < T::zero() => TripletOrientation::Clockwise,
_ => TripletOrientation::Collinear,
}
}
+/// Calculate the angle between three points. Guaranteed to have 0 <= angle < 2Pi. The angle is
+/// calculated as the angle between a line from a to b and then from b to c, increasing
+/// counterclockwise.
+///
+/// # Panics
+/// If the length from a to b or the length from b to c is zero.
+pub(crate) fn triplet_angle<T>(a: Vec2<T>, b: Vec2<T>, c: Vec2<T>) -> T
+where
+ T: Scalar + Copy + ClosedSub + RealField + Zero,
+{
+ assert!(a != b);
+ assert!(b != c);
+
+ // Handle the extreme 0 and 180 degree cases
+ let orientation = triplet_orientation(a, b, c);
+ if orientation == TripletOrientation::Collinear {
+ if LineSegment::new(a, b).contains_collinear(c)
+ || LineSegment::new(b, c).contains_collinear(a)
+ {
+ return T::zero();
+ } else {
+ return T::pi();
+ }
+ }
+
+ // Calculate the vectors out of the points
+ let ba = a - b;
+ let bc = c - b;
+
+ // Calculate the angle between 0 and Pi.
+ let angle = ((ba * bc) / (ba.length() * bc.length())).acos();
+
+ // Make angle into a full circle angle by looking at the orientation of the triplet.
+ let angle = match orientation {
+ TripletOrientation::Counterclockwise => T::pi() + (T::pi() - angle),
+ _ => angle,
+ };
+
+ angle
+}
+
#[cfg(test)]
mod test {
use super::*;
+ use std::f64::consts::PI;
#[test]
fn contains_collinear() {
@@ -214,4 +256,32 @@ mod test {
assert!(!segment.contains_collinear(Vec2::new(3., 3.)));
assert!(!segment.contains_collinear(Vec2::new(-1., 0.)));
}
+
+ #[test]
+ fn triplet_angle() {
+ assert_eq!(
+ super::triplet_angle(Vec2::new(0., 0.), Vec2::new(0., -1.), Vec2::new(-1., -1.)),
+ 1.5 * PI
+ );
+ assert_eq!(
+ super::triplet_angle(Vec2::new(2., 2.), Vec2::new(0., 0.), Vec2::new(-1., -1.)),
+ PI
+ );
+ assert_eq!(
+ super::triplet_angle(Vec2::new(3., 1.), Vec2::new(0., 0.), Vec2::new(6., 2.)),
+ 0.
+ );
+ assert_eq!(
+ super::triplet_angle(Vec2::new(3., 1.), Vec2::new(0., 0.), Vec2::new(-6., -2.)),
+ PI
+ );
+ assert_eq!(
+ super::triplet_angle(Vec2::new(0., 1.), Vec2::new(0., 2.), Vec2::new(-3., 2.)),
+ 0.5 * PI
+ );
+ assert_eq!(
+ super::triplet_angle(Vec2::new(3., 1.), Vec2::new(2., 2.), Vec2::new(0., 2.)),
+ 0.75 * PI
+ );
+ }
}