geometry.rs

  1use super::scene::{Path, PathVertex};
  2use crate::{color::ColorU, json::ToJson};
  3pub use pathfinder_geometry::*;
  4use rect::RectF;
  5use serde_json::json;
  6use vector::{vec2f, Vector2F};
  7
  8pub struct PathBuilder {
  9    vertices: Vec<PathVertex>,
 10    start: Vector2F,
 11    current: Vector2F,
 12    contour_count: usize,
 13    bounds: RectF,
 14}
 15
 16enum PathVertexKind {
 17    Solid,
 18    Quadratic,
 19}
 20
 21impl PathBuilder {
 22    pub fn new() -> Self {
 23        Self {
 24            vertices: Vec::new(),
 25            start: vec2f(0., 0.),
 26            current: vec2f(0., 0.),
 27            contour_count: 0,
 28            bounds: RectF::default(),
 29        }
 30    }
 31
 32    pub fn reset(&mut self, point: Vector2F) {
 33        self.vertices.clear();
 34        self.start = point;
 35        self.current = point;
 36        self.contour_count = 0;
 37    }
 38
 39    pub fn line_to(&mut self, point: Vector2F) {
 40        self.contour_count += 1;
 41        if self.contour_count > 1 {
 42            self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
 43        }
 44
 45        self.current = point;
 46    }
 47
 48    pub fn curve_to(&mut self, point: Vector2F, ctrl: Vector2F) {
 49        self.contour_count += 1;
 50        if self.contour_count > 1 {
 51            self.push_triangle(self.start, self.current, point, PathVertexKind::Solid);
 52        }
 53
 54        self.push_triangle(self.current, ctrl, point, PathVertexKind::Quadratic);
 55        self.current = point;
 56    }
 57
 58    pub fn build(mut self, color: ColorU, clip_bounds: Option<RectF>) -> Path {
 59        if let Some(clip_bounds) = clip_bounds {
 60            self.bounds = self
 61                .bounds
 62                .intersection(clip_bounds)
 63                .unwrap_or(RectF::default());
 64        }
 65        Path {
 66            bounds: self.bounds,
 67            color,
 68            vertices: self.vertices,
 69        }
 70    }
 71
 72    fn push_triangle(&mut self, a: Vector2F, b: Vector2F, c: Vector2F, kind: PathVertexKind) {
 73        if self.vertices.is_empty() {
 74            self.bounds = RectF::new(a, Vector2F::zero());
 75        }
 76        self.bounds = self.bounds.union_point(a).union_point(b).union_point(c);
 77
 78        match kind {
 79            PathVertexKind::Solid => {
 80                self.vertices.push(PathVertex {
 81                    xy_position: a,
 82                    st_position: vec2f(0., 1.),
 83                });
 84                self.vertices.push(PathVertex {
 85                    xy_position: b,
 86                    st_position: vec2f(0., 1.),
 87                });
 88                self.vertices.push(PathVertex {
 89                    xy_position: c,
 90                    st_position: vec2f(0., 1.),
 91                });
 92            }
 93            PathVertexKind::Quadratic => {
 94                self.vertices.push(PathVertex {
 95                    xy_position: a,
 96                    st_position: vec2f(0., 0.),
 97                });
 98                self.vertices.push(PathVertex {
 99                    xy_position: b,
100                    st_position: vec2f(0.5, 0.),
101                });
102                self.vertices.push(PathVertex {
103                    xy_position: c,
104                    st_position: vec2f(1., 1.),
105                });
106            }
107        }
108    }
109}
110
111impl ToJson for Vector2F {
112    fn to_json(&self) -> serde_json::Value {
113        json!([self.x(), self.y()])
114    }
115}
116
117impl ToJson for RectF {
118    fn to_json(&self) -> serde_json::Value {
119        json!({"origin": self.origin().to_json(), "size": self.size().to_json()})
120    }
121}