use geo::algorithm::bounding_rect::BoundingRect; use geo::algorithm::translate::Translate; use geo::Polygon; use geo_types::{Coordinate, LineString, MultiPolygon}; pub trait MultiPolygonExt { fn scale_to_width(&self, size: f64) -> Self; fn scale(&self, factor: f64) -> Self; } impl MultiPolygonExt for MultiPolygon { fn scale_to_width(&self, size: f64) -> Self { let option = self.bounding_rect().unwrap(); let diff = f64::abs(option.min().x - option.max().x); let scale = size / diff; self.scale(scale) } fn scale(&self, factor: f64) -> Self { let bounding_rectangle = self.bounding_rect().unwrap(); let zeroed_multi_polygons = self.translate(-bounding_rectangle.min().x, -bounding_rectangle.min().y); let mut new_polygons: Vec> = Vec::new(); for polygon in zeroed_multi_polygons.iter() { // map interiors let mut interiors: Vec> = Vec::new(); for interior_line_string in polygon.interiors().to_vec() { let mut new_line_string: Vec> = Vec::new(); for point in interior_line_string.into_points() { new_line_string.push(Coordinate { x: point.x() * factor, y: point.y() * factor, }); } interiors.push(LineString::from(new_line_string)); } // map exterior let mut new_line_string: Vec> = Vec::new(); for point in polygon.exterior().clone().into_points() { new_line_string.push(Coordinate { x: point.x() * factor, y: point.y() * factor, }); } let exterior = LineString::from(new_line_string); new_polygons.push(Polygon::new(exterior, interiors)); } MultiPolygon::from(new_polygons) .translate(bounding_rectangle.min().x, bounding_rectangle.min().y) } }