From 1574ca725fa86110352a92571eebddd985a4be12 Mon Sep 17 00:00:00 2001 From: Ingolf Wagner Date: Tue, 13 Apr 2021 07:47:29 +0200 Subject: [PATCH] feat: create translate_ext.rs --- examples/font.rs | 10 +-- examples/svg.rs | 1 + src/bin/asteroids.rs | 12 ++-- src/context.rs | 8 ++- src/extensions.rs | 2 + src/{ => extensions}/multipolygon_ext.rs | 28 -------- src/extensions/translate_ext.rs | 87 ++++++++++++++++++++++++ src/font.rs | 6 +- src/lib.rs | 5 +- src/svg.rs | 6 +- 10 files changed, 117 insertions(+), 48 deletions(-) create mode 100644 src/extensions.rs rename src/{ => extensions}/multipolygon_ext.rs (66%) create mode 100644 src/extensions/translate_ext.rs diff --git a/examples/font.rs b/examples/font.rs index 22b4cc5..6475bdf 100644 --- a/examples/font.rs +++ b/examples/font.rs @@ -11,25 +11,25 @@ fn main() { let font = AsteroidFont::new(); let line = font.get_text("Hey there!".to_string(), 12., LeftRight); - context.draw_line_strings(&line); + context.draw_multiline_string(&line); context.draw_line_string(&line_string![(x : 0., y:14.), (x: 1000. , y : 14.)]); context.translate(0.0, 18.); let line = font.get_text("How are you?".to_string(), 22., LeftRight); - context.draw_line_strings(&line); + context.draw_multiline_string(&line); context.translate(0.0, 28.); let line = font.get_text("Here a bitter text!".to_string(), 50., LeftRight); - context.draw_line_strings(&line); + context.draw_multiline_string(&line); context.translate(0.0, 56.); let line = font.get_text("0123456789".to_string(), 50., LeftRight); - context.draw_line_strings(&line); + context.draw_multiline_string(&line); context.restore(); context.translate(30., 50.); let line = font.get_text("0123456789".to_string(), 30., TopDown); - context.draw_line_strings(&line); + context.draw_multiline_string(&line); context.render(); } diff --git a/examples/svg.rs b/examples/svg.rs index 5543e4d..8b0eef9 100644 --- a/examples/svg.rs +++ b/examples/svg.rs @@ -6,6 +6,7 @@ use geo::{Coordinate, Point}; use polygon_art::load_multipolygon_from_svg; use polygon_art::Context; use polygon_art::MultiPolygonExt; +use polygon_art::TranslateExt; use rand::Rng; fn main() { diff --git a/src/bin/asteroids.rs b/src/bin/asteroids.rs index 9f01cc2..a302754 100644 --- a/src/bin/asteroids.rs +++ b/src/bin/asteroids.rs @@ -6,7 +6,7 @@ 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}; +use polygon_art::{AsteroidFont, FontDirection, MultiPolygonExt, TranslateExt}; use rand::prelude::StdRng; use rand::Rng; @@ -91,7 +91,7 @@ fn main() { let score_board_lines = font.get_text(random_seed_string, font_size, FontDirection::LeftRight); context.save(); context.translate(frame_offset, frame_offset); - context.draw_line_strings(&score_board_lines); + context.draw_multiline_string(&score_board_lines); context.restore(); // draw life board @@ -102,17 +102,17 @@ fn main() { (x: width - frame_offset - life * x_font_size - 3., y:frame_offset + y_font_size + 3.), (x: width , y:frame_offset + y_font_size + 3.) ]; - // todo translate_top - // todo translate_left + let life_ship = raw_ship .scale_to_width(font_size) .rotate(-90.) - .translate_center_y(); + .translate_center_y() + .translate_top(); for l in 1..(1 + life as i32) { context.save(); context.translate( width - frame_offset - (x_font_size * l as f64) as f64, - frame_offset + y_font_size / 2., + frame_offset, ); context.draw_multipolygon(&life_ship); context.restore(); diff --git a/src/context.rs b/src/context.rs index 5b46bec..cdc64eb 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,6 @@ use cairo::Format; use cairo::{ImageSurface, SvgSurface}; -use geo::{polygon, LineString, MultiPolygon, Polygon}; +use geo::{polygon, LineString, MultiLineString, MultiPolygon, Polygon}; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; @@ -71,6 +71,12 @@ impl Context { } } + pub fn draw_multiline_string(&self, multilinestring: &MultiLineString) { + for line in multilinestring.iter() { + self.draw_line_string(line); + } + } + /// restore state which was saved before by the context pub fn restore(&self) { self.render_container.context().restore(); diff --git a/src/extensions.rs b/src/extensions.rs new file mode 100644 index 0000000..76f3e22 --- /dev/null +++ b/src/extensions.rs @@ -0,0 +1,2 @@ +pub(crate) mod multipolygon_ext; +pub(crate) mod translate_ext; diff --git a/src/multipolygon_ext.rs b/src/extensions/multipolygon_ext.rs similarity index 66% rename from src/multipolygon_ext.rs rename to src/extensions/multipolygon_ext.rs index f31e86f..8b79290 100644 --- a/src/multipolygon_ext.rs +++ b/src/extensions/multipolygon_ext.rs @@ -4,41 +4,13 @@ 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 { - 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) diff --git a/src/extensions/translate_ext.rs b/src/extensions/translate_ext.rs new file mode 100644 index 0000000..1dee99f --- /dev/null +++ b/src/extensions/translate_ext.rs @@ -0,0 +1,87 @@ +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 +where + T: CoordinateType, +{ + fn bounding(&self) -> Option>; +} + +impl ExplicitBoundingRect for Polygon { + fn bounding(&self) -> Option> { + self.bounding_rect() + } +} + +impl ExplicitBoundingRect for MultiPolygon { + fn bounding(&self) -> Option> { + self.bounding_rect() + } +} + +impl ExplicitBoundingRect for LineString { + fn bounding(&self) -> Option> { + self.bounding_rect() + } +} + +impl ExplicitBoundingRect for MultiLineString { + fn bounding(&self) -> Option> { + self.bounding_rect() + } +} + +impl TranslateExt for B +where + B: ExplicitBoundingRect + Translate, +{ + fn translate_center(&self) -> Self { + let option = self.bounding().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().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().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 translate_left(&self) -> Self { + let bounding = self.bounding().unwrap(); + self.translate(-bounding.min().x, 0.) + } + + fn translate_top(&self) -> Self { + let bounding = self.bounding().unwrap(); + self.translate(0., -bounding.min().y) + } +} diff --git a/src/font.rs b/src/font.rs index 34e5915..bbc7aa8 100644 --- a/src/font.rs +++ b/src/font.rs @@ -2,7 +2,7 @@ // https://github.com/osresearch/vst/blob/master/teensyv/asteroids_font.c use geo::algorithm::translate::Translate; -use geo::{Coordinate, LineString}; +use geo::{Coordinate, LineString, MultiLineString}; use std::collections::HashMap; pub struct AsteroidFont { @@ -112,7 +112,7 @@ impl AsteroidFont { text: String, size: f64, direction: FontDirection, - ) -> Vec> { + ) -> MultiLineString { let mut letters: Vec> = Vec::new(); let mut count = 0.; for char in text.chars() { @@ -130,7 +130,7 @@ impl AsteroidFont { } count = count + 1.; } - letters + MultiLineString(letters) } } diff --git a/src/lib.rs b/src/lib.rs index c1aecd4..18a3ad2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,9 @@ mod context; pub use crate::context::Context; -mod multipolygon_ext; -pub use crate::multipolygon_ext::MultiPolygonExt; +mod extensions; +pub use crate::extensions::multipolygon_ext::MultiPolygonExt; +pub use crate::extensions::translate_ext::TranslateExt; mod svg; pub use crate::svg::load_multipolygon_from_svg; diff --git a/src/svg.rs b/src/svg.rs index 287bfae..d3b3158 100644 --- a/src/svg.rs +++ b/src/svg.rs @@ -9,7 +9,7 @@ use svg::Parser; pub fn load_multipolygon_from_svg(path: &str) -> Result, Box> { let mut content = String::new(); let parser = svg::open(path, &mut content)?; - parse_svg(parser) + parse_svg_to_multipolygon(parser) } /// load a multipolygon statically at compiletime @@ -18,11 +18,11 @@ pub fn load_multipolygon_from_svg_include( content: &str, ) -> Result, Box> { let parser = svg::read(content)?; - parse_svg(parser) + parse_svg_to_multipolygon(parser) } #[allow(non_upper_case_globals)] -fn parse_svg(parser: Parser) -> Result, Box> { +fn parse_svg_to_multipolygon(parser: Parser) -> Result, Box> { let mut result: Vec> = Vec::new(); for event in parser { match event {