use geo::algorithm::bounding_rect::BoundingRect; use geo::algorithm::translate::Translate; use geo::Polygon; use geo_types::{Coordinate, LineString, MultiPolygon}; pub trait MultiPolygonExt { fn translate_center(&self) -> Self; fn translate_center_x(&self) -> Self; fn translate_center_y(&self) -> Self; fn scale_to_width(&self, size: f64) -> Self; fn scale(&self, factor: f64) -> Self; } impl MultiPolygonExt for MultiPolygon { fn translate_center(&self) -> Self { let option = self.bounding_rect().unwrap(); let y_diff = option.max().y - option.min().y; let y_shift = y_diff / 2.0; let x_diff = option.max().x - option.min().x; let x_shift = x_diff / 2.0; self.translate(-(option.min().x + x_shift), -(option.min().y + y_shift)) } fn translate_center_x(&self) -> Self { let option = self.bounding_rect().unwrap(); let x_diff = option.max().x - option.min().x; let x_shift = x_diff / 2.0; self.translate(-(option.min().x + x_shift), 0.0) } fn translate_center_y(&self) -> Self { let option = self.bounding_rect().unwrap(); let y_diff = option.max().y - option.min().y; let y_shift = y_diff / 2.0; self.translate(0.0, -(option.min().y + y_shift)) } fn scale_to_width(&self, size: f64) -> Self { // let ((x_min, y_min), (x_max, _)) = self.get_min_max_rectangle(); 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) } }