polygon-art/src/multipolygon_ext.rs

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