nannou/geom/
path.rs

1//! Items related to working with paths for 2D geometry and vector graphics.
2//!
3//! This module attempts to provide abstractions around the various `Path` and `Builder` types
4//! offerred by `lyon` in a way that interoperates a little more fluidly and consistently with the
5//! rest of nannou's API.
6
7use crate::geom::Point2;
8
9/// A wrapper around a 2D lyon path exposing a nannou-friendly API.
10pub struct Path {
11    path: lyon::path::Path,
12}
13
14/// A type used for building a 2D lyon path.
15pub struct Builder {
16    builder: lyon::path::path::Builder,
17}
18
19impl Path {
20    /// Begin building a new path.
21    pub fn builder() -> Builder {
22        Builder::new()
23    }
24
25    /// Create an empty path.
26    pub fn new() -> Self {
27        lyon::path::Path::new().into()
28    }
29
30    /// Returns a lyon view on this **Path**.
31    pub fn as_slice(&self) -> lyon::path::PathSlice {
32        self.path.as_slice()
33    }
34
35    /// Returns a slice over an endpoint's custom attributes.
36    pub fn attributes(&self, endpoint: lyon::path::EndpointId) -> &[f32] {
37        self.path.attributes(endpoint)
38    }
39
40    /// Iterates over the entire **Path** yielding **PathEvent**s.
41    pub fn iter(&self) -> lyon::path::path::Iter {
42        self.path.iter()
43    }
44
45    /// Iterates over the endpoint and control point ids of the **Path**.
46    pub fn id_iter(&self) -> lyon::path::path::IdIter {
47        self.path.id_iter()
48    }
49
50    /// Iterate over points alongside their attributes.
51    pub fn iter_with_attributes(&self) -> lyon::path::path::IterWithAttributes {
52        self.path.iter_with_attributes()
53    }
54
55    /// Applies a transform to all endpoints and control points of this path and returns the
56    /// result.
57    pub fn transformed<T>(self, transform: &T) -> Self
58    where
59        T: lyon::geom::traits::Transformation<f32>,
60    {
61        self.path.transformed(transform).into()
62    }
63
64    /// Reversed version of this path with edge loops specified in the opposite order.
65    pub fn reversed(&self) -> Self {
66        self.path.reversed().into()
67    }
68
69    /// Concatenate two paths.
70    pub fn merge(&self, other: &Self) -> Self {
71        Self {
72            path: self.path.iter().chain(other.iter()).collect(),
73        }
74    }
75}
76
77impl Builder {
78    /// Begin building a new path.
79    pub fn new() -> Self {
80        lyon::path::path::Builder::new().into()
81    }
82
83    /// Build a path with the given capacity for the inner path event storage.
84    pub fn with_capacity(points: usize, edges: usize) -> Self {
85        lyon::path::path::Builder::with_capacity(points, edges).into()
86    }
87
88    /// Returns a lyon builder that supports SVG commands.
89    pub fn with_svg(self) -> lyon::path::builder::WithSvg<Self> {
90        lyon::path::builder::WithSvg::new(self)
91    }
92
93    /// Returns a lyon builder that approximates all curves with sequences of line segments.
94    pub fn flattened(self, tolerance: f32) -> lyon::path::builder::Flattened<Self> {
95        lyon::path::builder::Flattened::new(self, tolerance)
96    }
97
98    /// Sets the position in preparation for the next sub-path.
99    ///
100    /// If the current sub-path contains edges, this ends the sub-path without closing it.
101    pub fn begin(mut self, to: Point2) -> Self {
102        self.builder.begin(to.to_array().into());
103        self
104    }
105
106    /// Adds a line segment to the current sub-path and sets the current position.
107    pub fn line_to(mut self, to: Point2) -> Self {
108        self.builder.line_to(to.to_array().into());
109        self
110    }
111
112    /// Closes the current sub path and sets the current position to the first position of the
113    /// current sub-path.
114    pub fn close(mut self) -> Self {
115        self.builder.close();
116        self
117    }
118
119    /// Add a quadratic bezier curve to the path.
120    pub fn quadratic_bezier_to(mut self, ctrl: Point2, to: Point2) -> Self {
121        self.builder
122            .quadratic_bezier_to(ctrl.to_array().into(), to.to_array().into());
123        self
124    }
125
126    /// Add a cubic bezier curve to the path.
127    pub fn cubic_bezier_to(mut self, ctrl1: Point2, ctrl2: Point2, to: Point2) -> Self {
128        self.builder.cubic_bezier_to(
129            ctrl1.to_array().into(),
130            ctrl2.to_array().into(),
131            to.to_array().into(),
132        );
133        self
134    }
135
136    /// Build the path and return it.
137    pub fn build(self) -> Path {
138        self.builder.build().into()
139    }
140
141    /// Access to the inner `lyon::path::Builder`.
142    pub fn inner(&self) -> &lyon::path::path::Builder {
143        &self.builder
144    }
145
146    /// Mutable access to the inner `lyon::path::Builder`.
147    pub fn inner_mut(&mut self) -> &mut lyon::path::path::Builder {
148        &mut self.builder
149    }
150}
151
152// lyon builder traits
153
154impl lyon::path::builder::Build for Builder {
155    type PathType = Path;
156
157    fn build(self) -> Self::PathType {
158        self.builder.build().into()
159    }
160}
161
162impl lyon::path::builder::PathBuilder for Builder {
163    fn quadratic_bezier_to(
164        &mut self,
165        ctrl: lyon::math::Point,
166        to: lyon::math::Point,
167    ) -> lyon::path::EndpointId {
168        self.builder.quadratic_bezier_to(ctrl, to)
169    }
170
171    fn cubic_bezier_to(
172        &mut self,
173        ctrl1: lyon::math::Point,
174        ctrl2: lyon::math::Point,
175        to: lyon::math::Point,
176    ) -> lyon::path::EndpointId {
177        self.builder.cubic_bezier_to(ctrl1, ctrl2, to)
178    }
179
180    fn begin(&mut self, at: lyon::math::Point) -> lyon::path::EndpointId {
181        self.builder.begin(at)
182    }
183
184    fn end(&mut self, close: bool) {
185        self.builder.end(close)
186    }
187
188    fn line_to(&mut self, to: lyon::math::Point) -> lyon::path::EndpointId {
189        self.builder.line_to(to)
190    }
191}
192
193// Indexing
194
195impl std::ops::Index<lyon::path::ControlPointId> for Path {
196    type Output = Point2;
197    fn index(&self, id: lyon::path::ControlPointId) -> &Self::Output {
198        point_lyon_to_nannou(self.path.index(id))
199    }
200}
201
202impl std::ops::Index<lyon::path::EndpointId> for Path {
203    type Output = Point2;
204    fn index(&self, id: lyon::path::EndpointId) -> &Self::Output {
205        point_lyon_to_nannou(self.path.index(id))
206    }
207}
208
209// Path iteration
210
211impl<'a> IntoIterator for &'a Path {
212    type Item = lyon::path::PathEvent;
213    type IntoIter = lyon::path::path::Iter<'a>;
214
215    fn into_iter(self) -> Self::IntoIter {
216        self.iter()
217    }
218}
219
220// Conversions
221
222impl From<lyon::path::Path> for Path {
223    fn from(path: lyon::path::Path) -> Self {
224        Path { path }
225    }
226}
227
228impl From<lyon::path::path::Builder> for Builder {
229    fn from(builder: lyon::path::path::Builder) -> Self {
230        Builder { builder }
231    }
232}
233
234impl Into<lyon::path::Path> for Path {
235    fn into(self) -> lyon::path::Path {
236        self.path
237    }
238}
239
240impl Into<lyon::path::path::Builder> for Builder {
241    fn into(self) -> lyon::path::path::Builder {
242        self.builder
243    }
244}
245
246impl<'a> Into<lyon::path::PathSlice<'a>> for &'a Path {
247    fn into(self) -> lyon::path::PathSlice<'a> {
248        self.as_slice()
249    }
250}
251
252// Simplified constructors
253
254/// Begin building a path.
255pub fn path() -> Builder {
256    Builder::new()
257}
258
259/// Build a path with the given capacity for the inner path event storage.
260pub fn path_with_capacity(points: usize, edges: usize) -> Builder {
261    Builder::with_capacity(points, edges)
262}
263
264// Conversions between slice types.
265//
266// The following conversions are safe as both `Point2` and `lyon::path::Point` have the same size,
267// fields and `repr(C)` layout.
268
269fn point_lyon_to_nannou(p: &lyon::math::Point) -> &Point2 {
270    unsafe { std::mem::transmute(p) }
271}