feat: create translate_ext.rs
This commit is contained in:
parent
e169456958
commit
1574ca725f
10 changed files with 117 additions and 48 deletions
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
2
src/extensions.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub(crate) mod multipolygon_ext;
|
||||||
|
pub(crate) mod translate_ext;
|
|
@ -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)
|
87
src/extensions/translate_ext.rs
Normal file
87
src/extensions/translate_ext.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue