geometry.rs

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