polygon-art/src/extensions/scale_ext.rs

69 lines
2.3 KiB
Rust

use crate::extensions::translate_ext::ExplicitBoundingRect;
use geo::algorithm::map_coords::MapCoords;
use geo::algorithm::translate::Translate;
use geo::{CoordinateType, LineString, MultiLineString, MultiPolygon, Polygon};
pub trait ExplicitMapCoords<T> {
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self;
}
impl<T: CoordinateType> ExplicitMapCoords<T> for LineString<T> {
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self {
self.map_coords(func)
}
}
impl<T: CoordinateType> ExplicitMapCoords<T> for MultiLineString<T> {
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self {
self.map_coords(func)
}
}
impl<T: CoordinateType> ExplicitMapCoords<T> for MultiPolygon<T> {
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self {
self.map_coords(func)
}
}
impl<T: CoordinateType> ExplicitMapCoords<T> for Polygon<T> {
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self {
self.map_coords(func)
}
}
pub trait ScaleExt {
/// scale object
fn scale(&self, scale_x: f64, scale_y: f64) -> Self;
/// scale object to given width (in 1:1 ratio)
fn scale_to_width(&self, size: f64) -> Self;
/// scale object to given height (in 1:1 ratio)
fn scale_to_height(&self, size: f64) -> Self;
}
impl<V> ScaleExt for V
where
V: ExplicitBoundingRect<f64> + ExplicitMapCoords<f64> + Translate<f64>,
{
fn scale(&self, scale_x: f64, scale_y: f64) -> Self {
let bounding_rectangle = self.bounding().unwrap();
let minimum_coordinates = bounding_rectangle.min();
self.translate(-minimum_coordinates.x, -minimum_coordinates.y)
.map_coordinates(|&(x, y)| (x * scale_x, y * scale_y))
.translate(minimum_coordinates.x, minimum_coordinates.y)
}
fn scale_to_width(&self, size: f64) -> Self {
let option = self.bounding().unwrap();
let diff = f64::abs(option.min().x - option.max().x);
let scale = size / diff;
self.scale(scale, scale)
}
fn scale_to_height(&self, size: f64) -> Self {
let option = self.bounding().unwrap();
let diff = f64::abs(option.min().y - option.max().y);
let scale = size / diff;
self.scale(scale, scale)
}
}