polygon-art/src/extensions/multipolygon_ext.rs

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)
}
}