summaryrefslogtreecommitdiffstats
path: root/svgbob/src/point.rs
diff options
context:
space:
mode:
Diffstat (limited to 'svgbob/src/point.rs')
-rw-r--r--svgbob/src/point.rs140
1 files changed, 108 insertions, 32 deletions
diff --git a/svgbob/src/point.rs b/svgbob/src/point.rs
index 1cc373f..395c92e 100644
--- a/svgbob/src/point.rs
+++ b/svgbob/src/point.rs
@@ -1,47 +1,123 @@
-use std::cmp::Ordering;
+use crate::util;
+use nalgebra::{Point2, Vector2};
+use std::{
+ cmp::Ordering,
+ fmt,
+ ops::{Add, Deref, Sub},
+};
-#[derive(Debug, PartialOrd, PartialEq, Clone)]
-pub struct Point {
- pub x: f32,
- pub y: f32,
-}
-impl Ord for Point {
- fn cmp(&self, other: &Point) -> Ordering {
- if let Some(order) = self.partial_cmp(other) {
- return order;
- }
- Ordering::Equal
+#[derive(Clone, Copy, Debug)]
+pub struct Point(Point2<f32>);
+
+impl Deref for Point {
+ type Target = Point2<f32>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
}
}
-impl Eq for Point {}
impl Point {
- pub fn new(x: f32, y: f32) -> Point {
- Point { x: x, y: y }
+ pub fn new(x: f32, y: f32) -> Self {
+ Point(Point2::new(x, y))
}
- pub fn adjust(&mut self, x: f32, y: f32) {
- self.x += x;
- self.y += y;
+
+ /// convert a point to vector
+ #[inline]
+ pub fn to_vector(&self) -> Vector2<f32> {
+ Vector2::new(self.x, self.y)
+ }
+
+ /// scale point
+ pub fn scale(&self, scale: f32) -> Self {
+ Point::new(self.x * scale, self.y * scale)
+ }
+
+ pub fn normalize(&self) -> Point {
+ let vector = self.to_vector().normalize();
+ Point::new(vector.x, vector.y)
+ }
+
+ pub fn distance(&self, other: &Self) -> f32 {
+ nalgebra::distance(&self.0, &other.0)
+ }
+
+ /// align x to 0.5
+ /// align y to odd number
+ pub fn align(&self) -> Self {
+ let x = self.x.round() + 0.5;
+ let y = if self.y.round().rem_euclid(2.0) == 0.0 {
+ self.y.round() + 1.0
+ } else {
+ self.y.round()
+ };
+ Point::new(x, y)
}
}
-// 3 points are collinear when the area of the triangle connecting them is 0;
-pub fn collinear(a: &Point, b: &Point, c: &Point) -> bool {
- a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y) == 0.0
+
+impl From<Point2<f32>> for Point {
+ fn from(point: Point2<f32>) -> Self {
+ Point(point)
+ }
}
-/*
-pub fn is_on_line(point: &Point, start: &Point, end: &Point) -> bool {
- ((point.x - start.x) / (end.x - start.x)) == ((point.y - start.y) / (end.y - start.y))
+impl From<Point2<i32>> for Point {
+ fn from(point: Point2<i32>) -> Self {
+ Point::new(point.x as f32, point.y as f32)
+ }
}
-// Given three colinear points p, q, r, the function checks if
-// point q lies on line segment 'pr'
-pub fn on_segment(q: &Point, p:&Point, r:&Point)-> bool {
- q.x <= p.x.max(r.x) && q.x >= p.x.min(r.x) &&
- q.y <= p.y.max(r.y) && q.y >= p.y.min(r.y)
+
+impl Add for Point {
+ type Output = Self;
+
+ fn add(self, other: Self) -> Self::Output {
+ Point::new(self.x + other.x, self.y + other.y)
+ }
}
+impl Sub for Point {
+ type Output = Self;
-pub fn distance(a: &Point, b: &Point) -> f32{
- ((b.x - a.x ).powi(2) + (b.y - a.y).powi(2)).sqrt()
+ fn sub(self, other: Self) -> Self::Output {
+ Point::new(self.x - other.x, self.y - other.y)
+ }
+}
+
+impl fmt::Display for Point {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "({},{})", self.x, self.y)
+ }
+}
+
+impl Eq for Point {}
+
+impl Ord for Point {
+ fn cmp(&self, other: &Self) -> Ordering {
+ util::ord(self.y, other.y).then(util::ord(self.x, other.x))
+ }
+}
+
+impl PartialOrd for Point {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialEq for Point {
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(other) == Ordering::Equal
+ }
+}
+
+#[cfg(test)]
+mod tests {
+
+ use super::*;
+
+ #[test]
+ fn test_align() {
+ let p = Point::new(1.25, 2.0);
+ let p2 = p.align();
+ assert_eq!(p2, Point::new(1.5, 3.0));
+ }
}
-*/