Skip to main content

PathBuilder

Struct PathBuilder 

Source
pub struct PathBuilder { /* private fields */ }
Expand description

Accumulates verbs and points into a Path.

Implementations§

Source§

impl PathBuilder

Source

pub fn new() -> Self

Source

pub fn with_fill_rule(self, rule: FillRule) -> Self

Source

pub fn move_to(&mut self, p: Vec2) -> &mut Self

Source

pub fn line_to(&mut self, p: Vec2) -> &mut Self

Add a line segment.

A line before any move_to implicitly starts the subpath at the origin, matching how path data from SVG and font outlines behaves when it omits the opening move.

Source

pub fn quad_to(&mut self, ctrl: Vec2, to: Vec2) -> &mut Self

Source

pub fn conic_to(&mut self, ctrl: Vec2, to: Vec2, weight: f32) -> &mut Self

Append a rational quadratic – a conic – through one control point.

The curve a circular arc actually is, and the one a font or an SVG hands over. weight is the control point’s pull: one is an ordinary quadratic, less than one is elliptical, more is hyperbolic, and sqrt(2)/2 with the control at the corner of a square is exactly a quarter circle.

§Why this becomes quadratics here rather than surviving as a verb

A conic of weight one is a quadratic, and splitting a conic in half moves its weight toward one – quadratically, so a handful of splits puts it within a thousandth. So this subdivides until the weight is near enough and emits ordinary quadratics, which every part of this crate and the tessellator already understand.

The alternative is a verb of its own, converted during flattening where the transform’s scale is known. That is what a renderer does when it wants an absolute error in device pixels. What is bought here instead is a relative error: the approximation is a fixed fraction of the curve’s own size, so it stays correct at every scale the path is later drawn at, and nothing downstream has to learn a fifth verb.

§Subdividing by the error rather than by the weight

The criterion below stops when the error is small enough, and that is worth spelling out because the obvious criterion – stop when the weight is near one – is what it replaced, and it was expensive by a factor of four.

A weight criterion counts halvings of the weight’s distance from one, and each halving doubles the output. So a curve gets subdivided by how hyperbolic it is rather than by how much the approximation misses. A rounded superellipse octant emits conics at weights around 0.7 and 8.3; under the weight criterion those became thirty-two and sixty-four quadratics, and the corpus scene cost 1340 vertices where a circle costs 40. It is 305 now, and the stroked one 274 against 922.

The error itself is four lines: a rational quadratic and its weight-one counterpart differ most at their midpoints, both midpoints have closed forms, and the distance between them measured against the chord is a relative bound – the same quantity the weight criterion was a proxy for, at the same tolerance of a thousandth.

It is a little less accurate where the proxy over-subdivided, which is most places. Measured against the old criterion: four pixels of the filled corpus scene and eight of the stroked one, out of sixteen thousand, and all of them at the shape’s tangent extremes where the outline lies along a pixel boundary and a sub-pixel shift moves every sample in the pixel together. Every comparison in the workspace passes unchanged, including the pin on upstream’s boundary points, which is what says the outline is still the shape upstream draws.

A weight that is zero or negative or not finite describes no curve, and gives the straight line between the ends.

Source

pub fn cubic_to(&mut self, c0: Vec2, c1: Vec2, to: Vec2) -> &mut Self

Source

pub fn arc( &mut self, center: Vec2, radii: Vec2, start: f32, sweep: f32, ) -> &mut Self

Append an elliptical arc, centered at center with the given radii.

Angles are in radians, measured from the positive X axis toward positive Y, and sweep may be negative to travel the other way. A sweep of a full turn or more is clamped to one: going round twice draws the same pixels as going round once, and the extra segments are cost without a picture.

If the path has a current point, a line joins it to the arc’s start, the way SVG and Skia both behave; otherwise the arc begins with a move. That is what makes a pie slice move_to(center) then arc(..) then close, and a progress ring just arc(..) on an empty builder.

§Accuracy

The arc is emitted as cubics of at most a quarter turn each, with control points at (4/3)·tan(θ/4) of the radius for a segment spanning θ. That expression is where the familiar 0.5523 comes from — it is this evaluated at a right angle — and using the constant for any other angle is the usual way to draw an arc that is visibly wrong near its ends. At a quarter turn the worst radial error is under three parts in ten thousand, so a circle a thousand pixels across is off by less than a third of a pixel.

Source

pub fn close(&mut self) -> &mut Self

Close the current subpath.

Closing an empty builder is a no-op rather than an error, so callers replaying arbitrary path data do not have to special-case it.

Source

pub fn current_point(&self) -> Option<Vec2>

Current pen position, if the path has started.

Source

pub fn as_rounded_rect(&mut self, rect: Rect, radius: f32) -> &mut Self

Record that what was laid down is this rounded rectangle.

An assertion by the caller, not a check: nothing here reads the verbs back to confirm it, because the only caller is the one that just wrote them. A builder that marks a shape it did not draw gets that shape drawn wherever a route prefers the shape to the outline – so this is called beside the drawing, never afterwards from somewhere that inferred it.

A radius at or below zero is a plain rectangle and is recorded as such. Anything not finite records nothing, since it describes no shape.

Source

pub fn build(self) -> Path

Trait Implementations§

Source§

impl Clone for PathBuilder

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PathBuilder

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for PathBuilder

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.