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 { fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self; } impl ExplicitMapCoords for LineString { fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self { self.map_coords(func) } } impl ExplicitMapCoords for MultiLineString { fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self { self.map_coords(func) } } impl ExplicitMapCoords for MultiPolygon { fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self { self.map_coords(func) } } impl ExplicitMapCoords for Polygon { 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 ScaleExt for V where V: ExplicitBoundingRect + ExplicitMapCoords + Translate, { 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) } }