lyon_tessellation/
lib.rs

1#![doc(html_logo_url = "https://nical.github.io/lyon-doc/lyon-logo.svg")]
2#![deny(bare_trait_objects)]
3#![deny(unconditional_recursion)]
4#![allow(clippy::float_cmp)]
5#![allow(clippy::too_many_arguments)]
6#![allow(mismatched_lifetime_syntaxes)]
7#![no_std]
8
9// TODO: Tessellation pipeline diagram needs to be updated.
10
11//! Tessellation of 2D fill and stroke operations.
12//!
13//! <svg viewBox="0 0 600.0 300.0" height="300" width="600">
14//!   <g transform="translate(0,-752.36216)">
15//!     <path style="fill:none;stroke:#ff9955;" d="m 346.4,790.7 186.8,11.2 -213.6,25.9 196.8,12.7 -185.1,41.4 192.4,24.4 -205.5,10.3 194.1,33.4 -97.3,25.5 -96.9,-58.9"/>
16//!     <path style="fill:#ffb380;stroke:none;" d="m 59.1,965.3 -15.1,-48.7 13.0,-34.4 -11.5,-54.2 26.7,-37.1 73.2,-19.2 114.4,30.4 -17.0,38.0 1.1,15.3 13.4,-8.1 14.8,6.8 -5.2,48.2 -16.8,4.8 -11.4,43.5 -40.4,29.9 -31.3,-3.0 0,28.2 19.0,8.3 -44.2,19.0 -10.6,-25.1 9.9,-3.8 0,-28.2 z"/>
17//!     <path style="fill:#de8787;stroke:none;" d="m 106.4,853.1 2.2,67.9 49.6,0.7 13.7,-22.9 -20.6,-3.8 -4.5,-44.2 -17.5,-13.7 z"/>
18//!     <path style="fill:#a02c2c;stroke:none;" d="m 108.74845,940.94089 61.08369,3.05419 -13.74383,15.27092 -33.59604,-3.05418 z"/>
19//!     <path style="fill:#784421;stroke:none;" d="m 176.93475,845.6345 20.51653,4.85918 -5.39908,30.7748 -12.68786,-1.88968 z"/>
20//!     <path style="fill:#784421;stroke:none;" d="m 78.4,882.0 9.4,-3.2 3.7,-30.7 -13.2,8.6 z"/>
21//!     <path style="fill:none;stroke:#ff9955;stroke-linecap:round;stroke-linejoin:round;" d="m 333.2,965.3 -15.1,-48.7 13.0,-34.4 -11.5,-54.2 26.7,-37.1 73.2,-19.2 114.4,30.4 -17.0,38.0 1.2,15.3 13.2,-8.0 14.8,6.8 -5.2,48.2 -16.8,4.8 -11.4,43.5 -40.4,29.9 -31.3,-3.0 0,28.2 19.0,8.3 -44.2,19.0 -10.6,-25.1 9.9,-3.8 0,-28.2 z"/>
22//!     <path style="fill:none;stroke:#de8787;stroke-linecap:round;stroke-linejoin:round;" d="m 380.5,853.1 2.2,67.9 49.6,0.7 13.7,-22.9 -20.6,-3.8 -4.5,-44.2 -17.5,-13.7 z"/>
23//!     <path style="fill:none;stroke:#a02c2c;stroke-linecap:round;stroke-linejoin:round;" d="m 382.8,940.9 61.0,3.0 -13.7,15.2 -33.5,-3.0 z"/>
24//!     <path style="fill:none;stroke:#803300;stroke-linecap:round;stroke-linejoin:round;" d="m 451.0,845.6 20.5,4.8 -5.3,30.7 -12.6,-1.8 z"/>
25//!     <path style="fill:none;stroke:#803300;stroke-linecap:round;stroke-linejoin:round;" d="m 352.5,882.0 9.4,-3.2 3.7,-30.7 -13.2,8.6 z"/>
26//!     <path style="fill:none;stroke:#803300;stroke-linecap:round;stroke-linejoin:round;" d="m 352.5,856.4 9.3,22.2"/>
27//!     <path style="fill:none;stroke:#de8787;stroke-linecap:round;stroke-linejoin:round;" d="m 380.8,853.3 40.2,-2.5 -38.3,70.1 42.6,-25.9 6.6,26.5"/>
28//!     <path style="fill:none;stroke:#803300;stroke-linecap:round;stroke-linejoin:round;" d="m 471.4,850.4 -17.6,28.6"/>
29//!     <path style="fill:none;stroke:#a02c2c;stroke-linecap:round;stroke-linejoin:round;" d="m 443.3,943.9 -46.7,12.2"/>
30//!     <path style="fill:none;stroke:#ff9955;stroke-linecap:round;stroke-linejoin:round;" d="m 540.7,902.0 -22.5,-46.9 5.7,51.7"/>
31//!     <path style="fill:none;stroke:#ff9955;stroke-linecap:round;stroke-linejoin:round;" d="m 512.2,950.2 -71.0,27.1 -26.1,-1.7 25.3,30.1 -25.1,-1.7 44.0,10.3 -53.8,-6.1"/>
32//!     <path style="fill:none;stroke:#ff9955;stroke-linecap:round;stroke-linejoin:round;" d="m 518.5,8.3 27.5,-1.2"/>
33//!   </g>
34//! </svg>
35//!
36//! This crate is reexported in [lyon](https://docs.rs/lyon/).
37//!
38//! ## Overview
39//!
40//! The most interesting types and traits of this crate are:
41//!
42//! * [FillTessellator](struct.FillTessellator.html) - Tessellator for complex path fill operations.
43//! * [StrokeTessellator](struct.StrokeTessellator.html) - Tessellator for complex path stroke operations.
44//! * [`GeometryBuilder`](geometry_builder/trait.GeometryBuilder.html) - (See the documentation of the
45//!   [geometry_builder module](geometry_builder/index.html)) which the above two are built on. This trait
46//!   provides an interface for types that help with building and assembling the vertices and triangles that
47//!   form the tessellation, usually in the form of arbitrary vertex and index buffers.
48//!
49//! ## The tessellation pipeline
50//!
51//! <svg xmlns="http://www.w3.org/2000/svg" width="280mm" height="42mm" viewBox="0 0 280 42">
52//!   <defs>
53//!     <marker id="e" orient="auto" overflow="visible">
54//!       <path fill="#59f" fill-rule="evenodd" stroke="#59f" stroke-width=".532" d="M-4 0l-2 2 7-2-7-2z"/>
55//!     </marker>
56//!     <marker id="d" orient="auto" overflow="visible">
57//!       <path fill-rule="evenodd" stroke="#000" stroke-width=".532" d="M-4 0l-2 2 7-2-7-2z"/>
58//!     </marker>
59//!     <marker id="c" orient="auto" overflow="visible">
60//!       <path fill="#59f" fill-rule="evenodd" stroke="#59f" stroke-width=".532" d="M-4 0l-2 2 7-2-7-2z"/>
61//!     </marker>
62//!     <marker id="b" orient="auto" overflow="visible">
63//!       <path fill-rule="evenodd" stroke="#000" stroke-width=".532" d="M-4 0l-2 2 7-2-7-2z"/>
64//!     </marker>
65//!     <marker id="a" orient="auto" overflow="visible">
66//!       <path fill-rule="evenodd" stroke="#000" stroke-width=".532" d="M-4 0l-2 2 7-2-7-2z"/>
67//!     </marker>
68//!   </defs>
69//!   <path fill="#fff" stroke="#000" stroke-opacity=".56" stroke-width=".26" stroke-miterlimit="4.27" d="M39.55 17.37h15.8l2.15-1.7 2.06 1.7h15.36V38.8H39.55zM194.65 31.3h21.58l2.1-1.83 2.04 1.82h35.07v7.07h-60.8zM77.7 19.5h54.6l3.3-2.58 3.17 2.57h52.56v19H77.7z" color="#000" overflow="visible" stroke-linecap="round" stroke-linejoin="round"/>
70//!   <g color="#000">
71//!     <path fill="#80b3ff" d="M194.6 20.37h50.65v8.73H194.6z" overflow="visible"/>
72//!     <path fill="#d5f6ff" d="M194.6 19.3h50.65v8.74H194.6z" overflow="visible"/>
73//!   </g>
74//!   <g color="#000">
75//!     <path fill="#2a7fff" d="M221.6 5.74h21.56v8.73H221.6z" overflow="visible"/>
76//!     <path fill="#d5f6ff" d="M221.6 4.68h21.56v8.73H221.6z" overflow="visible"/>
77//!   </g>
78//!   <g color="#000">
79//!     <path fill="#2a7fff" d="M154.38 5.74h47.4v8.73h-47.4z" overflow="visible"/>
80//!     <path fill="#d5f6ff" d="M154.38 4.68h47.4v8.73h-47.4z" overflow="visible"/>
81//!   </g>
82//!   <g color="#000">
83//!     <path fill="#2a7fff" d="M91.94 5.74h39.34v8.73H91.94z" overflow="visible"/>
84//!     <path fill="#d5f6ff" d="M91.94 4.68h39.34v8.73H91.94z" overflow="visible"/>
85//!   </g>
86//!   <g color="#000">
87//!     <path fill="#2a7fff" d="M3.04 5.74H75.2v8.73H3.03z" overflow="visible"/>
88//!     <path fill="#d5f6ff" d="M3.04 4.68H75.2v8.73H3.03z" overflow="visible"/>
89//!   </g>
90//!   <text x="93.73" y="266.09" stroke-width=".26" style="line-height:6.61458302px" font-size="5.29" font-family="Sans" letter-spacing="0" word-spacing="0" transform="translate(0 -255)">
91//!     <tspan x="93.73" y="266.09">FillTessellator</tspan>
92//!   </text>
93//!   <text x="155.37" y="265.58" stroke-width=".26" style="line-height:6.61458302px" font-size="5.29" font-family="Sans" letter-spacing="0" word-spacing="0" transform="translate(0 -255)">
94//!     <tspan x="155.37" y="265.58">GeometryBuilder</tspan>
95//!   </text>
96//!   <text x="223.1" y="266.02" stroke-width=".26" style="line-height:6.61458302px" font-size="5.29" font-family="Sans" letter-spacing="0" word-spacing="0" transform="translate(0 -255)">
97//!     <tspan x="223.1" y="266.02">output</tspan>
98//!   </text>
99//!   <text x="196.17" y="280.9" stroke-width=".26" style="line-height:6.61458302px" font-size="5.29" font-family="Sans" letter-spacing="0" word-spacing="0" transform="translate(0 -255)">
100//!     <tspan x="196.17" y="280.9">VertexConstructor</tspan>
101//!   </text>
102//!   <text x="5.13" y="266.09" stroke-width=".26" style="line-height:6.61458302px" font-size="5.29" font-family="Sans" letter-spacing="0" word-spacing="0" transform="translate(0 -255)">
103//!     <tspan x="5.13" y="266.09">Iterator&lt;PathEvent&gt;</tspan>
104//!   </text>
105//!   <text x="79.79" y="282.2" stroke-width=".26" style="line-height:6.61458302px" font-size="5.29" font-family="Sans" letter-spacing="0" word-spacing="0" transform="translate(0 -255)">
106//!     <tspan x="79.79" y="282.2" fill="navy" font-size="4.23">builder.add_vertex(FillVertex) -&gt; VertexId;</tspan><tspan x="79.79" y="289.09" fill="navy" font-size="4.23">builder.add_triangle(VertexId, <tspan stroke-width=".07" style="line-height:1.75010836px;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;text-orientation:mixed;shape-padding:0" white-space="normal">VertexId, VertexId);</tspan></tspan>
107//!   </text>
108//!   <path fill="none" stroke="#000" stroke-width=".3" stroke-miterlimit="4.4" d="M76.94 265l13.64-.1" marker-end="url(#a)" transform="translate(0 -255)"/>
109//!   <path fill="none" stroke="#000" stroke-width=".3" stroke-miterlimit="4.4" d="M132.86 265l19.55-.1" marker-end="url(#b)" transform="translate(0 -255)"/>
110//!   <path fill="#59f" fill-rule="evenodd" stroke="#59f" stroke-width=".3" stroke-miterlimit="4.4" d="M203.38 264.53l8.27 8.26" marker-end="url(#c)" transform="translate(0 -255)"/>
111//!   <path fill="none" stroke="#000" stroke-width=".3" stroke-miterlimit="4.4" d="M203.38 264.53l16 .06" marker-end="url(#d)" transform="translate(0 -255)"/>
112//!   <text x="196.69" y="291.41" stroke-width=".26" style="line-height:6.61458302px" font-size="5.29" font-family="Sans" letter-spacing="0" word-spacing="0" transform="translate(0 -255)">
113//!     <tspan x="196.69" y="291.41" fill="navy" font-size="4.23">FillVertex -&gt; CustomVertex</tspan>
114//!   </text>
115//!   <path fill="#59f" fill-rule="evenodd" stroke="#59f" stroke-width=".3" stroke-miterlimit="4.4" d="M212.97 272.98l6.75-6.5" marker-end="url(#e)" transform="translate(0 -255)"/>
116//!   <g fill="none" stroke="#000" stroke-width=".26">
117//!     <path d="M7.2 30.1l2.98 1.72h3.24l1.78-1.8 2.62-.75 2.08 1.83-1.6 2.87-5.64 1.54-3.5-1.62zM32.6 30.1l-3 1.72H26.4l-1.78-1.8-2.62-.75-2.08 1.83 1.6 2.87 5.64 1.54 3.5-1.62zM15 20.67l-.5 4.42 1.34 1 1.63-1.57-1.06-4.03zM24.53 20.67l.5 4.42-1.33 1-1.63-1.57 1.06-4.03z"/>
118//!   </g>
119//!   <path fill="#b7c8c4" fill-rule="evenodd" stroke="#000" stroke-width=".15" d="M251.68 19.5l2.98 1.74h3.23l1.78-1.8 2.62-.75 2.07 1.82-1.6 2.87-5.63 1.53-3.5-1.63z" stroke-linecap="round" stroke-linejoin="round"/>
120//!   <path fill="#b7c8c4" fill-rule="evenodd" stroke="#000" stroke-width=".15" d="M277.07 19.5l-2.98 1.74h-3.24l-1.8-1.8-2.6-.75-2.1 1.82L266 23.4l5.63 1.53 3.5-1.63zM259.48 10.08l-.5 4.42 1.33 1 1.65-1.55-1.07-4.03zM269 10.08l.52 4.42-1.34 1-1.64-1.55 1.07-4.03z" stroke-linecap="round" stroke-linejoin="round"/>
121//!   <path fill="none" stroke="#000" stroke-width=".15" d="M258.97 14.5l2.98-.55-2.47-3.87M266.54 13.95l2.98.55-1.9-4.58M254.66 21.24l-1 2.06 4.23-2.06-.76 3.7 2.54-5.5 3.1 3.95-.48-4.7M275.1 23.3l-1-2.06-2.5 3.7-.74-3.7-4.4-2.55-.48 4.7 4.88-2.16" stroke-linecap="round" stroke-linejoin="round"/>
122//!   <text x="43.5" y="277.68" stroke-width=".26" style="line-height:6.61458349px" font-size="5.29" font-family="Sans" letter-spacing="0" word-spacing="0" transform="translate(0 -255)">
123//!     <tspan x="43.5" y="277.68" fill="navy" font-size="3.88">MoveTo(Point)</tspan><tspan x="43.5" y="284.66" fill="navy" font-size="3.88">LineTo(Point)</tspan><tspan x="43.5" y="291.65" fill="navy" font-size="3.88">Close</tspan>
124//!   </text>
125//! </svg>
126//!
127//! The figure above shows a simplified summary of each step of the fill tessellation pipeline.
128//!
129//! ### The input: iterators
130//!
131//! The path tessellators are not tied to a particular data structure. Instead they consume
132//! iterators of flattened path events.
133//! A [Path struct](https://docs.rs/lyon_path/*/lyon_path/struct.Path.html) in the crate
134//! [lyon_path](https://docs.rs/lyon_path/*/lyon_path/) is provided for convenience
135//! (but is optional).
136//!
137//! ### The output: geometry builders
138//!
139//! The tessellators are parametrized over a type implementing the
140//! [GeometryBuilder trait](geometry_builder/trait.GeometryBuilder.html).
141//! This trait provides some simple methods to add vertices and triangles, without enforcing
142//! any particular representation for the resulting geometry. This is important because each
143//! application will usually want to work with its own vertex type tailored a certain rendering
144//! model.
145//!
146//! Applications can implement the ```GeometryBuilder<Point>``` trait in order to
147//! generate vertex buffers and index buffers with custom vertex types.
148//!
149//! The structs [VertexBuffers](geometry_builder/struct.VertexBuffers.html) and
150//! [geometry_builder::BuffersBuilder](geometry_builder/struct.BuffersBuilder.html) are provided
151//! for convenience. `VertexBuffers<T>` is contains a `Vec<T>` for the vertices and a `Vec<u16>`
152//! for the indices.
153//!
154//! `BuffersBuilder` is generic over a `VertexConstructor<InputVertex, OutputVertex>` trait which
155//! creates the application's output vertices from the tessellator input vertices (either `FillVertex`
156//! or `StrokeVertex`).
157//!
158//! ### Rendering the tessellated geometry
159//!
160//! The tessellators produce geometry in the form of vertex and index buffers which are expected
161//! to be rendered using the equivalent of OpenGL's `glDrawElements` with mode `GL_TRIANGLES` available
162//! under various names in the different graphics APIs.
163//! There is an [example](https://github.com/nical/lyon/tree/main/examples/wgpu) showing how
164//! it can be done with wgpu.
165//!
166//! ### Flattening and tolerance
167//!
168//! Most tessellators in this crate currently operate on flattened paths (paths or shapes represented
169//! by sequences of line segments). when paths contain bézier curves or arcs, the latter need to be
170//! approximated with sequences of line segments. This approximation depends on a `tolerance` parameter
171//! which represents the maximum distance between a curve and its flattened approximation.
172//!
173//! More explanation about flattening and tolerance in the [lyon_geom crate](https://docs.rs/lyon_geom/#flattening).
174//!
175//! ## Examples
176//!
177//! - [Tessellating path fills](fill/struct.FillTessellator.html#examples).
178//! - [Tessellating path strokes](stroke/struct.StrokeTessellator.html#examples).
179//! - [Generating custom vertices](geometry_builder/index.html#generating-custom-vertices).
180//! - [Generating completely custom output](geometry_builder/index.html#generating-a-completely-custom-output).
181//! - [Writing a tessellator](geometry_builder/index.html#writing-a-tessellator).
182//!
183
184#![allow(dead_code)]
185//#![allow(needless_return, new_without_default_derive)] // clippy
186
187extern crate alloc;
188
189#[cfg(any(test, feature = "std"))]
190extern crate std;
191
192pub use lyon_path as path;
193
194#[cfg(test)]
195use lyon_extra as extra;
196
197#[cfg(feature = "serialization")]
198#[macro_use]
199pub extern crate serde;
200
201mod basic_shapes;
202mod error;
203mod event_queue;
204mod fill;
205pub mod geometry_builder;
206mod math_utils;
207mod monotone;
208mod stroke;
209
210#[cfg(test)]
211#[rustfmt::skip]
212mod earcut_tests;
213#[cfg(test)]
214mod fill_tests;
215#[cfg(test)]
216mod fuzz_tests;
217
218pub use crate::path::math;
219
220pub use crate::path::geom;
221
222#[doc(inline)]
223pub use crate::event_queue::*;
224
225#[doc(inline)]
226pub use crate::fill::*;
227
228#[doc(inline)]
229pub use crate::stroke::*;
230
231#[doc(inline)]
232pub use crate::geometry_builder::{
233    BuffersBuilder, FillGeometryBuilder, FillVertexConstructor, GeometryBuilder,
234    GeometryBuilderError, StrokeGeometryBuilder, StrokeVertexConstructor, VertexBuffers,
235};
236
237#[doc(inline)]
238pub use crate::error::*;
239
240pub use crate::path::{AttributeIndex, Attributes, FillRule, LineCap, LineJoin, Side};
241
242use crate::path::EndpointId;
243
244use core::ops::{Add, Sub};
245use alloc::vec::Vec;
246
247/// Before or After. Used to describe position relative to a join.
248#[derive(Copy, Clone, Debug, PartialEq)]
249#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
250pub(crate) enum Order {
251    Before,
252    After,
253}
254
255impl Order {
256    pub fn opposite(self) -> Self {
257        match self {
258            Order::Before => Order::After,
259            Order::After => Order::Before,
260        }
261    }
262
263    pub fn is_before(self) -> bool {
264        self == Order::Before
265    }
266
267    pub fn is_after(self) -> bool {
268        self == Order::After
269    }
270}
271
272pub use fill::FillVertex;
273pub use stroke::StrokeVertex;
274
275/// Where a vertex produced by a tessellator comes from in the original path.
276///
277/// In most cases, vertices come directly from an endpoint. However, Curve
278/// approximations and self-intersections can introduce vertices that are on
279/// one or several edges, at a certain parameter `t` between the two endpoints
280/// of the edge.
281#[derive(Copy, Clone, Debug, PartialEq)]
282pub enum VertexSource {
283    Endpoint {
284        id: EndpointId,
285    },
286    Edge {
287        from: EndpointId,
288        to: EndpointId,
289        t: f32,
290    },
291}
292
293impl VertexSource {
294    pub fn is_endpoint(&self) -> bool {
295        matches!(self, VertexSource::Endpoint { .. })
296    }
297
298    pub fn is_edge(&self) -> bool {
299        matches!(self, VertexSource::Edge { .. })
300    }
301}
302
303/// Vertical or Horizontal.
304#[derive(Copy, Clone, Debug, PartialEq)]
305#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
306pub enum Orientation {
307    Horizontal,
308    Vertical,
309}
310
311/// Parameters for the tessellator.
312#[derive(Copy, Clone, Debug, PartialEq)]
313#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
314#[non_exhaustive]
315pub struct StrokeOptions {
316    /// What cap to use at the start of each sub-path.
317    ///
318    /// Default value: `LineCap::Butt`.
319    pub start_cap: LineCap,
320
321    /// What cap to use at the end of each sub-path.
322    ///
323    /// Default value: `LineCap::Butt`.
324    pub end_cap: LineCap,
325
326    /// See the SVG specification.
327    ///
328    /// Default value: `LineJoin::Miter`.
329    pub line_join: LineJoin,
330
331    /// Line width
332    ///
333    /// Default value: `StrokeOptions::DEFAULT_LINE_WIDTH`.
334    pub line_width: f32,
335
336    /// Index of a custom attribute defining a per-vertex
337    /// factor to modulate the line width.
338    ///
339    /// Default value: `None`.
340    pub variable_line_width: Option<AttributeIndex>,
341
342    /// See the SVG specification.
343    ///
344    /// Must be greater than or equal to 1.0.
345    /// Default value: `StrokeOptions::DEFAULT_MITER_LIMIT`.
346    pub miter_limit: f32,
347
348    /// Maximum allowed distance to the path when building an approximation.
349    ///
350    /// See [Flattening and tolerance](index.html#flattening-and-tolerance).
351    /// Default value: `StrokeOptions::DEFAULT_TOLERANCE`.
352    pub tolerance: f32,
353}
354
355impl StrokeOptions {
356    /// Minimum miter limit as defined by the SVG specification.
357    ///
358    /// See [StrokeMiterLimitProperty](https://svgwg.org/specs/strokes/#StrokeMiterlimitProperty)
359    pub const MINIMUM_MITER_LIMIT: f32 = 1.0;
360    /// Default miter limit as defined by the SVG specification.
361    ///
362    /// See [StrokeMiterLimitProperty](https://svgwg.org/specs/strokes/#StrokeMiterlimitProperty)
363    pub const DEFAULT_MITER_LIMIT: f32 = 4.0;
364    pub const DEFAULT_LINE_CAP: LineCap = LineCap::Butt;
365    pub const DEFAULT_LINE_JOIN: LineJoin = LineJoin::Miter;
366    pub const DEFAULT_LINE_WIDTH: f32 = 1.0;
367    pub const DEFAULT_TOLERANCE: f32 = 0.1;
368
369    pub const DEFAULT: Self = StrokeOptions {
370        start_cap: Self::DEFAULT_LINE_CAP,
371        end_cap: Self::DEFAULT_LINE_CAP,
372        line_join: Self::DEFAULT_LINE_JOIN,
373        line_width: Self::DEFAULT_LINE_WIDTH,
374        variable_line_width: None,
375        miter_limit: Self::DEFAULT_MITER_LIMIT,
376        tolerance: Self::DEFAULT_TOLERANCE,
377    };
378
379    #[inline]
380    pub fn tolerance(tolerance: f32) -> Self {
381        Self::DEFAULT.with_tolerance(tolerance)
382    }
383
384    #[inline]
385    pub const fn with_tolerance(mut self, tolerance: f32) -> Self {
386        self.tolerance = tolerance;
387        self
388    }
389
390    #[inline]
391    pub const fn with_line_cap(mut self, cap: LineCap) -> Self {
392        self.start_cap = cap;
393        self.end_cap = cap;
394        self
395    }
396
397    #[inline]
398    pub const fn with_start_cap(mut self, cap: LineCap) -> Self {
399        self.start_cap = cap;
400        self
401    }
402
403    #[inline]
404    pub const fn with_end_cap(mut self, cap: LineCap) -> Self {
405        self.end_cap = cap;
406        self
407    }
408
409    #[inline]
410    pub const fn with_line_join(mut self, join: LineJoin) -> Self {
411        self.line_join = join;
412        self
413    }
414
415    #[inline]
416    pub const fn with_line_width(mut self, width: f32) -> Self {
417        self.line_width = width;
418        self
419    }
420
421    #[inline]
422    pub fn with_miter_limit(mut self, limit: f32) -> Self {
423        assert!(limit >= Self::MINIMUM_MITER_LIMIT);
424        self.miter_limit = limit;
425        self
426    }
427
428    #[inline]
429    pub const fn with_variable_line_width(mut self, idx: AttributeIndex) -> Self {
430        self.variable_line_width = Some(idx);
431        self
432    }
433}
434
435impl Default for StrokeOptions {
436    fn default() -> Self {
437        Self::DEFAULT
438    }
439}
440
441/// Parameters for the fill tessellator.
442#[derive(Copy, Clone, Debug, PartialEq)]
443#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
444#[non_exhaustive]
445pub struct FillOptions {
446    /// Maximum allowed distance to the path when building an approximation.
447    ///
448    /// See [Flattening and tolerance](index.html#flattening-and-tolerance).
449    ///
450    /// Default value: `FillOptions::DEFAULT_TOLERANCE`.
451    pub tolerance: f32,
452
453    /// Set the fill rule.
454    ///
455    /// See the [SVG specification](https://www.w3.org/TR/SVG/painting.html#FillRuleProperty).
456    ///
457    /// Default value: `EvenOdd`.
458    pub fill_rule: FillRule,
459
460    /// Whether to perform a vertical or horizontal traversal of the geometry.
461    ///
462    /// Default value: `Vertical`.
463    pub sweep_orientation: Orientation,
464
465    /// A fast path to avoid some expensive operations if the path is known to
466    /// not have any self-intersections.
467    ///
468    /// Do not set this to `false` if the path may have intersecting edges else
469    /// the tessellator may panic or produce incorrect results. In doubt, do not
470    /// change the default value.
471    ///
472    /// Default value: `true`.
473    pub handle_intersections: bool,
474}
475
476impl FillOptions {
477    /// Default flattening tolerance.
478    pub const DEFAULT_TOLERANCE: f32 = 0.1;
479    /// Default Fill rule.
480    pub const DEFAULT_FILL_RULE: FillRule = FillRule::EvenOdd;
481    /// Default orientation.
482    pub const DEFAULT_SWEEP_ORIENTATION: Orientation = Orientation::Vertical;
483
484    pub const DEFAULT: Self = FillOptions {
485        tolerance: Self::DEFAULT_TOLERANCE,
486        fill_rule: Self::DEFAULT_FILL_RULE,
487        sweep_orientation: Self::DEFAULT_SWEEP_ORIENTATION,
488        handle_intersections: true,
489    };
490
491    #[inline]
492    pub fn even_odd() -> Self {
493        Self::DEFAULT
494    }
495
496    #[inline]
497    pub fn tolerance(tolerance: f32) -> Self {
498        Self::DEFAULT.with_tolerance(tolerance)
499    }
500
501    #[inline]
502    pub fn non_zero() -> Self {
503        let mut options = Self::DEFAULT;
504        options.fill_rule = FillRule::NonZero;
505        options
506    }
507
508    #[inline]
509    pub const fn with_tolerance(mut self, tolerance: f32) -> Self {
510        self.tolerance = tolerance;
511        self
512    }
513
514    #[inline]
515    pub const fn with_fill_rule(mut self, rule: FillRule) -> Self {
516        self.fill_rule = rule;
517        self
518    }
519
520    #[inline]
521    pub const fn with_sweep_orientation(mut self, orientation: Orientation) -> Self {
522        self.sweep_orientation = orientation;
523        self
524    }
525
526    #[inline]
527    pub const fn with_intersections(mut self, intersections: bool) -> Self {
528        self.handle_intersections = intersections;
529        self
530    }
531}
532
533impl Default for FillOptions {
534    fn default() -> Self {
535        Self::DEFAULT
536    }
537}
538
539type Index = u32;
540
541/// A virtual vertex offset in a geometry.
542///
543/// The `VertexId`s are only valid between `GeometryBuilder::begin_geometry` and
544/// `GeometryBuilder::end_geometry`. `GeometryBuilder` implementations typically be translate
545/// the ids internally so that first `VertexId` after `begin_geometry` is zero.
546#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
547#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
548pub struct VertexId(pub Index);
549
550impl VertexId {
551    pub const INVALID: VertexId = VertexId(u32::MAX);
552
553    pub fn offset(self) -> Index {
554        self.0
555    }
556
557    pub fn to_usize(self) -> usize {
558        self.0 as usize
559    }
560
561    pub fn from_usize(v: usize) -> Self {
562        VertexId(v as Index)
563    }
564}
565
566impl Add<u32> for VertexId {
567    type Output = Self;
568    fn add(self, rhs: u32) -> Self {
569        VertexId(self.0 + rhs)
570    }
571}
572
573impl Sub<u32> for VertexId {
574    type Output = Self;
575    fn sub(self, rhs: u32) -> Self {
576        VertexId(self.0 - rhs)
577    }
578}
579
580impl From<u16> for VertexId {
581    fn from(v: u16) -> Self {
582        VertexId(v as Index)
583    }
584}
585impl From<u32> for VertexId {
586    fn from(v: u32) -> Self {
587        VertexId(v)
588    }
589}
590impl From<i32> for VertexId {
591    fn from(v: i32) -> Self {
592        VertexId(v as Index)
593    }
594}
595
596impl From<VertexId> for u16 {
597    fn from(v: VertexId) -> Self {
598        v.0 as u16
599    }
600}
601impl From<VertexId> for u32 {
602    fn from(v: VertexId) -> Self {
603        v.0
604    }
605}
606impl From<VertexId> for i32 {
607    fn from(v: VertexId) -> Self {
608        v.0 as i32
609    }
610}
611impl From<VertexId> for usize {
612    fn from(v: VertexId) -> Self {
613        v.0 as usize
614    }
615}
616
617pub(crate) struct SimpleAttributeStore {
618    data: Vec<f32>,
619    num_attributes: usize,
620    next_id: EndpointId,
621}
622
623impl path::AttributeStore for SimpleAttributeStore {
624    fn get(&self, id: EndpointId) -> Attributes {
625        let start = id.0 as usize * self.num_attributes;
626        let end = start + self.num_attributes;
627        &self.data[start..end]
628    }
629
630    fn num_attributes(&self) -> usize {
631        self.num_attributes
632    }
633}
634
635impl Default for SimpleAttributeStore {
636    fn default() -> Self {
637        SimpleAttributeStore::new(0)
638    }
639}
640
641impl SimpleAttributeStore {
642    pub fn new(num_attributes: usize) -> Self {
643        SimpleAttributeStore {
644            data: Vec::new(),
645            num_attributes,
646            next_id: EndpointId(0),
647        }
648    }
649
650    pub fn add(&mut self, attributes: Attributes) -> EndpointId {
651        debug_assert_eq!(attributes.len(), self.num_attributes);
652        self.data.extend_from_slice(attributes);
653        let id = self.next_id;
654        self.next_id.0 += 1;
655        id
656    }
657
658    pub fn reserve(&mut self, n: usize) {
659        self.data.reserve(n * self.num_attributes);
660    }
661
662    pub fn reset(&mut self, num_attributes: usize) {
663        self.data.clear();
664        self.next_id = EndpointId(0);
665        self.num_attributes = num_attributes;
666    }
667}
668
669#[test]
670fn test_without_miter_limit() {
671    let expected_limit = 4.0;
672    let stroke_options = StrokeOptions::default();
673
674    assert_eq!(expected_limit, stroke_options.miter_limit);
675}
676
677#[test]
678fn test_with_miter_limit() {
679    let expected_limit = 3.0;
680    let stroke_options = StrokeOptions::default().with_miter_limit(expected_limit);
681
682    assert_eq!(expected_limit, stroke_options.miter_limit);
683}
684
685#[test]
686#[should_panic]
687fn test_with_invalid_miter_limit() {
688    let _ = StrokeOptions::default().with_miter_limit(0.0);
689}