feat: add merge_ext.rs and scale_ext.rs
This commit is contained in:
parent
1574ca725f
commit
f008f92bfc
8 changed files with 134 additions and 87 deletions
|
@ -3,10 +3,9 @@
|
|||
use geo::rotate::RotatePoint;
|
||||
use geo::translate::Translate;
|
||||
use geo::{Coordinate, Point};
|
||||
use polygon_art::load_multipolygon_from_svg;
|
||||
use polygon_art::Context;
|
||||
use polygon_art::MultiPolygonExt;
|
||||
use polygon_art::TranslateExt;
|
||||
use polygon_art::{load_multipolygon_from_svg, ScaleExt};
|
||||
use rand::Rng;
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -5,8 +5,8 @@ use geo::rotate::RotatePoint;
|
|||
use geo::LineString;
|
||||
use geo::{polygon, Coordinate, MultiPolygon, Point, Polygon};
|
||||
use geo_clipper::Clipper;
|
||||
use polygon_art::{load_multipolygon_from_svg_include, Context};
|
||||
use polygon_art::{AsteroidFont, FontDirection, MultiPolygonExt, TranslateExt};
|
||||
use polygon_art::{load_multipolygon_from_svg_include, Context, MergeExt, ScaleExt};
|
||||
use polygon_art::{AsteroidFont, FontDirection, TranslateExt};
|
||||
use rand::prelude::StdRng;
|
||||
use rand::Rng;
|
||||
|
||||
|
@ -19,12 +19,10 @@ fn main() {
|
|||
let height = context.height;
|
||||
let diagonal = f64::sqrt(width * width + height * height);
|
||||
|
||||
// todo : it does not make to much sense to define all parameters like this
|
||||
// todo : it makes more sense to create a static (diagonal / width /height ratio ) setup and scale it up
|
||||
let frame_offset = diagonal * 0.01;
|
||||
let max_asteroid = (diagonal / 40.) as usize;
|
||||
let max_asteroid = (diagonal / 80.) as usize;
|
||||
|
||||
let min_asteroid_size = diagonal / 40.;
|
||||
let min_asteroid_size = diagonal / 50.;
|
||||
let max_asteroid_size = diagonal / 12.;
|
||||
let ship_length = diagonal / 23.;
|
||||
let ship_orbit = 3.0;
|
||||
|
@ -34,7 +32,7 @@ fn main() {
|
|||
.translate(width / 2., height / 2.);
|
||||
|
||||
// create asteroid
|
||||
let mut asteroids: Vec<MultiPolygon<f64>> = Vec::new();
|
||||
let mut asteroids: MultiPolygon<f64> = MultiPolygon(Vec::new());
|
||||
for _ in 0..(max_asteroid * 2) {
|
||||
let without_orbit = rng.gen_range(min_asteroid_size..max_asteroid_size) as f64;
|
||||
let with_orbit = without_orbit * 1.32;
|
||||
|
@ -44,15 +42,11 @@ fn main() {
|
|||
.scale_to_width(with_orbit)
|
||||
.translate(x, y);
|
||||
|
||||
if (!center_point.intersects(&asteroid))
|
||||
&& asteroids
|
||||
.iter()
|
||||
.find(|&m| *&m.intersects(&asteroid))
|
||||
.is_none()
|
||||
{
|
||||
asteroids.push(asteroid.scale_to_width(without_orbit));
|
||||
if (!center_point.intersects(&asteroid)) && !asteroids.intersects(&asteroid) {
|
||||
// asteroids.push(asteroid.scale_to_width(without_orbit));
|
||||
asteroids.merge_destructive(&mut asteroid.scale_to_width(without_orbit))
|
||||
}
|
||||
if asteroids.len() > max_asteroid {
|
||||
if asteroids.0.len() > max_asteroid {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -123,10 +117,10 @@ fn main() {
|
|||
let window = window.difference(&life_board, 100.);
|
||||
context.draw_multipolygon(&window);
|
||||
|
||||
for asteroid in asteroids.iter() {
|
||||
context.draw_multipolygon(&asteroid.intersection(&window, 100.));
|
||||
}
|
||||
// draw asteroids
|
||||
context.draw_multipolygon(&asteroids.intersection(&window, 100.));
|
||||
|
||||
// render image
|
||||
context.render();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
pub(crate) mod multipolygon_ext;
|
||||
pub(crate) mod merge_ext;
|
||||
pub(crate) mod scale_ext;
|
||||
pub(crate) mod translate_ext;
|
||||
|
|
35
src/extensions/merge_ext.rs
Normal file
35
src/extensions/merge_ext.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use geo::{LineString, MultiLineString, MultiPolygon};
|
||||
|
||||
pub trait MergeExt {
|
||||
/// merge Container object
|
||||
fn merge(&mut self, other: &Self);
|
||||
/// merge container object, empty the other object
|
||||
fn merge_destructive(&mut self, other: &mut Self);
|
||||
}
|
||||
|
||||
impl MergeExt for LineString<f64> {
|
||||
fn merge(&mut self, other: &Self) {
|
||||
self.0.append(&mut other.0.clone());
|
||||
}
|
||||
fn merge_destructive(&mut self, other: &mut Self) {
|
||||
self.0.append(&mut other.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl MergeExt for MultiLineString<f64> {
|
||||
fn merge(&mut self, other: &Self) {
|
||||
self.0.append(&mut other.0.clone());
|
||||
}
|
||||
fn merge_destructive(&mut self, other: &mut Self) {
|
||||
self.0.append(&mut other.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl MergeExt for MultiPolygon<f64> {
|
||||
fn merge(&mut self, other: &Self) {
|
||||
self.0.append(&mut other.0.clone());
|
||||
}
|
||||
fn merge_destructive(&mut self, other: &mut Self) {
|
||||
self.0.append(&mut other.0);
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
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)
|
||||
}
|
||||
}
|
68
src/extensions/scale_ext.rs
Normal file
68
src/extensions/scale_ext.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use crate::extensions::translate_ext::ExplicitBoundingRect;
|
||||
use geo::algorithm::map_coords::MapCoords;
|
||||
use geo::algorithm::translate::Translate;
|
||||
use geo::{CoordinateType, LineString, MultiLineString, MultiPolygon, Polygon};
|
||||
|
||||
pub trait ExplicitMapCoords<T> {
|
||||
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self;
|
||||
}
|
||||
|
||||
impl<T: CoordinateType> ExplicitMapCoords<T> for LineString<T> {
|
||||
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self {
|
||||
self.map_coords(func)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CoordinateType> ExplicitMapCoords<T> for MultiLineString<T> {
|
||||
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self {
|
||||
self.map_coords(func)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CoordinateType> ExplicitMapCoords<T> for MultiPolygon<T> {
|
||||
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self {
|
||||
self.map_coords(func)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CoordinateType> ExplicitMapCoords<T> for Polygon<T> {
|
||||
fn map_coordinates(&self, func: impl Fn(&(T, T)) -> (T, T) + Copy) -> Self {
|
||||
self.map_coords(func)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ScaleExt {
|
||||
/// scale object
|
||||
fn scale(&self, scale_x: f64, scale_y: f64) -> Self;
|
||||
/// scale object to given width (in 1:1 ratio)
|
||||
fn scale_to_width(&self, size: f64) -> Self;
|
||||
/// scale object to given height (in 1:1 ratio)
|
||||
fn scale_to_height(&self, size: f64) -> Self;
|
||||
}
|
||||
|
||||
impl<V> ScaleExt for V
|
||||
where
|
||||
V: ExplicitBoundingRect<f64> + ExplicitMapCoords<f64> + Translate<f64>,
|
||||
{
|
||||
fn scale(&self, scale_x: f64, scale_y: f64) -> Self {
|
||||
let bounding_rectangle = self.bounding().unwrap();
|
||||
let minimum_coordinates = bounding_rectangle.min();
|
||||
self.translate(-minimum_coordinates.x, -minimum_coordinates.y)
|
||||
.map_coordinates(|&(x, y)| (x * scale_x, y * scale_y))
|
||||
.translate(minimum_coordinates.x, minimum_coordinates.y)
|
||||
}
|
||||
|
||||
fn scale_to_width(&self, size: f64) -> Self {
|
||||
let option = self.bounding().unwrap();
|
||||
let diff = f64::abs(option.min().x - option.max().x);
|
||||
let scale = size / diff;
|
||||
self.scale(scale, scale)
|
||||
}
|
||||
|
||||
fn scale_to_height(&self, size: f64) -> Self {
|
||||
let option = self.bounding().unwrap();
|
||||
let diff = f64::abs(option.min().y - option.max().y);
|
||||
let scale = size / diff;
|
||||
self.scale(scale, scale)
|
||||
}
|
||||
}
|
|
@ -2,20 +2,6 @@ use geo::algorithm::bounding_rect::BoundingRect;
|
|||
use geo::algorithm::translate::Translate;
|
||||
use geo::{CoordinateType, LineString, MultiLineString, MultiPolygon, Polygon, Rect};
|
||||
|
||||
/// Translate Extensions
|
||||
pub trait TranslateExt {
|
||||
/// translate the object to it's center
|
||||
fn translate_center(&self) -> Self;
|
||||
/// translate the object to it's center on the x aches
|
||||
fn translate_center_x(&self) -> Self;
|
||||
/// translate the object to it's center on the y aches
|
||||
fn translate_center_y(&self) -> Self;
|
||||
/// translate the object, so it touches the y aches
|
||||
fn translate_left(&self) -> Self;
|
||||
/// translate the object, so it touches the x aches
|
||||
fn translate_top(&self) -> Self;
|
||||
}
|
||||
|
||||
/// wrapper for BoundingRect because of the Output type
|
||||
pub trait ExplicitBoundingRect<T>
|
||||
where
|
||||
|
@ -48,6 +34,20 @@ impl<T: CoordinateType> ExplicitBoundingRect<T> for MultiLineString<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Translate Extensions
|
||||
pub trait TranslateExt {
|
||||
/// translate the object to it's center
|
||||
fn translate_center(&self) -> Self;
|
||||
/// translate the object to it's center on the x aches
|
||||
fn translate_center_x(&self) -> Self;
|
||||
/// translate the object to it's center on the y aches
|
||||
fn translate_center_y(&self) -> Self;
|
||||
/// translate the object, so it touches the y aches
|
||||
fn translate_left(&self) -> Self;
|
||||
/// translate the object, so it touches the x aches
|
||||
fn translate_top(&self) -> Self;
|
||||
}
|
||||
|
||||
impl<B> TranslateExt for B
|
||||
where
|
||||
B: ExplicitBoundingRect<f64> + Translate<f64>,
|
||||
|
|
|
@ -2,7 +2,8 @@ mod context;
|
|||
pub use crate::context::Context;
|
||||
|
||||
mod extensions;
|
||||
pub use crate::extensions::multipolygon_ext::MultiPolygonExt;
|
||||
pub use crate::extensions::merge_ext::MergeExt;
|
||||
pub use crate::extensions::scale_ext::ScaleExt;
|
||||
pub use crate::extensions::translate_ext::TranslateExt;
|
||||
|
||||
mod svg;
|
||||
|
|
Loading…
Reference in a new issue