digital-ink-library 1.4.0

library for digital ink (strokes, sketches etc.)
Documentation
use std::fmt;

use serde::{Deserialize, Serialize};
use serde_json::json;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BoundingBox {
    pub x_min: f64,
    pub y_min: f64,
    pub x_max: f64,
    pub y_max: f64,
    pub width: f64,
    pub height: f64,
}

impl BoundingBox {
    pub fn new(x_min: f64, y_min: f64, x_max: f64, y_max: f64) -> BoundingBox {
        if x_min > x_max { panic!("x_min value ({}) should be less than x_max value ({})", x_min, x_max); }
        if y_min > y_max { panic!("y_min value ({}) should be less than y_max value ({})", y_min, y_max); }

        let width = x_max - x_min;
        let height = y_max - y_min;

        BoundingBox { x_min, y_min, x_max, y_max, width, height }
    }

    pub fn merge(&self, bounding_box: &BoundingBox) -> BoundingBox {
        let x_min = if self.x_min < bounding_box.x_min { self.x_min } else { bounding_box.x_min };
        let y_min = if self.y_min < bounding_box.y_min { self.y_min } else { bounding_box.y_min };
        let x_max = if self.x_max > bounding_box.x_max { self.x_max } else { bounding_box.x_max };
        let y_max = if self.y_max > bounding_box.y_max { self.y_max } else { bounding_box.y_max };

        BoundingBox::new(x_min, y_min, x_max, y_max)
    }

    pub fn contains(&self, x: f64, y: f64) -> bool {
        self.x_min <= x && x <= self.x_max && self.y_min <= y && y <= self.y_max
    }

    pub fn intersects(&self, bounding_box: &BoundingBox) -> bool {
        self.contains(bounding_box.x_min, bounding_box.y_max)
            || self.contains(bounding_box.x_min, bounding_box.y_min)
            || self.contains(bounding_box.x_max, bounding_box.y_max)
            || self.contains(bounding_box.x_max, bounding_box.y_min)
            || bounding_box.contains(self.x_min, self.y_max)
            || bounding_box.contains(self.x_min, self.y_min)
            || bounding_box.contains(self.x_max, self.y_max)
            || bounding_box.contains(self.x_max, self.y_min)
    }

    pub fn get_intersection(&self, bounding_box: &BoundingBox) -> Option<BoundingBox> {
        if !self.intersects(bounding_box) {
            return None;
        }

        let x_min = if self.x_min > bounding_box.x_min { self.x_min } else { bounding_box.x_min };
        let x_max = if self.x_max < bounding_box.x_max { self.x_max } else { bounding_box.x_max };
        let y_min = if self.y_min > bounding_box.y_min { self.y_min } else { bounding_box.y_min };
        let y_max = if self.y_max < bounding_box.y_max { self.y_max } else { bounding_box.y_max };

        Some(BoundingBox::new(x_min, y_min, x_max, y_max))
    }

    pub fn area(&self) -> f64 {
        self.width * self.height
    }
}

impl fmt::Display for BoundingBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", json!(self))
    }
}

impl PartialEq for BoundingBox {
    fn eq(&self, other: &Self) -> bool {
        self.x_min == other.x_min &&
            self.y_min == other.y_min &&
            self.x_max == other.x_max &&
            self.y_max == other.y_max &&
            self.width == other.width &&
            self.height == other.height
    }
}

impl Eq for BoundingBox {}