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::rotate::RotatePoint;
|
||||||
use geo::translate::Translate;
|
use geo::translate::Translate;
|
||||||
use geo::{Coordinate, Point};
|
use geo::{Coordinate, Point};
|
||||||
use polygon_art::load_multipolygon_from_svg;
|
|
||||||
use polygon_art::Context;
|
use polygon_art::Context;
|
||||||
use polygon_art::MultiPolygonExt;
|
|
||||||
use polygon_art::TranslateExt;
|
use polygon_art::TranslateExt;
|
||||||
|
use polygon_art::{load_multipolygon_from_svg, ScaleExt};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -5,8 +5,8 @@ use geo::rotate::RotatePoint;
|
||||||
use geo::LineString;
|
use geo::LineString;
|
||||||
use geo::{polygon, Coordinate, MultiPolygon, Point, Polygon};
|
use geo::{polygon, Coordinate, MultiPolygon, Point, Polygon};
|
||||||
use geo_clipper::Clipper;
|
use geo_clipper::Clipper;
|
||||||
use polygon_art::{load_multipolygon_from_svg_include, Context};
|
use polygon_art::{load_multipolygon_from_svg_include, Context, MergeExt, ScaleExt};
|
||||||
use polygon_art::{AsteroidFont, FontDirection, MultiPolygonExt, TranslateExt};
|
use polygon_art::{AsteroidFont, FontDirection, TranslateExt};
|
||||||
use rand::prelude::StdRng;
|
use rand::prelude::StdRng;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
|
@ -19,12 +19,10 @@ fn main() {
|
||||||
let height = context.height;
|
let height = context.height;
|
||||||
let diagonal = f64::sqrt(width * width + height * 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 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 max_asteroid_size = diagonal / 12.;
|
||||||
let ship_length = diagonal / 23.;
|
let ship_length = diagonal / 23.;
|
||||||
let ship_orbit = 3.0;
|
let ship_orbit = 3.0;
|
||||||
|
@ -34,7 +32,7 @@ fn main() {
|
||||||
.translate(width / 2., height / 2.);
|
.translate(width / 2., height / 2.);
|
||||||
|
|
||||||
// create asteroid
|
// create asteroid
|
||||||
let mut asteroids: Vec<MultiPolygon<f64>> = Vec::new();
|
let mut asteroids: MultiPolygon<f64> = MultiPolygon(Vec::new());
|
||||||
for _ in 0..(max_asteroid * 2) {
|
for _ in 0..(max_asteroid * 2) {
|
||||||
let without_orbit = rng.gen_range(min_asteroid_size..max_asteroid_size) as f64;
|
let without_orbit = rng.gen_range(min_asteroid_size..max_asteroid_size) as f64;
|
||||||
let with_orbit = without_orbit * 1.32;
|
let with_orbit = without_orbit * 1.32;
|
||||||
|
@ -44,15 +42,11 @@ fn main() {
|
||||||
.scale_to_width(with_orbit)
|
.scale_to_width(with_orbit)
|
||||||
.translate(x, y);
|
.translate(x, y);
|
||||||
|
|
||||||
if (!center_point.intersects(&asteroid))
|
if (!center_point.intersects(&asteroid)) && !asteroids.intersects(&asteroid) {
|
||||||
&& asteroids
|
// asteroids.push(asteroid.scale_to_width(without_orbit));
|
||||||
.iter()
|
asteroids.merge_destructive(&mut asteroid.scale_to_width(without_orbit))
|
||||||
.find(|&m| *&m.intersects(&asteroid))
|
|
||||||
.is_none()
|
|
||||||
{
|
|
||||||
asteroids.push(asteroid.scale_to_width(without_orbit));
|
|
||||||
}
|
}
|
||||||
if asteroids.len() > max_asteroid {
|
if asteroids.0.len() > max_asteroid {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,10 +117,10 @@ fn main() {
|
||||||
let window = window.difference(&life_board, 100.);
|
let window = window.difference(&life_board, 100.);
|
||||||
context.draw_multipolygon(&window);
|
context.draw_multipolygon(&window);
|
||||||
|
|
||||||
for asteroid in asteroids.iter() {
|
// draw asteroids
|
||||||
context.draw_multipolygon(&asteroid.intersection(&window, 100.));
|
context.draw_multipolygon(&asteroids.intersection(&window, 100.));
|
||||||
}
|
|
||||||
|
|
||||||
|
// render image
|
||||||
context.render();
|
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;
|
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::algorithm::translate::Translate;
|
||||||
use geo::{CoordinateType, LineString, MultiLineString, MultiPolygon, Polygon, Rect};
|
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
|
/// wrapper for BoundingRect because of the Output type
|
||||||
pub trait ExplicitBoundingRect<T>
|
pub trait ExplicitBoundingRect<T>
|
||||||
where
|
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
|
impl<B> TranslateExt for B
|
||||||
where
|
where
|
||||||
B: ExplicitBoundingRect<f64> + Translate<f64>,
|
B: ExplicitBoundingRect<f64> + Translate<f64>,
|
||||||
|
|
|
@ -2,7 +2,8 @@ mod context;
|
||||||
pub use crate::context::Context;
|
pub use crate::context::Context;
|
||||||
|
|
||||||
mod extensions;
|
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;
|
pub use crate::extensions::translate_ext::TranslateExt;
|
||||||
|
|
||||||
mod svg;
|
mod svg;
|
||||||
|
|
Loading…
Reference in a new issue