topola/src/bin/topola-sdl2-demo/painter.rs

99 lines
3.6 KiB
Rust

use geo::{CoordsIter, Point, Polygon};
use pathfinder_canvas::{
vec2f, ArcDirection, Canvas, CanvasRenderingContext2D, ColorU, FillRule, Path2D, RectF,
};
use topola::geometry::primitive::{PrimitiveShape, PrimitiveShapeTrait};
pub struct Painter<'a> {
canvas: &'a mut CanvasRenderingContext2D,
}
impl<'a> Painter<'a> {
pub fn new(canvas: &'a mut CanvasRenderingContext2D) -> Self {
Self { canvas }
}
pub fn paint_primitive(&mut self, shape: &PrimitiveShape, color: ColorU, zoom: f32) {
self.canvas.set_stroke_style(color);
self.canvas.set_fill_style(color);
match shape {
PrimitiveShape::Dot(dot) => {
let mut path = Path2D::new();
path.ellipse(
vec2f(dot.c.pos.x() as f32, -dot.c.pos.y() as f32),
dot.c.r as f32,
0.0,
0.0,
std::f32::consts::TAU,
);
self.canvas.fill_path(path, FillRule::Winding);
}
PrimitiveShape::Seg(seg) => {
let mut path = Path2D::new();
path.move_to(vec2f(seg.from.x() as f32, -seg.from.y() as f32));
path.line_to(vec2f(seg.to.x() as f32, -seg.to.y() as f32));
self.canvas.set_line_width(seg.width as f32);
self.canvas.stroke_path(path);
}
PrimitiveShape::Bend(bend) => {
let delta1 = bend.from - bend.c.pos;
let delta2 = bend.to - bend.c.pos;
let angle1 = delta1.y().atan2(delta1.x());
let angle2 = delta2.y().atan2(delta2.x());
let mut path = Path2D::new();
path.arc(
vec2f(bend.c.pos.x() as f32, -bend.c.pos.y() as f32),
bend.circle().r as f32,
angle1 as f32,
angle2 as f32,
ArcDirection::CW,
);
self.canvas.set_line_width(bend.width as f32);
self.canvas.stroke_path(path);
}
}
let envelope = PrimitiveShapeTrait::envelope(shape, 0.0);
// XXX: points represented as arrays can't be conveniently converted to vector types
let topleft = vec2f(envelope.lower()[0] as f32, -envelope.upper()[1] as f32);
let bottomright = vec2f(envelope.upper()[0] as f32, -envelope.lower()[1] as f32);
self.canvas.set_line_width(2.0 / zoom);
self.canvas
.set_stroke_style(ColorU::new(100, 100, 100, 255));
self.canvas
.stroke_rect(RectF::new(topleft, bottomright - topleft));
}
pub fn paint_polygon(&mut self, polygon: &Polygon, color: ColorU, zoom: f32) {
let mut path = Path2D::new();
let mut it = polygon.exterior_coords_iter();
if let Some(initial_vertex) = it.next() {
path.move_to(vec2f(initial_vertex.x as f32, -initial_vertex.y as f32));
}
for vertex in it {
path.line_to(vec2f(vertex.x as f32, -vertex.y as f32));
}
path.close_path();
self.canvas.set_stroke_style(color);
self.canvas.set_fill_style(color);
self.canvas.set_line_width(0.0);
self.canvas.fill_path(path, FillRule::Winding);
}
pub fn paint_edge(&mut self, from: Point, to: Point, color: ColorU, zoom: f32) {
let mut path = Path2D::new();
path.move_to(vec2f(from.x() as f32, from.y() as f32));
path.line_to(vec2f(to.x() as f32, to.y() as f32));
self.canvas.set_stroke_style(color);
self.canvas.set_line_width(2.0 / zoom);
self.canvas.stroke_path(path);
}
}