nannou/draw/properties/
stroke.rs

1use lyon::tessellation::{LineCap, LineJoin, StrokeOptions};
2
3/// Nodes that support stroke tessellation.
4///
5/// This trait allows the `Drawing` context to automatically provide an implementation of the
6/// following builder methods for all primitives that provide some stroke tessellation options.
7pub trait SetStroke: Sized {
8    /// Provide a mutable reference to the `StrokeOptions` field.
9    fn stroke_options_mut(&mut self) -> &mut StrokeOptions;
10
11    /// Specify the whole set of stroke tessellation options.
12    fn stroke_opts(mut self, opts: StrokeOptions) -> Self {
13        *self.stroke_options_mut() = opts;
14        self
15    }
16
17    /// The start line cap as specified by the SVG spec.
18    fn start_cap(mut self, cap: LineCap) -> Self {
19        self.stroke_options_mut().start_cap = cap;
20        self
21    }
22
23    /// The end line cap as specified by the SVG spec.
24    fn end_cap(mut self, cap: LineCap) -> Self {
25        self.stroke_options_mut().end_cap = cap;
26        self
27    }
28
29    /// The start and end line cap as specified by the SVG spec.
30    fn caps(self, cap: LineCap) -> Self {
31        self.start_cap(cap).end_cap(cap)
32    }
33
34    /// The stroke for each sub-path does not extend beyond its two endpoints. A zero length
35    /// sub-path will therefore not have any stroke.
36    fn start_cap_butt(self) -> Self {
37        self.start_cap(LineCap::Butt)
38    }
39
40    /// At the end of each sub-path, the shape representing the stroke will be extended by a
41    /// rectangle with the same width as the stroke width and whose length is half of the stroke
42    /// width. If a sub-path has zero length, then the resulting effect is that the stroke for that
43    /// sub-path consists solely of a square with side length equal to the stroke width, centered
44    /// at the sub-path's point.
45    fn start_cap_square(self) -> Self {
46        self.start_cap(LineCap::Square)
47    }
48
49    /// At each end of each sub-path, the shape representing the stroke will be extended by a half
50    /// circle with a radius equal to the stroke width. If a sub-path has zero length, then the
51    /// resulting effect is that the stroke for that sub-path consists solely of a full circle
52    /// centered at the sub-path's point.
53    fn start_cap_round(self) -> Self {
54        self.start_cap(LineCap::Round)
55    }
56
57    /// The stroke for each sub-path does not extend beyond its two endpoints. A zero length
58    /// sub-path will therefore not have any stroke.
59    fn end_cap_butt(self) -> Self {
60        self.end_cap(LineCap::Butt)
61    }
62
63    /// At the end of each sub-path, the shape representing the stroke will be extended by a
64    /// rectangle with the same width as the stroke width and whose length is half of the stroke
65    /// width. If a sub-path has zero length, then the resulting effect is that the stroke for that
66    /// sub-path consists solely of a square with side length equal to the stroke width, centered
67    /// at the sub-path's point.
68    fn end_cap_square(self) -> Self {
69        self.end_cap(LineCap::Square)
70    }
71
72    /// At each end of each sub-path, the shape representing the stroke will be extended by a half
73    /// circle with a radius equal to the stroke width. If a sub-path has zero length, then the
74    /// resulting effect is that the stroke for that sub-path consists solely of a full circle
75    /// centered at the sub-path's point.
76    fn end_cap_round(self) -> Self {
77        self.end_cap(LineCap::Round)
78    }
79
80    /// The stroke for each sub-path does not extend beyond its two endpoints. A zero length
81    /// sub-path will therefore not have any stroke.
82    fn caps_butt(self) -> Self {
83        self.caps(LineCap::Butt)
84    }
85
86    /// At the end of each sub-path, the shape representing the stroke will be extended by a
87    /// rectangle with the same width as the stroke width and whose length is half of the stroke
88    /// width. If a sub-path has zero length, then the resulting effect is that the stroke for that
89    /// sub-path consists solely of a square with side length equal to the stroke width, centered
90    /// at the sub-path's point.
91    fn caps_square(self) -> Self {
92        self.caps(LineCap::Square)
93    }
94
95    /// At each end of each sub-path, the shape representing the stroke will be extended by a half
96    /// circle with a radius equal to the stroke width. If a sub-path has zero length, then the
97    /// resulting effect is that the stroke for that sub-path consists solely of a full circle
98    /// centered at the sub-path's point.
99    fn caps_round(self) -> Self {
100        self.caps(LineCap::Round)
101    }
102
103    /// The way in which lines are joined at the vertices, matching the SVG spec.
104    ///
105    /// Default value is `MiterClip`.
106    fn join(mut self, join: LineJoin) -> Self {
107        self.stroke_options_mut().line_join = join;
108        self
109    }
110
111    /// A sharp corner is to be used to join path segments.
112    fn join_miter(self) -> Self {
113        self.join(LineJoin::Miter)
114    }
115
116    /// Same as a `join_miter`, but if the miter limit is exceeded, the miter is clipped at a miter
117    /// length equal to the miter limit value multiplied by the stroke width.
118    fn join_miter_clip(self) -> Self {
119        self.join(LineJoin::MiterClip)
120    }
121
122    /// A round corner is to be used to join path segments.
123    fn join_round(self) -> Self {
124        self.join(LineJoin::Round)
125    }
126
127    /// A bevelled corner is to be used to join path segments. The bevel shape is a triangle that
128    /// fills the area between the two stroked segments.
129    fn join_bevel(self) -> Self {
130        self.join(LineJoin::Bevel)
131    }
132
133    /// The total stroke_weight (aka width) of the line.
134    fn stroke_weight(mut self, stroke_weight: f32) -> Self {
135        self.stroke_options_mut().line_width = stroke_weight;
136        self
137    }
138
139    /// Describes the limit before miter lines will clip, as described in the SVG spec.
140    ///
141    /// Must be greater than or equal to `1.0`.
142    fn miter_limit(mut self, limit: f32) -> Self {
143        self.stroke_options_mut().miter_limit = limit;
144        self
145    }
146
147    /// Maximum allowed distance to the path when building an approximation.
148    fn stroke_tolerance(mut self, tolerance: f32) -> Self {
149        self.stroke_options_mut().tolerance = tolerance;
150        self
151    }
152}
153
154impl SetStroke for Option<StrokeOptions> {
155    fn stroke_options_mut(&mut self) -> &mut StrokeOptions {
156        self.get_or_insert_with(Default::default)
157    }
158}