52 lines
2.0 KiB
Rust
52 lines
2.0 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 scale_to_width(&self, size: f64) -> Self;
|
|
fn scale(&self, factor: f64) -> Self;
|
|
}
|
|
|
|
impl MultiPolygonExt for MultiPolygon<f64> {
|
|
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<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)
|
|
}
|
|
}
|