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}