147 lines
4.5 KiB
Rust
147 lines
4.5 KiB
Rust
use cairo::Format;
|
|
use cairo::{ImageSurface, SvgSurface};
|
|
use geo_types::{LineString, MultiPolygon, Polygon};
|
|
use rand::rngs::StdRng;
|
|
use rand::{Rng, SeedableRng};
|
|
|
|
use crate::context::commandline::Opt;
|
|
use crate::context::palette::Palette;
|
|
use crate::context::renderer::{PngRenderContainer, RenderContainer, SvgRenderContainer};
|
|
|
|
pub mod commandline;
|
|
pub mod palette;
|
|
pub mod renderer;
|
|
|
|
pub struct Context {
|
|
render_container: Box<dyn RenderContainer>,
|
|
pub height: f64,
|
|
pub width: f64,
|
|
pub line_size: f64,
|
|
pub pseudo_random_number_generator: Box<StdRng>,
|
|
}
|
|
|
|
impl Context {
|
|
pub fn draw_multipolgon(&self, multi_polygon: &MultiPolygon<f64>) {
|
|
for polygon in multi_polygon.iter() {
|
|
self.draw_polygon(polygon);
|
|
}
|
|
}
|
|
|
|
pub fn draw_polygon(&self, polygon: &Polygon<f64>) {
|
|
self.plot_line_string(polygon.exterior());
|
|
for interior in polygon.interiors() {
|
|
self.plot_line_string(interior);
|
|
}
|
|
}
|
|
|
|
fn plot_line_string(&self, line_string: &LineString<f64>) {
|
|
let context = self.render_container.context();
|
|
let mut init = true;
|
|
for point in line_string.clone().into_points() {
|
|
if init {
|
|
context.move_to(point.x(), point.y());
|
|
init = false;
|
|
} else {
|
|
context.line_to(point.x(), point.y());
|
|
}
|
|
}
|
|
context.stroke();
|
|
}
|
|
}
|
|
|
|
// cairo facades
|
|
impl Context {
|
|
/// restore state which was saved before by the context
|
|
pub fn restore(&self) {
|
|
self.render_container.context().restore();
|
|
}
|
|
|
|
/// scale, but line with stays
|
|
pub fn scale(&self, factor: f64) {
|
|
let context = self.render_container.context();
|
|
context.save();
|
|
context.scale(factor, factor);
|
|
context.set_line_width(1. / factor);
|
|
}
|
|
|
|
/// translate to the center of the image
|
|
pub fn translate_center(&self) {
|
|
self.translate(self.width / 2., self.height / 2.);
|
|
}
|
|
|
|
/// translate to a position
|
|
pub fn translate(&self, tx: f64, ty: f64) {
|
|
let context = self.render_container.context();
|
|
context.save();
|
|
context.translate(tx, ty);
|
|
}
|
|
|
|
/// plot a path
|
|
// pub fn plot_object(&self, object: &Object) {
|
|
// self.render_container.plot_object(object);
|
|
// }
|
|
|
|
/// plot a path
|
|
// pub fn plot_polygon(&self, polygon: &OldPolynom) {
|
|
// self.plot_path(&polygon.path, polygon.filled);
|
|
// }
|
|
|
|
/// plot a path
|
|
// pub fn plot_path(&self, path: &Vec<[f64; 2]>, fill: bool) {
|
|
// self.render_container.plot_path(path, fill);
|
|
// }
|
|
|
|
pub fn render(self) {
|
|
self.render_container.render();
|
|
}
|
|
|
|
pub fn create() -> Context {
|
|
let opt = Opt::get_command_line_arguments();
|
|
let height = f64::from(opt.height.clone());
|
|
let width = f64::from(opt.width.clone());
|
|
let line_size = opt.line_size.clone();
|
|
let random_seed = match opt.random_seed {
|
|
Some(random_seed) => random_seed,
|
|
None => rand::random(),
|
|
};
|
|
println!("random seed {}", random_seed);
|
|
let mut rng = StdRng::seed_from_u64(random_seed);
|
|
|
|
// color
|
|
let y: f32 = rng.gen(); // generates a float between 0 and 1
|
|
let hue: f32 = y * 360.0;
|
|
let saturation: f32 = f32::max(rng.gen(), 0.6);
|
|
let value: f32 = f32::max(rng.gen(), 0.6);
|
|
let palette = Palette::dark_on_bright(Palette::color(hue, saturation, value));
|
|
|
|
let render_container: Box<dyn RenderContainer> = if opt.svg {
|
|
let svg_surface = SvgSurface::new(
|
|
f64::from(width),
|
|
f64::from(height),
|
|
Some(opt.output.as_path()),
|
|
)
|
|
.expect("Can't svg surface");
|
|
Box::new(SvgRenderContainer::new(svg_surface, palette)) as Box<dyn RenderContainer>
|
|
} else {
|
|
let png_surface =
|
|
ImageSurface::create(Format::Rgb24, opt.width.clone(), opt.height.clone())
|
|
.expect("Can't create png surface");
|
|
Box::new(PngRenderContainer::new(
|
|
opt.output.to_string_lossy().to_string(),
|
|
png_surface,
|
|
palette,
|
|
)) as Box<dyn RenderContainer>
|
|
};
|
|
|
|
render_container.init(width as f64, height as f64, line_size);
|
|
|
|
Context {
|
|
height,
|
|
width,
|
|
line_size,
|
|
pseudo_random_number_generator: Box::new(rng),
|
|
render_container,
|
|
}
|
|
}
|
|
}
|