feat: create translate_ext.rs

develop
Ingolf Wagner 2021-04-13 07:47:29 +02:00
parent e169456958
commit 1574ca725f
Signed by: palo
GPG Key ID: 76BF5F1928B9618B
10 changed files with 117 additions and 48 deletions

View File

@ -11,25 +11,25 @@ fn main() {
let font = AsteroidFont::new(); let font = AsteroidFont::new();
let line = font.get_text("Hey there!".to_string(), 12., LeftRight); 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.draw_line_string(&line_string![(x : 0., y:14.), (x: 1000. , y : 14.)]);
context.translate(0.0, 18.); context.translate(0.0, 18.);
let line = font.get_text("How are you?".to_string(), 22., LeftRight); 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.); context.translate(0.0, 28.);
let line = font.get_text("Here a bitter text!".to_string(), 50., LeftRight); 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.); context.translate(0.0, 56.);
let line = font.get_text("0123456789".to_string(), 50., LeftRight); let line = font.get_text("0123456789".to_string(), 50., LeftRight);
context.draw_line_strings(&line); context.draw_multiline_string(&line);
context.restore(); context.restore();
context.translate(30., 50.); context.translate(30., 50.);
let line = font.get_text("0123456789".to_string(), 30., TopDown); let line = font.get_text("0123456789".to_string(), 30., TopDown);
context.draw_line_strings(&line); context.draw_multiline_string(&line);
context.render(); context.render();
} }

View File

@ -6,6 +6,7 @@ use geo::{Coordinate, Point};
use polygon_art::load_multipolygon_from_svg; use polygon_art::load_multipolygon_from_svg;
use polygon_art::Context; use polygon_art::Context;
use polygon_art::MultiPolygonExt; use polygon_art::MultiPolygonExt;
use polygon_art::TranslateExt;
use rand::Rng; use rand::Rng;
fn main() { fn main() {

View File

@ -6,7 +6,7 @@ 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};
use polygon_art::{AsteroidFont, FontDirection, MultiPolygonExt}; use polygon_art::{AsteroidFont, FontDirection, MultiPolygonExt, TranslateExt};
use rand::prelude::StdRng; use rand::prelude::StdRng;
use rand::Rng; use rand::Rng;
@ -91,7 +91,7 @@ fn main() {
let score_board_lines = font.get_text(random_seed_string, font_size, FontDirection::LeftRight); let score_board_lines = font.get_text(random_seed_string, font_size, FontDirection::LeftRight);
context.save(); context.save();
context.translate(frame_offset, frame_offset); context.translate(frame_offset, frame_offset);
context.draw_line_strings(&score_board_lines); context.draw_multiline_string(&score_board_lines);
context.restore(); context.restore();
// draw life board // 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 - frame_offset - life * x_font_size - 3., y:frame_offset + y_font_size + 3.),
(x: width , 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 let life_ship = raw_ship
.scale_to_width(font_size) .scale_to_width(font_size)
.rotate(-90.) .rotate(-90.)
.translate_center_y(); .translate_center_y()
.translate_top();
for l in 1..(1 + life as i32) { for l in 1..(1 + life as i32) {
context.save(); context.save();
context.translate( context.translate(
width - frame_offset - (x_font_size * l as f64) as f64, 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.draw_multipolygon(&life_ship);
context.restore(); context.restore();

View File

@ -1,6 +1,6 @@
use cairo::Format; use cairo::Format;
use cairo::{ImageSurface, SvgSurface}; use cairo::{ImageSurface, SvgSurface};
use geo::{polygon, LineString, MultiPolygon, Polygon}; use geo::{polygon, LineString, MultiLineString, MultiPolygon, Polygon};
use rand::rngs::StdRng; use rand::rngs::StdRng;
use rand::{Rng, SeedableRng}; use rand::{Rng, SeedableRng};
@ -71,6 +71,12 @@ impl Context {
} }
} }
pub fn draw_multiline_string(&self, multilinestring: &MultiLineString<f64>) {
for line in multilinestring.iter() {
self.draw_line_string(line);
}
}
/// restore state which was saved before by the context /// restore state which was saved before by the context
pub fn restore(&self) { pub fn restore(&self) {
self.render_container.context().restore(); self.render_container.context().restore();

2
src/extensions.rs Normal file
View File

@ -0,0 +1,2 @@
pub(crate) mod multipolygon_ext;
pub(crate) mod translate_ext;

View File

@ -4,41 +4,13 @@ use geo::Polygon;
use geo_types::{Coordinate, LineString, MultiPolygon}; use geo_types::{Coordinate, LineString, MultiPolygon};
pub trait MultiPolygonExt { 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_to_width(&self, size: f64) -> Self;
fn scale(&self, factor: f64) -> Self; fn scale(&self, factor: f64) -> Self;
} }
impl MultiPolygonExt for MultiPolygon<f64> { 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 { 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 option = self.bounding_rect().unwrap();
let diff = f64::abs(option.min().x - option.max().x); let diff = f64::abs(option.min().x - option.max().x);
let scale = size / diff; let scale = size / diff;
self.scale(scale) self.scale(scale)

View File

@ -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<T>
where
T: CoordinateType,
{
fn bounding(&self) -> Option<Rect<T>>;
}
impl<T: CoordinateType> ExplicitBoundingRect<T> for Polygon<T> {
fn bounding(&self) -> Option<Rect<T>> {
self.bounding_rect()
}
}
impl<T: CoordinateType> ExplicitBoundingRect<T> for MultiPolygon<T> {
fn bounding(&self) -> Option<Rect<T>> {
self.bounding_rect()
}
}
impl<T: CoordinateType> ExplicitBoundingRect<T> for LineString<T> {
fn bounding(&self) -> Option<Rect<T>> {
self.bounding_rect()
}
}
impl<T: CoordinateType> ExplicitBoundingRect<T> for MultiLineString<T> {
fn bounding(&self) -> Option<Rect<T>> {
self.bounding_rect()
}
}
impl<B> TranslateExt for B
where
B: ExplicitBoundingRect<f64> + Translate<f64>,
{
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)
}
}

View File

@ -2,7 +2,7 @@
// https://github.com/osresearch/vst/blob/master/teensyv/asteroids_font.c // https://github.com/osresearch/vst/blob/master/teensyv/asteroids_font.c
use geo::algorithm::translate::Translate; use geo::algorithm::translate::Translate;
use geo::{Coordinate, LineString}; use geo::{Coordinate, LineString, MultiLineString};
use std::collections::HashMap; use std::collections::HashMap;
pub struct AsteroidFont { pub struct AsteroidFont {
@ -112,7 +112,7 @@ impl AsteroidFont {
text: String, text: String,
size: f64, size: f64,
direction: FontDirection, direction: FontDirection,
) -> Vec<LineString<f64>> { ) -> MultiLineString<f64> {
let mut letters: Vec<LineString<f64>> = Vec::new(); let mut letters: Vec<LineString<f64>> = Vec::new();
let mut count = 0.; let mut count = 0.;
for char in text.chars() { for char in text.chars() {
@ -130,7 +130,7 @@ impl AsteroidFont {
} }
count = count + 1.; count = count + 1.;
} }
letters MultiLineString(letters)
} }
} }

View File

@ -1,8 +1,9 @@
mod context; mod context;
pub use crate::context::Context; pub use crate::context::Context;
mod multipolygon_ext; mod extensions;
pub use crate::multipolygon_ext::MultiPolygonExt; pub use crate::extensions::multipolygon_ext::MultiPolygonExt;
pub use crate::extensions::translate_ext::TranslateExt;
mod svg; mod svg;
pub use crate::svg::load_multipolygon_from_svg; pub use crate::svg::load_multipolygon_from_svg;

View File

@ -9,7 +9,7 @@ use svg::Parser;
pub fn load_multipolygon_from_svg(path: &str) -> Result<MultiPolygon<f64>, Box<dyn Error>> { pub fn load_multipolygon_from_svg(path: &str) -> Result<MultiPolygon<f64>, Box<dyn Error>> {
let mut content = String::new(); let mut content = String::new();
let parser = svg::open(path, &mut content)?; let parser = svg::open(path, &mut content)?;
parse_svg(parser) parse_svg_to_multipolygon(parser)
} }
/// load a multipolygon statically at compiletime /// load a multipolygon statically at compiletime
@ -18,11 +18,11 @@ pub fn load_multipolygon_from_svg_include(
content: &str, content: &str,
) -> Result<MultiPolygon<f64>, Box<dyn Error>> { ) -> Result<MultiPolygon<f64>, Box<dyn Error>> {
let parser = svg::read(content)?; let parser = svg::read(content)?;
parse_svg(parser) parse_svg_to_multipolygon(parser)
} }
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
fn parse_svg(parser: Parser) -> Result<MultiPolygon<f64>, Box<dyn Error>> { fn parse_svg_to_multipolygon(parser: Parser) -> Result<MultiPolygon<f64>, Box<dyn Error>> {
let mut result: Vec<Polygon<f64>> = Vec::new(); let mut result: Vec<Polygon<f64>> = Vec::new();
for event in parser { for event in parser {
match event { match event {