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