nannou/draw/
drawing.rs

1use crate::color::IntoLinSrgba;
2use crate::draw::mesh::vertex::{Color, TexCoords};
3use crate::draw::primitive::Primitive;
4use crate::draw::properties::{
5    ColorScalar, SetColor, SetDimensions, SetFill, SetOrientation, SetPosition, SetStroke,
6};
7use crate::draw::{self, Draw};
8use crate::geom::{Point2, Point3};
9use crate::glam::{Quat, Vec2, Vec3};
10use lyon::path::PathEvent;
11use lyon::tessellation::{FillOptions, LineCap, LineJoin, StrokeOptions};
12use std::marker::PhantomData;
13
14/// A **Drawing** in progress.
15///
16/// **Drawing** provides a way of chaining together method calls describing properties of the thing
17/// that we are drawing. **Drawing** ends when the instance is **Drop**ped, at which point the
18/// properties of the drawing are inserted into the **Draw** type.
19///
20/// When a **Drawing** begins, a node is immediately created for the drawing within the **Draw**'s
21/// inner **geom::Graph**. This ensures the correct instantiation order is maintained within the
22/// graph. As a result, each **Drawing** is associated with a single, unique node. Thus a
23/// **Drawing** can be thought of as a way of specifying properties for a node.
24#[derive(Debug)]
25pub struct Drawing<'a, T> {
26    // The `Draw` instance used to create this drawing.
27    draw: &'a Draw,
28    // The draw command index of the primitive being drawn.
29    index: usize,
30    // Whether or not the **Drawing** should attempt to finish the drawing on drop.
31    finish_on_drop: bool,
32    // The node type currently being drawn.
33    _ty: PhantomData<T>,
34}
35
36/// Some context that may be optionally provided to primitives in the drawing implementation.
37///
38/// This is particularly useful for paths and meshes.
39pub struct DrawingContext<'a> {
40    /// The intermediary mesh for buffering yet-to-be-drawn paths and meshes.
41    pub mesh: &'a mut draw::Mesh,
42    /// A re-usable buffer for collecting path events.
43    pub path_event_buffer: &'a mut Vec<PathEvent>,
44    /// A re-usable buffer for collecting colored polyline points.
45    pub path_points_colored_buffer: &'a mut Vec<(Point2, Color)>,
46    /// A re-usable buffer for collecting textured polyline points.
47    pub path_points_textured_buffer: &'a mut Vec<(Point2, TexCoords)>,
48    /// A re-usable buffer for collecting text.
49    pub text_buffer: &'a mut String,
50}
51
52/// Construct a new **Drawing** instance.
53pub fn new<'a, T>(draw: &'a Draw, index: usize) -> Drawing<'a, T> {
54    let _ty = PhantomData;
55    let finish_on_drop = true;
56    Drawing {
57        draw,
58        index,
59        finish_on_drop,
60        _ty,
61    }
62}
63
64impl<'a, T> Drop for Drawing<'a, T> {
65    fn drop(&mut self) {
66        if self.finish_on_drop {
67            self.finish_inner();
68        }
69    }
70}
71
72impl<'a> DrawingContext<'a> {
73    // Initialise the DrawingContext from the draw's IntermediaryState.
74    pub(crate) fn from_intermediary_state(state: &'a mut super::IntermediaryState) -> Self {
75        let super::IntermediaryState {
76            ref mut intermediary_mesh,
77            ref mut path_event_buffer,
78            ref mut path_points_colored_buffer,
79            ref mut path_points_textured_buffer,
80            ref mut text_buffer,
81        } = *state;
82        DrawingContext {
83            mesh: intermediary_mesh,
84            path_event_buffer: path_event_buffer,
85            path_points_colored_buffer: path_points_colored_buffer,
86            path_points_textured_buffer: path_points_textured_buffer,
87            text_buffer: text_buffer,
88        }
89    }
90}
91
92impl<'a, T> Drawing<'a, T> {
93    // Shared between the **finish** method and the **Drawing**'s **Drop** implementation.
94    //
95    // 1. Create vertices based on node-specific position, points, etc.
96    // 2. Insert edges into geom graph based on
97    fn finish_inner(&mut self) {
98        match self.draw.state.try_borrow_mut() {
99            Err(err) => eprintln!("drawing failed to borrow state and finish: {}", err),
100            Ok(mut state) => state.finish_drawing(self.index),
101        }
102    }
103
104    /// Complete the drawing and insert it into the parent **Draw** instance.
105    ///
106    /// This will be called when the **Drawing** is **Drop**ped if it has not yet been called.
107    pub fn finish(mut self) {
108        self.finish_inner()
109    }
110
111    // Map the given function onto the primitive stored within **Draw** at `index`.
112    //
113    // The functionn is only applied if the node has not yet been **Drawn**.
114    fn map_primitive<F, T2>(mut self, map: F) -> Drawing<'a, T2>
115    where
116        F: FnOnce(Primitive) -> Primitive,
117        T2: Into<Primitive>,
118    {
119        if let Ok(mut state) = self.draw.state.try_borrow_mut() {
120            if let Some(mut primitive) = state.drawing.remove(&self.index) {
121                primitive = map(primitive);
122                state.drawing.insert(self.index, primitive);
123            }
124        }
125        self.finish_on_drop = false;
126        let Drawing { draw, index, .. } = self;
127        Drawing {
128            draw,
129            index,
130            finish_on_drop: true,
131            _ty: PhantomData,
132        }
133    }
134
135    // The same as `map_primitive` but also passes a mutable reference to the vertex data to the
136    // map function. This is useful for types that may have an unknown number of arbitrary
137    // vertices.
138    fn map_primitive_with_context<F, T2>(mut self, map: F) -> Drawing<'a, T2>
139    where
140        F: FnOnce(Primitive, DrawingContext) -> Primitive,
141        T2: Into<Primitive>,
142    {
143        if let Ok(mut state) = self.draw.state.try_borrow_mut() {
144            if let Some(mut primitive) = state.drawing.remove(&self.index) {
145                {
146                    let mut intermediary_state = state.intermediary_state.borrow_mut();
147                    let ctxt = DrawingContext::from_intermediary_state(&mut *intermediary_state);
148                    primitive = map(primitive, ctxt);
149                }
150                state.drawing.insert(self.index, primitive);
151            }
152        }
153        self.finish_on_drop = false;
154        let Drawing { draw, index, .. } = self;
155        Drawing {
156            draw,
157            index,
158            finish_on_drop: true,
159            _ty: PhantomData,
160        }
161    }
162
163    /// Apply the given function to the type stored within **Draw**.
164    ///
165    /// The function is only applied if the node has not yet been **Drawn**.
166    ///
167    /// **Panics** if the primitive does not contain type **T**.
168    pub fn map_ty<F, T2>(self, map: F) -> Drawing<'a, T2>
169    where
170        F: FnOnce(T) -> T2,
171        T2: Into<Primitive>,
172        Primitive: Into<Option<T>>,
173    {
174        self.map_primitive(|prim| {
175            let maybe_ty: Option<T> = prim.into();
176            let ty = maybe_ty.expect("expected `T` but primitive contained different type");
177            let ty2 = map(ty);
178            ty2.into()
179        })
180    }
181
182    /// Apply the given function to the type stored within **Draw**.
183    ///
184    /// The function is only applied if the node has not yet been **Drawn**.
185    ///
186    /// **Panics** if the primitive does not contain type **T**.
187    pub(crate) fn map_ty_with_context<F, T2>(self, map: F) -> Drawing<'a, T2>
188    where
189        F: FnOnce(T, DrawingContext) -> T2,
190        T2: Into<Primitive>,
191        Primitive: Into<Option<T>>,
192    {
193        self.map_primitive_with_context(|prim, ctxt| {
194            let maybe_ty: Option<T> = prim.into();
195            let ty = maybe_ty.expect("expected `T` but primitive contained different type");
196            let ty2 = map(ty, ctxt);
197            ty2.into()
198        })
199    }
200}
201
202// SetColor implementations.
203
204impl<'a, T> Drawing<'a, T>
205where
206    T: SetColor<ColorScalar> + Into<Primitive>,
207    Primitive: Into<Option<T>>,
208{
209    /// Specify a color.
210    ///
211    /// This method supports any color type that can be converted into RGBA.
212    ///
213    /// Colors that have no alpha channel will be given an opaque alpha channel value `1.0`.
214    pub fn color<C>(self, color: C) -> Self
215    where
216        C: IntoLinSrgba<ColorScalar>,
217    {
218        self.map_ty(|ty| SetColor::color(ty, color))
219    }
220
221    /// Specify the color via red, green and blue channels.
222    pub fn rgb(self, r: ColorScalar, g: ColorScalar, b: ColorScalar) -> Self {
223        self.map_ty(|ty| SetColor::rgb(ty, r, g, b))
224    }
225
226    /// Specify the color via red, green and blue channels as bytes
227    pub fn rgb8(self, r: u8, g: u8, b: u8) -> Self {
228        self.map_ty(|ty| SetColor::rgb8(ty, r, g, b))
229    }
230
231    /// Specify the color via red, green, blue and alpha channels.
232    pub fn rgba(self, r: ColorScalar, g: ColorScalar, b: ColorScalar, a: ColorScalar) -> Self {
233        self.map_ty(|ty| SetColor::rgba(ty, r, g, b, a))
234    }
235
236    /// Specify the color via red, green, blue and alpha channels as bytes.
237    pub fn rgba8(self, r: u8, g: u8, b: u8, a: u8) -> Self {
238        self.map_ty(|ty| SetColor::rgba8(ty, r, g, b, a))
239    }
240
241    /// Specify the color via hue, saturation and luminance.
242    ///
243    /// If you're looking for HSVA or HSBA, use the `hsva` method instead.
244    ///
245    /// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
246    /// 360 degrees (or 2 PI radians).
247    ///
248    /// See the [wikipedia entry](https://en.wikipedia.org/wiki/HSL_and_HSV) for more details on
249    /// this color space.
250    pub fn hsl(self, h: ColorScalar, s: ColorScalar, l: ColorScalar) -> Self {
251        self.map_ty(|ty| SetColor::hsl(ty, h, s, l))
252    }
253
254    /// Specify the color via hue, saturation, luminance and an alpha channel.
255    ///
256    /// If you're looking for HSVA or HSBA, use the `hsva` method instead.
257    ///
258    /// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
259    /// 360 degrees (or 2 PI radians).
260    ///
261    /// See the [wikipedia entry](https://en.wikipedia.org/wiki/HSL_and_HSV) for more details on
262    /// this color space.
263    pub fn hsla(self, h: ColorScalar, s: ColorScalar, l: ColorScalar, a: ColorScalar) -> Self {
264        self.map_ty(|ty| SetColor::hsla(ty, h, s, l, a))
265    }
266
267    /// Specify the color via hue, saturation and *value* (brightness).
268    ///
269    /// This is sometimes also known as "hsb".
270    ///
271    /// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
272    /// 360 degrees (or 2 PI radians).
273    ///
274    /// See the [wikipedia entry](https://en.wikipedia.org/wiki/HSL_and_HSV) for more details on
275    /// this color space.
276    pub fn hsv(self, h: ColorScalar, s: ColorScalar, v: ColorScalar) -> Self {
277        self.map_ty(|ty| SetColor::hsv(ty, h, s, v))
278    }
279
280    /// Specify the color via hue, saturation, *value* (brightness) and an alpha channel.
281    ///
282    /// This is sometimes also known as "hsba".
283    ///
284    /// The given hue expects a value between `0.0` and `1.0` where `0.0` is 0 degress and `1.0` is
285    /// 360 degrees (or 2 PI radians).
286    ///
287    /// See the [wikipedia entry](https://en.wikipedia.org/wiki/HSL_and_HSV) for more details on
288    /// this color space.
289    pub fn hsva(self, h: ColorScalar, s: ColorScalar, v: ColorScalar, a: ColorScalar) -> Self {
290        self.map_ty(|ty| SetColor::hsva(ty, h, s, v, a))
291    }
292
293    /// Specify the color as gray scale
294    ///
295    /// The given g expects a value between `0.0` and `1.0` where `0.0` is black and `1.0` is white
296    pub fn gray(self, g: ColorScalar) -> Self {
297        self.map_ty(|ty| SetColor::gray(ty, g))
298    }
299}
300
301// SetDimensions implementations.
302
303impl<'a, T> Drawing<'a, T>
304where
305    T: SetDimensions + Into<Primitive>,
306    Primitive: Into<Option<T>>,
307{
308    /// Set the absolute width for the node.
309    pub fn width(self, w: f32) -> Self {
310        self.map_ty(|ty| SetDimensions::width(ty, w))
311    }
312
313    /// Set the absolute height for the node.
314    pub fn height(self, h: f32) -> Self {
315        self.map_ty(|ty| SetDimensions::height(ty, h))
316    }
317
318    /// Set the absolute depth for the node.
319    pub fn depth(self, d: f32) -> Self {
320        self.map_ty(|ty| SetDimensions::depth(ty, d))
321    }
322
323    /// Short-hand for the **width** method.
324    pub fn w(self, w: f32) -> Self {
325        self.map_ty(|ty| SetDimensions::w(ty, w))
326    }
327
328    /// Short-hand for the **height** method.
329    pub fn h(self, h: f32) -> Self {
330        self.map_ty(|ty| SetDimensions::h(ty, h))
331    }
332
333    /// Short-hand for the **depth** method.
334    pub fn d(self, d: f32) -> Self {
335        self.map_ty(|ty| SetDimensions::d(ty, d))
336    }
337
338    /// Set the **x** and **y** dimensions for the node.
339    pub fn wh(self, v: Vec2) -> Self {
340        self.map_ty(|ty| SetDimensions::wh(ty, v))
341    }
342
343    /// Set the **x**, **y** and **z** dimensions for the node.
344    pub fn whd(self, v: Vec3) -> Self {
345        self.map_ty(|ty| SetDimensions::whd(ty, v))
346    }
347
348    /// Set the width and height for the node.
349    pub fn w_h(self, x: f32, y: f32) -> Self {
350        self.map_ty(|ty| SetDimensions::w_h(ty, x, y))
351    }
352
353    /// Set the width and height for the node.
354    pub fn w_h_d(self, x: f32, y: f32, z: f32) -> Self {
355        self.map_ty(|ty| SetDimensions::w_h_d(ty, x, y, z))
356    }
357}
358
359// SetPosition methods.
360
361impl<'a, T> Drawing<'a, T>
362where
363    T: SetPosition + Into<Primitive>,
364    Primitive: Into<Option<T>>,
365{
366    /// Build with the given **Absolute** **Position** along the *x* axis.
367    pub fn x(self, x: f32) -> Self {
368        self.map_ty(|ty| SetPosition::x(ty, x))
369    }
370
371    /// Build with the given **Absolute** **Position** along the *y* axis.
372    pub fn y(self, y: f32) -> Self {
373        self.map_ty(|ty| SetPosition::y(ty, y))
374    }
375
376    /// Build with the given **Absolute** **Position** along the *z* axis.
377    pub fn z(self, z: f32) -> Self {
378        self.map_ty(|ty| SetPosition::z(ty, z))
379    }
380
381    /// Set the **Position** with some two-dimensional point.
382    pub fn xy(self, p: Point2) -> Self {
383        self.map_ty(|ty| SetPosition::xy(ty, p))
384    }
385
386    /// Set the **Position** with some three-dimensional point.
387    pub fn xyz(self, p: Point3) -> Self {
388        self.map_ty(|ty| SetPosition::xyz(ty, p))
389    }
390
391    /// Set the **Position** with *x* *y* coordinates.
392    pub fn x_y(self, x: f32, y: f32) -> Self {
393        self.map_ty(|ty| SetPosition::x_y(ty, x, y))
394    }
395
396    /// Set the **Position** with *x* *y* *z* coordinates.
397    pub fn x_y_z(self, x: f32, y: f32, z: f32) -> Self {
398        self.map_ty(|ty| SetPosition::x_y_z(ty, x, y, z))
399    }
400}
401
402// SetOrientation methods.
403
404impl<'a, T> Drawing<'a, T>
405where
406    T: SetOrientation + Into<Primitive>,
407    Primitive: Into<Option<T>>,
408{
409    /// Describe orientation via the vector that points to the given target.
410    pub fn look_at(self, target: Point3) -> Self {
411        self.map_ty(|ty| SetOrientation::look_at(ty, target))
412    }
413
414    /// Specify the orientation around the *x* axis as an absolute value in radians.
415    pub fn x_radians(self, x: f32) -> Self {
416        self.map_ty(|ty| SetOrientation::x_radians(ty, x))
417    }
418
419    /// Specify the orientation around the *y* axis as an absolute value in radians.
420    pub fn y_radians(self, y: f32) -> Self {
421        self.map_ty(|ty| SetOrientation::y_radians(ty, y))
422    }
423
424    /// Specify the orientation around the *z* axis as an absolute value in radians.
425    pub fn z_radians(self, z: f32) -> Self {
426        self.map_ty(|ty| SetOrientation::z_radians(ty, z))
427    }
428
429    /// Specify the orientation around the *x* axis as an absolute value in degrees.
430    pub fn x_degrees(self, x: f32) -> Self {
431        self.map_ty(|ty| SetOrientation::x_degrees(ty, x))
432    }
433
434    /// Specify the orientation around the *y* axis as an absolute value in degrees.
435    pub fn y_degrees(self, y: f32) -> Self {
436        self.map_ty(|ty| SetOrientation::y_degrees(ty, y))
437    }
438
439    /// Specify the orientation around the *z* axis as an absolute value in degrees.
440    pub fn z_degrees(self, z: f32) -> Self {
441        self.map_ty(|ty| SetOrientation::z_degrees(ty, z))
442    }
443
444    /// Specify the orientation around the *x* axis as a number of turns around the axis.
445    pub fn x_turns(self, x: f32) -> Self {
446        self.map_ty(|ty| SetOrientation::x_turns(ty, x))
447    }
448
449    /// Specify the orientation around the *y* axis as a number of turns around the axis.
450    pub fn y_turns(self, y: f32) -> Self {
451        self.map_ty(|ty| SetOrientation::y_turns(ty, y))
452    }
453
454    /// Specify the orientation around the *z* axis as a number of turns around the axis.
455    pub fn z_turns(self, z: f32) -> Self {
456        self.map_ty(|ty| SetOrientation::z_turns(ty, z))
457    }
458
459    /// Specify the orientation along each axis with the given **Vector** of radians.
460    ///
461    /// This has the same affect as calling `self.x_radians(v.x).y_radians(v.y).z_radians(v.z)`.
462    pub fn radians(self, v: Vec3) -> Self {
463        self.map_ty(|ty| SetOrientation::radians(ty, v))
464    }
465
466    /// Specify the orientation along each axis with the given **Vector** of degrees.
467    ///
468    /// This has the same affect as calling `self.x_degrees(v.x).y_degrees(v.y).z_degrees(v.z)`.
469    pub fn degrees(self, v: Vec3) -> Self {
470        self.map_ty(|ty| SetOrientation::degrees(ty, v))
471    }
472
473    /// Specify the orientation along each axis with the given **Vector** of "turns".
474    ///
475    /// This has the same affect as calling `self.x_turns(v.x).y_turns(v.y).z_turns(v.z)`.
476    pub fn turns(self, v: Vec3) -> Self {
477        self.map_ty(|ty| SetOrientation::turns(ty, v))
478    }
479
480    /// Specify the orientation with the given **Euler**.
481    ///
482    /// The euler must be specified in radians.
483    pub fn euler(self, e: Vec3) -> Self {
484        self.map_ty(|ty| SetOrientation::euler(ty, e))
485    }
486
487    /// Specify the orientation with the given **Quaternion**.
488    pub fn quaternion(self, q: Quat) -> Self {
489        self.map_ty(|ty| SetOrientation::quaternion(ty, q))
490    }
491
492    // Higher level methods.
493
494    /// Specify the "pitch" of the orientation in radians.
495    ///
496    /// This has the same effect as calling `x_radians`.
497    pub fn pitch(self, pitch: f32) -> Self {
498        self.map_ty(|ty| SetOrientation::pitch(ty, pitch))
499    }
500
501    /// Specify the "yaw" of the orientation in radians.
502    ///
503    /// This has the same effect as calling `y_radians`.
504    pub fn yaw(self, yaw: f32) -> Self {
505        self.map_ty(|ty| SetOrientation::yaw(ty, yaw))
506    }
507
508    /// Specify the "roll" of the orientation in radians.
509    ///
510    /// This has the same effect as calling `z_radians`.
511    pub fn roll(self, roll: f32) -> Self {
512        self.map_ty(|ty| SetOrientation::roll(ty, roll))
513    }
514
515    /// Assuming we're looking at a 2D plane, positive values cause a clockwise rotation where the
516    /// given value is specified in radians.
517    ///
518    /// This is equivalent to calling the `z_radians` or `roll` methods.
519    pub fn rotate(self, radians: f32) -> Self {
520        self.map_ty(|ty| SetOrientation::rotate(ty, radians))
521    }
522}
523
524// SetFill methods
525
526impl<'a, T> Drawing<'a, T>
527where
528    T: SetFill + Into<Primitive>,
529    Primitive: Into<Option<T>>,
530{
531    /// Specify the whole set of fill tessellation options.
532    pub fn fill_opts(self, opts: FillOptions) -> Self {
533        self.map_ty(|ty| ty.fill_opts(opts))
534    }
535
536    /// Maximum allowed distance to the path when building an approximation.
537    pub fn fill_tolerance(self, tolerance: f32) -> Self {
538        self.map_ty(|ty| ty.fill_tolerance(tolerance))
539    }
540
541    /// Specify the rule used to determine what is inside and what is outside of the shape.
542    ///
543    /// Currently, only the `EvenOdd` rule is implemented.
544    pub fn fill_rule(self, rule: lyon::tessellation::FillRule) -> Self {
545        self.map_ty(|ty| ty.fill_rule(rule))
546    }
547
548    /// Whether to perform a vertical or horizontal traversal of the geometry.
549    ///
550    /// Default value: `Vertical`.
551    pub fn fill_sweep_orientation(self, orientation: lyon::tessellation::Orientation) -> Self {
552        self.map_ty(|ty| ty.fill_sweep_orientation(orientation))
553    }
554
555    /// A fast path to avoid some expensive operations if the path is known to not have any
556    /// self-intersections.
557    ///
558    /// Do not set this to `false` if the path may have intersecting edges else the tessellator may
559    /// panic or produce incorrect results. In doubt, do not change the default value.
560    ///
561    /// Default value: `true`.
562    pub fn handle_intersections(self, b: bool) -> Self {
563        self.map_ty(|ty| ty.handle_intersections(b))
564    }
565}
566
567// SetStroke methods
568
569impl<'a, T> Drawing<'a, T>
570where
571    T: SetStroke + Into<Primitive>,
572    Primitive: Into<Option<T>>,
573{
574    /// The start line cap as specified by the SVG spec.
575    pub fn start_cap(self, cap: LineCap) -> Self {
576        self.map_ty(|ty| ty.start_cap(cap))
577    }
578
579    /// The end line cap as specified by the SVG spec.
580    pub fn end_cap(self, cap: LineCap) -> Self {
581        self.map_ty(|ty| ty.end_cap(cap))
582    }
583
584    /// The start and end line cap as specified by the SVG spec.
585    pub fn caps(self, cap: LineCap) -> Self {
586        self.map_ty(|ty| ty.caps(cap))
587    }
588
589    /// The stroke for each sub-path does not extend beyond its two endpoints. A zero length
590    /// sub-path will therefore not have any stroke.
591    pub fn start_cap_butt(self) -> Self {
592        self.map_ty(|ty| ty.start_cap_butt())
593    }
594
595    /// At the end of each sub-path, the shape representing the stroke will be extended by a
596    /// rectangle with the same width as the stroke width and whose length is half of the stroke
597    /// width. If a sub-path has zero length, then the resulting effect is that the stroke for that
598    /// sub-path consists solely of a square with side length equal to the stroke width, centered
599    /// at the sub-path's point.
600    pub fn start_cap_square(self) -> Self {
601        self.map_ty(|ty| ty.start_cap_square())
602    }
603
604    /// At each end of each sub-path, the shape representing the stroke will be extended by a half
605    /// circle with a radius equal to the stroke width. If a sub-path has zero length, then the
606    /// resulting effect is that the stroke for that sub-path consists solely of a full circle
607    /// centered at the sub-path's point.
608    pub fn start_cap_round(self) -> Self {
609        self.map_ty(|ty| ty.start_cap_round())
610    }
611
612    /// The stroke for each sub-path does not extend beyond its two endpoints. A zero length
613    /// sub-path will therefore not have any stroke.
614    pub fn end_cap_butt(self) -> Self {
615        self.map_ty(|ty| ty.end_cap_butt())
616    }
617
618    /// At the end of each sub-path, the shape representing the stroke will be extended by a
619    /// rectangle with the same width as the stroke width and whose length is half of the stroke
620    /// width. If a sub-path has zero length, then the resulting effect is that the stroke for that
621    /// sub-path consists solely of a square with side length equal to the stroke width, centered
622    /// at the sub-path's point.
623    pub fn end_cap_square(self) -> Self {
624        self.map_ty(|ty| ty.end_cap_square())
625    }
626
627    /// At each end of each sub-path, the shape representing the stroke will be extended by a half
628    /// circle with a radius equal to the stroke width. If a sub-path has zero length, then the
629    /// resulting effect is that the stroke for that sub-path consists solely of a full circle
630    /// centered at the sub-path's point.
631    pub fn end_cap_round(self) -> Self {
632        self.map_ty(|ty| ty.end_cap_round())
633    }
634
635    /// The stroke for each sub-path does not extend beyond its two endpoints. A zero length
636    /// sub-path will therefore not have any stroke.
637    pub fn caps_butt(self) -> Self {
638        self.map_ty(|ty| ty.caps_butt())
639    }
640
641    /// At the end of each sub-path, the shape representing the stroke will be extended by a
642    /// rectangle with the same width as the stroke width and whose length is half of the stroke
643    /// width. If a sub-path has zero length, then the resulting effect is that the stroke for that
644    /// sub-path consists solely of a square with side length equal to the stroke width, centered
645    /// at the sub-path's point.
646    pub fn caps_square(self) -> Self {
647        self.map_ty(|ty| ty.caps_square())
648    }
649
650    /// At each end of each sub-path, the shape representing the stroke will be extended by a half
651    /// circle with a radius equal to the stroke width. If a sub-path has zero length, then the
652    /// resulting effect is that the stroke for that sub-path consists solely of a full circle
653    /// centered at the sub-path's point.
654    pub fn caps_round(self) -> Self {
655        self.map_ty(|ty| ty.caps_round())
656    }
657
658    /// The way in which lines are joined at the vertices, matching the SVG spec.
659    ///
660    /// Default value is `MiterClip`.
661    pub fn join(self, join: LineJoin) -> Self {
662        self.map_ty(|ty| ty.join(join))
663    }
664
665    /// A sharp corner is to be used to join path segments.
666    pub fn join_miter(self) -> Self {
667        self.map_ty(|ty| ty.join_miter())
668    }
669
670    /// Same as a `join_miter`, but if the miter limit is exceeded, the miter is clipped at a miter
671    /// length equal to the miter limit value multiplied by the stroke width.
672    pub fn join_miter_clip(self) -> Self {
673        self.map_ty(|ty| ty.join_miter_clip())
674    }
675
676    /// A round corner is to be used to join path segments.
677    pub fn join_round(self) -> Self {
678        self.map_ty(|ty| ty.join_round())
679    }
680
681    /// A bevelled corner is to be used to join path segments. The bevel shape is a triangle that
682    /// fills the area between the two stroked segments.
683    pub fn join_bevel(self) -> Self {
684        self.map_ty(|ty| ty.join_bevel())
685    }
686
687    /// The total stroke_weight (aka width) of the line.
688    pub fn stroke_weight(self, stroke_weight: f32) -> Self {
689        self.map_ty(|ty| ty.stroke_weight(stroke_weight))
690    }
691
692    /// Describes the limit before miter lines will clip, as described in the SVG spec.
693    ///
694    /// Must be greater than or equal to `1.0`.
695    pub fn miter_limit(self, limit: f32) -> Self {
696        self.map_ty(|ty| ty.miter_limit(limit))
697    }
698
699    /// Maximum allowed distance to the path when building an approximation.
700    pub fn stroke_tolerance(self, tolerance: f32) -> Self {
701        self.map_ty(|ty| ty.stroke_tolerance(tolerance))
702    }
703
704    /// Specify the full set of stroke options for the path tessellation.
705    pub fn stroke_opts(self, opts: StrokeOptions) -> Self {
706        self.map_ty(|ty| ty.stroke_opts(opts))
707    }
708}