80 lines
3.1 KiB
Rust
80 lines
3.1 KiB
Rust
|
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<f64> {
|
||
|
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<Polygon<f64>> = Vec::new();
|
||
|
for polygon in zeroed_multi_polygons.iter() {
|
||
|
// map interiors
|
||
|
let mut interiors: Vec<LineString<f64>> = Vec::new();
|
||
|
for interior_line_string in polygon.interiors().to_vec() {
|
||
|
let mut new_line_string: Vec<Coordinate<f64>> = 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<Coordinate<f64>> = 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)
|
||
|
}
|
||
|
}
|