lyon_path-0.15.1/Cargo.toml.orig010064400017500001750000000010621360142424100146770ustar0000000000000000[package] name = "lyon_path" version = "0.15.1" description = "Types and utilities to store, build and iterate over 2D paths." authors = [ "Nicolas Silva " ] repository = "https://github.com/nical/lyon" documentation = "https://docs.rs/lyon_path/" license = "MIT/Apache-2.0" workspace = ".." edition = "2018" [lib] name = "lyon_path" [features] serialization = ["serde", "lyon_geom/serialization"] [dependencies] lyon_geom = { version = "0.15.0", path = "../geom" } serde = { version = "1.0", optional = true, features = ["serde_derive"] }lyon_path-0.15.1/Cargo.toml0000644000000020341360142427200112110ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "lyon_path" version = "0.15.1" authors = ["Nicolas Silva "] description = "Types and utilities to store, build and iterate over 2D paths." documentation = "https://docs.rs/lyon_path/" license = "MIT/Apache-2.0" repository = "https://github.com/nical/lyon" [lib] name = "lyon_path" [dependencies.lyon_geom] version = "0.15.0" [dependencies.serde] version = "1.0" features = ["serde_derive"] optional = true [features] serialization = ["serde", "lyon_geom/serialization"] lyon_path-0.15.1/src/builder.rs010064400017500001750000000340121360010744200145740ustar0000000000000000//! Tools to build path objects from a sequence of imperative commands. //! //! ## Examples //! //! The following example shows the Builder struct from the //! [lyon_path](https://docs.rs/lyon_path/*/lyon_path) crate using the //! [FlatPathBuilder](traits.FlatPathBuilder.html) interface. //! //! ```ignore //! use lyon_path::Path; //! use lyon_core::math::{point}; //! use lyon_path::builder::*; //! //! // Create a builder object to build the path. //! let mut builder = Path::builder(); //! //! // Build a simple path using the FlatPathBuilder interface. //! builder.move_to(point(0.0, 0.0)); //! builder.line_to(point(1.0, 2.0)); //! builder.line_to(point(2.0, 0.0)); //! builder.line_to(point(1.0, 1.0)); //! builder.close(); //! //! // Finish building and create the actual path object. //! let path = builder.build(); //! ``` //! //! The next example uses the [PathBuilder](traits.PathBuilder.html) trait, which adds //! some simple curves to the [FlatPathBuilder](traits.FlatPathBuilder.html) trait. //! //! ```ignore //! let mut builder = Path::builder(); //! //! builder.move_to(point(0.0, 0.0)); //! builder.line_to(point(1.0, 0.0)); //! builder.quadratic_bezier_to(point(2.0, 0.0), point(2.0, 1.0)); //! builder.cubic_bezier_to(point(2.0, 2.0), point(0.0, 2.0), point(0.0, 0.0)); //! builder.close(); //! //! let path = builder.build(); //! ``` //! //! The [SvgBuilder](trait.SvgBuilder.html) Adds to [PathBuilder](traits.PathBuilder.html) //! the rest of the [SVG path](https://svgwg.org/specs/paths/) commands. //! //! These SVG commands can approximated with the simpler set of commands supported by //! [PathBuilder](traits.PathBuilder.html). Therefore it is possible to create an SvgBuilder //! adapter on top of a PathBuilder using the with_svg method: //! //! ```ignore //! let mut builder = Path::builder().with_svg(); //! //! builder.move_to(point(0.0, 0.0)); //! builder.horizontal_line_to(1.0); //! builder.relative_quadratic_bezier_to(point(1.0, 0.0), point(1.0, 1.0)); //! builder.smooth_relative_quadratic_bezier_to(point(-1.0, 1.0)); //! //! let path = builder.build(); //! ``` //! //! To build a path that approximates curves with a sequence of line segments, use the //! flattened method: //! //! ```ignore //! let tolerance = 0.05;// maximum distance between a curve and its approximation. //! let mut builder = Path::builder().flattened(tolerance); //! //! builder.move_to(point(0.0, 0.0)); //! builder.quadratic_bezier_to(point(1.0, 0.0), point(1.0, 1.0)); //! builder.close(); //! //! // The resulting path contains only Begin, Line and End events. //! let path = builder.build(); //! ``` //! use crate::math::*; use crate::events::PathEvent; use crate::geom::{CubicBezierSegment, QuadraticBezierSegment, SvgArc, Arc, ArcFlags}; use crate::path_state::PathState; use std::marker::Sized; pub trait Build { /// The type of object that is created by this builder. type PathType; /// Builds a path object and resets the builder so that it can be used again. fn build(self) -> Self::PathType; /// Builds a path object and resets the builder so that it can be used again. fn build_and_reset(&mut self) -> Self::PathType; } /// The most basic path building interface. Does not handle any kind of curve. pub trait FlatPathBuilder { /// Sets the current position in preparation for the next sub-path. /// If the current sub-path contains edges, this ends the sub-path without closing it. fn move_to(&mut self, to: Point); /// Adds a line segment to the current sub-path and set the current position. fn line_to(&mut self, to: Point); /// Closes the current sub path and sets the current position to the first position of /// this the current sub-path. /// /// Subsequent commands will affect the next sub-path. fn close(&mut self); fn current_position(&self) -> Point; /// Returns a builder that approximates all curves with sequences of line segments. fn flattened(self, tolerance: f32) -> FlatteningBuilder where Self: Sized { FlatteningBuilder::new(self, tolerance) } } /// The main path building interface. More elaborate interfaces are built on top /// of the provided primitives. pub trait PathBuilder: FlatPathBuilder { fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point); fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point); fn arc(&mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle); fn path_event(&mut self, event: PathEvent) { match event { PathEvent::Begin { at } => { self.move_to(at); } PathEvent::Line { to, .. } => { self.line_to(to); } PathEvent::Quadratic { ctrl, to, .. } => { self.quadratic_bezier_to(ctrl, to); } PathEvent::Cubic { ctrl1, ctrl2, to, .. } => { self.cubic_bezier_to(ctrl1, ctrl2, to); } PathEvent::End { close : true, .. } => { self.close(); } PathEvent::End { close : false, .. } => { } } } /// Returns a builder that support svg commands. fn with_svg(self) -> SvgPathBuilder where Self : Sized { SvgPathBuilder::new(self) } } /// A path building interface that tries to stay close to SVG's path specification. /// https://svgwg.org/specs/paths/ pub trait SvgBuilder: PathBuilder { fn relative_move_to(&mut self, to: Vector); fn relative_line_to(&mut self, to: Vector); fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector); fn relative_cubic_bezier_to(&mut self, ctrl1: Vector, ctrl2: Vector, to: Vector); fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point); fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector); fn smooth_quadratic_bezier_to(&mut self, to: Point); fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector); fn horizontal_line_to(&mut self, x: f32); fn relative_horizontal_line_to(&mut self, dx: f32); fn vertical_line_to(&mut self, y: f32); fn relative_vertical_line_to(&mut self, dy: f32); fn arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Point); fn relative_arc_to( &mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Vector, ); } /// Build a path from simple lists of points. pub trait PolygonBuilder { /// Add a closed polygon. fn polygon(&mut self, points: &[Point]); } #[doc(hidden)] pub fn build_polygon(builder: &mut Builder, points: &[Point]) { if points.len() < 2 { return; } builder.move_to(points[0]); for p in &points[1..] { builder.line_to(*p); } builder.close(); } /// Implements the Svg building interface on top of a PathBuilder. pub struct SvgPathBuilder { builder: Builder, state: PathState, } impl SvgPathBuilder { pub fn new(builder: Builder) -> SvgPathBuilder { SvgPathBuilder { builder, state: PathState::new(), } } } impl Build for SvgPathBuilder { type PathType = Builder::PathType; fn build(self) -> Builder::PathType { self.builder.build() } fn build_and_reset(&mut self) -> Builder::PathType { self.builder.build_and_reset() } } impl FlatPathBuilder for SvgPathBuilder { fn move_to(&mut self, to: Point) { self.state.move_to(to); self.builder.move_to(to); } fn line_to(&mut self, to: Point) { self.state.line_to(to); self.builder.line_to(to); } fn close(&mut self) { self.state.close(); self.builder.close(); } fn current_position(&self) -> Point { self.state.current_position() } } impl PathBuilder for SvgPathBuilder { fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) { self.state.quadratic_bezier_to(ctrl, to); self.builder.quadratic_bezier_to(ctrl, to); } fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) { self.state.cubic_bezier_to(ctrl1, ctrl2, to); self.builder.cubic_bezier_to(ctrl1, ctrl2, to); } fn arc( &mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle ) { self.state.arc(center, radii, sweep_angle, x_rotation); self.builder.arc(center, radii, sweep_angle, x_rotation); } } impl SvgBuilder for SvgPathBuilder { fn relative_move_to(&mut self, to: Vector) { self.state.relative_move_to(to); self.builder.move_to(self.state.current_position()); } fn relative_line_to(&mut self, to: Vector) { self.state.relative_line_to(to); self.builder.line_to(self.state.current_position()); } fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector) { let offset = self.state.current_position(); self.state.relative_quadratic_bezier_to(ctrl, to); self.builder.quadratic_bezier_to(offset + ctrl, offset + to); } fn relative_cubic_bezier_to(&mut self, ctrl1: Vector, ctrl2: Vector, to: Vector) { let offset = self.state.current_position(); self.state.relative_cubic_bezier_to(ctrl1, ctrl2, to); self.builder.cubic_bezier_to(offset + ctrl1, offset + ctrl2, offset + to); } fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point) { let ctrl1 = self.state.get_smooth_cubic_ctrl(); self.state.smooth_cubic_bezier_to(ctrl2, to); self.builder.cubic_bezier_to(ctrl1, ctrl2, to); } fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector) { let ctrl1 = self.state.get_smooth_cubic_ctrl(); let offset = self.state.current_position(); self.state.smooth_relative_cubic_bezier_to(ctrl2, to); self.builder.cubic_bezier_to(ctrl1, offset + ctrl2, offset + to); } fn smooth_quadratic_bezier_to(&mut self, to: Point) { let ctrl = self.state.get_smooth_quadratic_ctrl(); self.state.smooth_quadratic_bezier_to(to); self.builder.quadratic_bezier_to(ctrl, to); } fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector) { let ctrl = self.state.get_smooth_quadratic_ctrl(); let offset = self.state.current_position(); self.state.smooth_relative_quadratic_bezier_to(to); self.builder.quadratic_bezier_to(ctrl, offset + to); } fn horizontal_line_to(&mut self, x: f32) { self.state.horizontal_line_to(x); self.builder.line_to(self.state.current_position()); } fn relative_horizontal_line_to(&mut self, dx: f32) { self.state.relative_horizontal_line_to(dx); self.builder.line_to(self.state.current_position()); } fn vertical_line_to(&mut self, y: f32) { self.state.vertical_line_to(y); self.builder.line_to(self.state.current_position()); } fn relative_vertical_line_to(&mut self, dy: f32) { self.state.relative_vertical_line_to(dy); self.builder.line_to(self.state.current_position()); } fn arc_to(&mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Point) { SvgArc { from: self.state.current_position(), to, radii, x_rotation, flags: ArcFlags { large_arc: flags.large_arc, sweep: flags.sweep, }, }.for_each_quadratic_bezier(&mut|curve| { self.quadratic_bezier_to(curve.ctrl, curve.to); }); self.state.arc_to(radii, x_rotation, flags, to); } fn relative_arc_to( &mut self, radii: Vector, x_rotation: Angle, flags: ArcFlags, to: Vector, ) { let offset = self.state.current_position(); self.arc_to(radii, x_rotation, flags, offset + to); } } /// Generates flattened paths pub struct FlatteningBuilder { builder: Builder, tolerance: f32, } impl Build for FlatteningBuilder { type PathType = Builder::PathType; fn build(self) -> Builder::PathType { self.builder.build() } fn build_and_reset(&mut self) -> Builder::PathType { self.builder.build_and_reset() } } impl FlatPathBuilder for FlatteningBuilder { fn move_to(&mut self, to: Point) { self.builder.move_to(to); } fn line_to(&mut self, to: Point) { self.builder.line_to(to); } fn close(&mut self) { self.builder.close() } fn current_position(&self) -> Point { self.builder.current_position() } } impl PathBuilder for FlatteningBuilder { fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) { QuadraticBezierSegment { from: self.current_position(), ctrl, to, }.for_each_flattened(self.tolerance, &mut |point| { self.line_to(point); }); } fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) { CubicBezierSegment { from: self.current_position(), ctrl1, ctrl2, to, }.for_each_flattened(self.tolerance, &mut |point| { self.line_to(point); }); } fn arc( &mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle ) { let start_angle = (self.current_position() - center).angle_from_x_axis() - x_rotation; Arc { center, radii, start_angle, sweep_angle, x_rotation, }.for_each_quadratic_bezier(&mut|curve| { self.quadratic_bezier_to(curve.ctrl, curve.to); }); } } impl FlatteningBuilder { pub fn new(builder: Builder, tolerance: f32) -> FlatteningBuilder { FlatteningBuilder { builder, tolerance, } } pub fn set_tolerance(&mut self, tolerance: f32) { self.tolerance = tolerance } } lyon_path-0.15.1/src/commands.rs010064400017500001750000000773101360023566500147700ustar0000000000000000//! A generic representation for paths that allow more control over how //! endpoints and control points are stored. //! //! # Motivation //! //! The default `Path` data structure in this crate is works well for the //! most common use cases. Sometimes, however, it is useful to be able to //! specify exactly how endpoints and control points are stored instead of //! relying on implicitly following the order of the events. //! //! This module contains bricks to help with building custom path representations. //! The central piece is the [`PathCommands`](struct.PathCommands.html) buffer and //! its [`PathCommandsBuilder`](struct.PathCommandsBuilder.html), providing a compact //! representation for path events with IDs instead of positions. //! //! # Examples //! //! The following example shows how `PathCommands` can be used together with an //! external buffers for positions to implement features similar to the default //! Path type with a different data structure. //! //! ``` //! use lyon_path::{EndpointId, Event, IdEvent, commands::PathCommands}; //! let points = &[ //! [0.0, 0.0], //! [1.0, 1.0], //! [0.0, 2.0], //! ]; //! //! let mut cmds = PathCommands::builder(); //! cmds.move_to(EndpointId(0)); //! cmds.line_to(EndpointId(1)); //! cmds.line_to(EndpointId(2)); //! cmds.close(); //! //! let cmds = cmds.build(); //! //! for event in &cmds { //! match event { //! IdEvent::Begin { at } => { println!("move to {:?}", points[at.to_usize()]); } //! IdEvent::Line { to, .. } => { println!("line to {:?}", points[to.to_usize()]); } //! IdEvent::End { close: true, .. } => { println!("close"); } //! _ => { panic!("unexpected event!") } //! } //! } //! //! // Iterate over the points directly using CommandsPathSlice //! for event in cmds.path_slice(points, points).events() { //! match event { //! Event::Begin { at } => { println!("move to {:?}", at); } //! Event::Line { to, .. } => { println!("line to {:?}", to); } //! Event::End { close: true, .. } => { println!("close"); } //! _ => { panic!("unexpected event!") } //! } //! } //! //! ``` use crate::{EndpointId, ControlPointId, EventId, Position, PositionStore}; use crate::events::{Event, PathEvent, IdEvent}; use crate::math::Point; use std::fmt; // Note: Tried making the path generic over the integer type used to store // the commands to allow u16 and u32, but the performance difference is very // small and not worth the added complexity. mod verb { pub const LINE: u32 = 0; pub const QUADRATIC: u32 = 1; pub const CUBIC: u32 = 2; pub const BEGIN: u32 = 3; pub const CLOSE: u32 = 4; pub const END: u32 = 5; } /// Sadly this is very close to std::slice::Iter but reimplementing /// it manually to iterate over u32 makes a difference. /// It would seem that having next return u32 with a special value /// for the end of the iteration instead of Option should /// improve performance (simpler code and a bunch of unwraps removed), /// however a naive initial attempt led to worse performance. #[derive(Copy, Clone)] struct CmdIter<'l> { ptr: *const u32, end: *const u32, _marker: std::marker::PhantomData<&'l u32>, } impl<'l> CmdIter<'l> { fn new(slice: &[u32]) -> Self { let ptr = slice.as_ptr(); let end = unsafe { ptr.offset(slice.len() as isize) }; CmdIter { ptr, end, _marker: std::marker::PhantomData, } } #[inline] fn next(&mut self) -> Option { unsafe { if self.ptr == self.end { return None; } let val = *self.ptr; self.ptr = self.ptr.offset(1); Some(val) } } } /// The commands of a path encoded in a single array using IDs to refer /// to endpoints and control points. /// /// `PathCommands` is a good fit when the a custom endpoint and control point /// types are needed or when their the user needs full control over their storage. /// /// # Representation /// /// Path commands contains a single array of 32 bits integer values encoding path /// commands, endpoint IDs or control point IDs. /// /// ```ascii /// __________________________________________________________________________ /// | | | | | | | | /// | Begin |EndpointID| Line |EndpointID|Quadratic|ControlPointId|EndpointID| ... /// |_______|__________|______|__________|_________|______________|__________|_ /// /// ``` #[derive(Clone)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] pub struct PathCommands { cmds: Box<[u32]>, } impl PathCommands { /// Creates a [PathCommandsBuilder](struct.PathCommandsBuilder.html) to create path commands. pub fn builder() -> PathCommandsBuilder { PathCommandsBuilder::new() } /// Returns an iterator over the path commands. pub fn id_events(&self) -> IdEvents { IdEvents::new(&self.cmds) } /// Returns a view on the path commands. pub fn as_slice(&self) -> CommandsSlice { CommandsSlice { cmds: &self.cmds, } } /// Returns a view on a path made of these commands with endpoint and /// control point slices. pub fn path_slice<'l, Endpoint, ControlPoint>( &'l self, endpoints: &'l [Endpoint], control_points: &'l [ControlPoint], ) -> CommandsPathSlice { CommandsPathSlice { endpoints, control_points, cmds: self.as_slice(), } } /// Returns an iterator over the path, with endpoints and control points. pub fn events<'l, Endpoint, ControlPoint>( &'l self, endpoints: &'l [Endpoint], control_points: &'l [ControlPoint], ) -> Events { Events { cmds: CmdIter::new(&self.cmds), first_endpoint: 0, prev_endpoint: 0, endpoints, control_points, } } /// Returns the event for a given event ID. pub fn event(&self, id: EventId) -> IdEvent { self.as_slice().event(id) } /// Returns the next event id within the path. pub fn next_event_id_in_path(&self, id: EventId) -> Option { self.as_slice().next_event_id_in_path(id) } /// Returns the next event id within the sub-path. /// /// Loops back to the first event after the end of the sub-path. pub fn next_event_id_in_sub_path(&self, id: EventId) -> EventId { self.as_slice().next_event_id_in_sub_path(id) } } impl fmt::Debug for PathCommands { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.as_slice().fmt(f) } } impl<'l> IntoIterator for &'l PathCommands { type Item = IdEvent; type IntoIter = IdEvents<'l>; fn into_iter(self) -> IdEvents<'l> { self.id_events() } } impl<'l> Into> for &'l PathCommands { fn into(self) -> CommandsSlice<'l> { self.as_slice() } } /// A view over [`PathCommands`](struct.PathCommands.html). #[derive(Copy, Clone)] pub struct CommandsSlice<'l> { cmds: &'l [u32], } impl<'l> CommandsSlice<'l> { /// Returns an iterator over the path commands. pub fn id_events(&self) -> IdEvents { IdEvents::new(self.cmds) } /// Returns the event for a given event ID. pub fn event(&self, id: EventId) -> IdEvent { let idx = id.to_usize(); match self.cmds[idx] { verb::LINE => IdEvent::Line { from: EndpointId(self.cmds[idx - 1]), to: EndpointId(self.cmds[idx + 1]), }, verb::QUADRATIC => IdEvent::Quadratic { from: EndpointId(self.cmds[idx - 1]), ctrl: ControlPointId(self.cmds[idx + 1]), to: EndpointId(self.cmds[idx + 2]), }, verb::CUBIC => IdEvent::Cubic { from: EndpointId(self.cmds[idx - 1]), ctrl1: ControlPointId(self.cmds[idx + 1]), ctrl2: ControlPointId(self.cmds[idx + 2]), to: EndpointId(self.cmds[idx + 3]), }, verb::BEGIN => IdEvent::Begin { at: EndpointId(self.cmds[idx + 1]) }, verb::END => { let first_event = self.cmds[idx + 1] as usize; IdEvent::End { last: EndpointId(self.cmds[idx - 1]), first: EndpointId(self.cmds[first_event + 1]), close: false, } } _ => { // CLOSE let first_event = self.cmds[idx + 1] as usize; IdEvent::End { last: EndpointId(self.cmds[idx - 1]), first: EndpointId(self.cmds[first_event + 1]), close: true, } } } } /// Returns the next event id within the path. pub fn next_event_id_in_sub_path(&self, id: EventId) -> EventId { let idx = id.to_usize(); match self.cmds[idx] { verb::LINE | verb::BEGIN => EventId(id.0 + 2), verb::QUADRATIC => EventId(id.0 + 3), verb::CUBIC => EventId(id.0 + 4), //verb::END | verb::CLOSE _ => EventId(self.cmds[idx + 1]), } } /// Returns the next event id within the path. pub fn next_event_id_in_path(&self, id: EventId) -> Option { let idx = id.to_usize(); let next = match self.cmds[idx] { verb::QUADRATIC => EventId(id.0 + 3), verb::CUBIC => EventId(id.0 + 4), // verb::LINE | verb::BEGIN | verb::END | verb::CLOSE _ => EventId(id.0 + 2), }; if next.0 < self.cmds.len() as u32 { return Some(next); } None } } impl<'l> fmt::Debug for CommandsSlice<'l> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{{ ")?; for evt in self.id_events() { match evt { IdEvent::Line { to, .. } => { write!(f, "L {:?}", to) } IdEvent::Quadratic { ctrl, to, .. } => { write!(f, "Q {:?} {:?} ", ctrl, to) } IdEvent::Cubic { ctrl1, ctrl2, to, .. } => { write!(f, "C {:?} {:?} {:?} ", ctrl1, ctrl2, to) } IdEvent::Begin { at, .. } => { write!(f, "M {:?} ", at) } IdEvent::End { close: true, .. } => { write!(f, "Z ") } IdEvent::End { close: false, .. } => { Ok(()) } }?; } write!(f, "}}") } } /// A view on a [`PathCommands`](struct.PathCommands.html) buffer and /// two slices for endpoints and control points, providing similar /// functionalities as `PathSlice`. #[derive(Copy, Clone)] pub struct CommandsPathSlice<'l, Endpoint, ControlPoint> { endpoints: &'l [Endpoint], control_points: &'l [ControlPoint], cmds: CommandsSlice<'l>, } impl<'l, Endpoint, ControlPoint> CommandsPathSlice<'l, Endpoint, ControlPoint> { /// Returns an iterator over the events of the path using IDs. pub fn id_events(&self) -> IdEvents { self.cmds.id_events() } /// Returns an iterator over the events of the path using endpoint /// and control point references. pub fn events(&self) -> Events { Events { cmds: CmdIter::new(&self.cmds.cmds), first_endpoint: 0, prev_endpoint: 0, endpoints: &self.endpoints[..], control_points: &self.control_points[..], } } } impl<'l, Endpoint, ControlPoint> std::ops::Index for CommandsPathSlice<'l, Endpoint, ControlPoint> { type Output = Endpoint; fn index(&self, id: EndpointId) -> &Endpoint { &self.endpoints[id.to_usize()] } } impl<'l, Endpoint, ControlPoint> std::ops::Index for CommandsPathSlice<'l, Endpoint, ControlPoint> { type Output = ControlPoint; fn index(&self, id: ControlPointId) -> &ControlPoint { &self.control_points[id.to_usize()] } } impl<'l, Endpoint, ControlPoint> fmt::Debug for CommandsPathSlice<'l, Endpoint, ControlPoint> where Endpoint: fmt::Debug, ControlPoint: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{{ ")?; for evt in self.events() { match evt { Event::Line { to, .. } => { write!(f, "L {:?}", to) } Event::Quadratic { ctrl, to, .. } => { write!(f, "Q {:?} {:?} ", ctrl, to) } Event::Cubic { ctrl1, ctrl2, to, .. } => { write!(f, "C {:?} {:?} {:?} ", ctrl1, ctrl2, to) } Event::Begin { at, .. } => { write!(f, "M {:?} ", at) } Event::End { close: true, .. } => { write!(f, "Z ") } Event::End { close: false, .. } => { Ok(()) } }?; } write!(f, "}}") } } /// Builds path commands. /// /// See [`PathCommands`](struct.PathCommands.html). #[derive(Clone)] pub struct PathCommandsBuilder { cmds: Vec, last_cmd: u32, start: u32, first_event_index: u32, } impl PathCommandsBuilder { /// Creates a builder without allocating memory. pub fn new() -> Self { Self { start: 0, cmds: Vec::new(), last_cmd: verb::END, first_event_index: 0, } } /// Creates a pre-allocated builder. pub fn with_capacity(cap: usize) -> Self { Self { start: 0, cmds: Vec::with_capacity(cap), last_cmd: verb::END, first_event_index: 0, } } pub fn move_to(&mut self, to: EndpointId) -> EventId { self.end_if_needed(); self.first_event_index = self.cmds.len() as u32; let id = EventId(self.cmds.len() as u32); self.cmds.push(verb::BEGIN); self.cmds.push(to.0); self.last_cmd = verb::BEGIN; id } pub fn line_to(&mut self, to: EndpointId) -> EventId { self.begin_if_needed(); let id = EventId(self.cmds.len() as u32); self.cmds.push(verb::LINE); self.cmds.push(to.0); self.last_cmd = verb::LINE; id } pub fn quadratic_bezier_to(&mut self, ctrl: ControlPointId, to: EndpointId) -> EventId { self.begin_if_needed(); let id = EventId(self.cmds.len() as u32); self.cmds.push(verb::QUADRATIC); self.cmds.push(ctrl.0); self.cmds.push(to.0); self.last_cmd = verb::QUADRATIC; id } pub fn cubic_bezier_to(&mut self, ctrl1: ControlPointId, ctrl2: ControlPointId, to: EndpointId) -> EventId { self.begin_if_needed(); let id = EventId(self.cmds.len() as u32); self.cmds.push(verb::CUBIC); self.cmds.push(ctrl1.0); self.cmds.push(ctrl2.0); self.cmds.push(to.0); self.last_cmd = verb::CUBIC; id } pub fn close(&mut self) -> EventId { let id = EventId(self.cmds.len() as u32); match self.last_cmd { verb::CLOSE | verb::END => { return id; } _ => {} } self.cmds.push(verb::CLOSE); self.cmds.push(self.first_event_index); self.last_cmd = verb::CLOSE; id } fn begin_if_needed(&mut self) { match self.last_cmd { verb::CLOSE | verb::END => { let first = self.cmds.last().cloned().unwrap_or(0); self.move_to(EndpointId(first)); } _ => {} } } fn end_if_needed(&mut self) { match self.last_cmd { verb::LINE | verb::QUADRATIC | verb::CUBIC => { self.cmds.push(verb::END); self.cmds.push(self.first_event_index); } _ => {} } } /// Consumes the builder and returns path commands. pub fn build(mut self) -> PathCommands { self.end_if_needed(); PathCommands { cmds: self.cmds.into_boxed_slice(), } } } /// An iterator of `Event<&Endpoint, &ControlPoint>`. #[derive(Clone)] pub struct Events<'l, Endpoint, ControlPoint> { cmds: CmdIter<'l>, prev_endpoint: usize, first_endpoint: usize, endpoints: &'l[Endpoint], control_points: &'l[ControlPoint], } impl<'l, Endpoint, ControlPoint> Iterator for Events<'l, Endpoint, ControlPoint> { type Item = Event<&'l Endpoint, &'l ControlPoint>; #[inline] fn next(&mut self) -> Option> { match self.cmds.next() { Some(verb::BEGIN) => { let to = self.cmds.next().unwrap() as usize; self.prev_endpoint = to; self.first_endpoint = to; Some(Event::Begin { at: &self.endpoints[to] }) } Some(verb::LINE) => { let to = self.cmds.next().unwrap() as usize; let from = self.prev_endpoint; self.prev_endpoint = to; Some(Event::Line { from: &self.endpoints[from], to: &self.endpoints[to], }) } Some(verb::QUADRATIC) => { let ctrl = self.cmds.next().unwrap() as usize; let to = self.cmds.next().unwrap() as usize; let from = self.prev_endpoint; self.prev_endpoint = to; Some(Event::Quadratic { from: &self.endpoints[from], ctrl: &self.control_points[ctrl], to: &self.endpoints[to], }) } Some(verb::CUBIC) => { let ctrl1 = self.cmds.next().unwrap() as usize; let ctrl2 = self.cmds.next().unwrap() as usize; let to = self.cmds.next().unwrap() as usize; let from = self.prev_endpoint; self.prev_endpoint = to; Some(Event::Cubic { from: &self.endpoints[from], ctrl1: &self.control_points[ctrl1], ctrl2: &self.control_points[ctrl2], to: &self.endpoints[to], }) } Some(verb::END) => { let _first_index = self.cmds.next(); let last = self.prev_endpoint; let first = self.first_endpoint; self.prev_endpoint = first; Some(Event::End { last: &self.endpoints[last], first: &self.endpoints[first], close: false, }) } Some(_) => { // CLOSE let _first_index = self.cmds.next(); let last = self.prev_endpoint; let first = self.first_endpoint; self.prev_endpoint = first; Some(Event::End { last: &self.endpoints[last], first: &self.endpoints[first], close: true, }) } None => None } } } impl<'l, Ep, Cp> Events<'l, Ep, Cp> where Ep: Position, Cp: Position, { pub fn points(self) -> PointEvents<'l, Ep, Cp> { PointEvents { cmds: self.cmds, prev_endpoint: self.prev_endpoint, first_endpoint: self.first_endpoint, endpoints: self.endpoints, control_points: self.control_points, } } } /// An iterator of `Event<&Endpoint, &ControlPoint>`. #[derive(Clone)] pub struct IdEvents<'l> { cmds: CmdIter<'l>, idx: u32, prev_endpoint: EndpointId, first_endpoint: EndpointId, } impl<'l> IdEvents<'l> { fn new(cmds: &[u32]) -> Self { IdEvents { cmds: CmdIter::new(cmds), idx:0, prev_endpoint: EndpointId(0), first_endpoint: EndpointId(0), } } } impl<'l> Iterator for IdEvents<'l> { type Item = IdEvent; #[inline] fn next(&mut self) -> Option { match self.cmds.next() { Some(verb::BEGIN) => { let to = EndpointId(self.cmds.next().unwrap()); self.prev_endpoint = to; self.first_endpoint = to; self.idx += 2; Some(IdEvent::Begin { at: to }) } Some(verb::LINE) => { let to = EndpointId(self.cmds.next().unwrap()); let from = self.prev_endpoint; self.prev_endpoint = to; self.idx += 2; Some(IdEvent::Line { from: from, to: to, }) } Some(verb::QUADRATIC) => { let ctrl = ControlPointId(self.cmds.next().unwrap()); let to = EndpointId(self.cmds.next().unwrap()); let from = self.prev_endpoint; self.prev_endpoint = to; self.idx += 3; Some(IdEvent::Quadratic { from: from, ctrl: ctrl, to: to, }) } Some(verb::CUBIC) => { let ctrl1 = ControlPointId(self.cmds.next().unwrap()); let ctrl2 = ControlPointId(self.cmds.next().unwrap()); let to = EndpointId(self.cmds.next().unwrap()); let from = self.prev_endpoint; self.prev_endpoint = to; self.idx += 4; Some(IdEvent::Cubic { from: from, ctrl1: ctrl1, ctrl2: ctrl2, to: to, }) } Some(verb::END) => { let _first_index = self.cmds.next(); let last = self.prev_endpoint; let first = self.first_endpoint; self.prev_endpoint = first; self.idx += 2; Some(IdEvent::End { last: last, first: first, close: false, }) } Some(_) => { let _first_index = self.cmds.next(); let last = self.prev_endpoint; let first = self.first_endpoint; self.prev_endpoint = first; self.idx += 2; Some(IdEvent::End { last: last, first: first, close: true, }) } None => None, } } } /// An iterator of `PathEvent`. #[derive(Clone)] pub struct PointEvents<'l, Endpoint, ControlPoint> { cmds: CmdIter<'l>, prev_endpoint: usize, first_endpoint: usize, endpoints: &'l[Endpoint], control_points: &'l[ControlPoint], } impl<'l, Endpoint, ControlPoint> Iterator for PointEvents<'l, Endpoint, ControlPoint> where Endpoint: Position, ControlPoint: Position, { type Item = PathEvent; #[inline] fn next(&mut self) -> Option { match self.cmds.next() { Some(verb::BEGIN) => { let to = self.cmds.next().unwrap() as usize; self.prev_endpoint = to; self.first_endpoint = to; Some(Event::Begin { at: self.endpoints[to].position() }) } Some(verb::LINE) => { let to = self.cmds.next().unwrap() as usize; let from = self.prev_endpoint; self.prev_endpoint = to; Some(Event::Line { from: self.endpoints[from].position(), to: self.endpoints[to].position(), }) } Some(verb::QUADRATIC) => { let ctrl = self.cmds.next().unwrap() as usize; let to = self.cmds.next().unwrap() as usize; let from = self.prev_endpoint; self.prev_endpoint = to; Some(Event::Quadratic { from: self.endpoints[from].position(), ctrl: self.control_points[ctrl].position(), to: self.endpoints[to].position(), }) } Some(verb::CUBIC) => { let ctrl1 = self.cmds.next().unwrap() as usize; let ctrl2 = self.cmds.next().unwrap() as usize; let to = self.cmds.next().unwrap() as usize; let from = self.prev_endpoint; self.prev_endpoint = to; Some(Event::Cubic { from: self.endpoints[from].position(), ctrl1: self.control_points[ctrl1].position(), ctrl2: self.control_points[ctrl2].position(), to: self.endpoints[to].position(), }) } Some(verb::END) => { let _first_index = self.cmds.next(); let last = self.prev_endpoint; let first = self.first_endpoint; self.prev_endpoint = first; Some(Event::End { last: self.endpoints[last].position(), first: self.endpoints[first].position(), close: false, }) } Some(_) => { let _first_index = self.cmds.next(); let last = self.prev_endpoint; let first = self.first_endpoint; self.prev_endpoint = first; Some(Event::End { last: self.endpoints[last].position(), first: self.endpoints[first].position(), close: true, }) } None => None, } } } impl<'l, Endpoint, ControlPoint> PositionStore for CommandsPathSlice<'l, Endpoint, ControlPoint> where Endpoint: Position, ControlPoint: Position, { fn get_endpoint(&self, id: EndpointId) -> Point { self[id].position() } fn get_control_point(&self, id: ControlPointId) -> Point { self[id].position() } } #[test] fn simple_path() { let mut builder = PathCommands::builder(); builder.move_to(EndpointId(0)); builder.line_to(EndpointId(1)); builder.quadratic_bezier_to(ControlPointId(2), EndpointId(3)); builder.cubic_bezier_to(ControlPointId(4), ControlPointId(5), EndpointId(6)); builder.move_to(EndpointId(10)); builder.line_to(EndpointId(11)); builder.quadratic_bezier_to(ControlPointId(12), EndpointId(13)); builder.cubic_bezier_to(ControlPointId(14), ControlPointId(15), EndpointId(16)); builder.close(); builder.move_to(EndpointId(20)); builder.line_to(EndpointId(21)); builder.quadratic_bezier_to(ControlPointId(22), EndpointId(23)); builder.cubic_bezier_to(ControlPointId(24), ControlPointId(25), EndpointId(26)); let path = builder.build(); let mut iter = path.id_events(); assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(0) })); assert_eq!(iter.next(), Some(IdEvent::Line { from: EndpointId(0), to: EndpointId(1) })); assert_eq!(iter.next(), Some(IdEvent::Quadratic { from: EndpointId(1), ctrl: ControlPointId(2), to: EndpointId(3) })); assert_eq!(iter.next(), Some(IdEvent::Cubic { from: EndpointId(3), ctrl1: ControlPointId(4), ctrl2: ControlPointId(5), to: EndpointId(6) })); assert_eq!(iter.next(), Some(IdEvent::End { last: EndpointId(6), first: EndpointId(0), close: false })); assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(10) })); assert_eq!(iter.next(), Some(IdEvent::Line { from: EndpointId(10), to: EndpointId(11) })); assert_eq!(iter.next(), Some(IdEvent::Quadratic { from: EndpointId(11), ctrl: ControlPointId(12), to: EndpointId(13) })); assert_eq!(iter.next(), Some(IdEvent::Cubic { from: EndpointId(13), ctrl1: ControlPointId(14), ctrl2: ControlPointId(15), to: EndpointId(16) })); assert_eq!(iter.next(), Some(IdEvent::End { last: EndpointId(16), first: EndpointId(10), close: true })); assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(20) })); assert_eq!(iter.next(), Some(IdEvent::Line { from: EndpointId(20), to: EndpointId(21) })); assert_eq!(iter.next(), Some(IdEvent::Quadratic { from: EndpointId(21), ctrl: ControlPointId(22), to: EndpointId(23) })); assert_eq!(iter.next(), Some(IdEvent::Cubic { from: EndpointId(23), ctrl1: ControlPointId(24), ctrl2: ControlPointId(25), to: EndpointId(26) })); assert_eq!(iter.next(), Some(IdEvent::End { last: EndpointId(26), first: EndpointId(20), close: false })); assert_eq!(iter.next(), None); } #[test] fn next_event() { let mut builder = PathCommands::builder(); builder.move_to(EndpointId(0)); builder.line_to(EndpointId(1)); builder.quadratic_bezier_to(ControlPointId(2), EndpointId(3)); builder.cubic_bezier_to(ControlPointId(4), ControlPointId(5), EndpointId(6)); builder.move_to(EndpointId(10)); builder.line_to(EndpointId(11)); builder.quadratic_bezier_to(ControlPointId(12), EndpointId(13)); builder.cubic_bezier_to(ControlPointId(14), ControlPointId(15), EndpointId(16)); builder.close(); builder.move_to(EndpointId(20)); builder.line_to(EndpointId(21)); builder.quadratic_bezier_to(ControlPointId(22), EndpointId(23)); builder.cubic_bezier_to(ControlPointId(24), ControlPointId(25), EndpointId(26)); let path = builder.build(); let mut id = EventId(0); let first = id; assert_eq!(path.event(id), IdEvent::Begin { at: EndpointId(0) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::Line { from: EndpointId(0), to: EndpointId(1) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::Quadratic { from: EndpointId(1), ctrl: ControlPointId(2), to: EndpointId(3) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::Cubic { from: EndpointId(3), ctrl1: ControlPointId(4), ctrl2: ControlPointId(5), to: EndpointId(6) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::End { last: EndpointId(6), first: EndpointId(0), close: false }); assert_eq!(path.next_event_id_in_sub_path(id), first); id = path.next_event_id_in_path(id).unwrap(); let first = id; assert_eq!(path.event(id), IdEvent::Begin { at: EndpointId(10) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::Line { from: EndpointId(10), to: EndpointId(11) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::Quadratic { from: EndpointId(11), ctrl: ControlPointId(12), to: EndpointId(13) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::Cubic { from: EndpointId(13), ctrl1: ControlPointId(14), ctrl2: ControlPointId(15), to: EndpointId(16) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::End { last: EndpointId(16), first: EndpointId(10), close: true }); assert_eq!(path.next_event_id_in_sub_path(id), first); id = path.next_event_id_in_path(id).unwrap(); let first = id; assert_eq!(path.event(id), IdEvent::Begin { at: EndpointId(20) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::Line { from: EndpointId(20), to: EndpointId(21) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::Quadratic { from: EndpointId(21), ctrl: ControlPointId(22), to: EndpointId(23) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::Cubic { from: EndpointId(23), ctrl1: ControlPointId(24), ctrl2: ControlPointId(25), to: EndpointId(26) }); id = path.next_event_id_in_path(id).unwrap(); assert_eq!(path.event(id), IdEvent::End { last: EndpointId(26), first: EndpointId(20), close: false }); assert_eq!(path.next_event_id_in_path(id), None); assert_eq!(path.next_event_id_in_sub_path(id), first); } lyon_path-0.15.1/src/events.rs010064400017500001750000000076341360117331400144660ustar0000000000000000use crate::math::Point; use crate::geom::traits::Transformation; use crate::{EndpointId, ControlPointId, Position}; /// Represents an event or edge of path. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] pub enum Event { Begin { at: Endpoint, }, Line { from: Endpoint, to: Endpoint }, Quadratic { from: Endpoint, ctrl: ControlPoint, to: Endpoint }, Cubic { from: Endpoint, ctrl1: ControlPoint, ctrl2: ControlPoint, to: Endpoint }, End { last: Endpoint, first: Endpoint, close: bool }, } /// A path event representing endpoints and control points as positions. pub type PathEvent = Event; /// A path event representing endpoints and control points as IDs. pub type IdEvent = Event; impl Event { pub fn is_edge(&self) -> bool { match self { &Event::Line { .. } | &Event::Quadratic { .. } | &Event::Cubic { .. } | &Event::End { close: true, .. } => true, _ => false, } } pub fn from(&self) -> Ep where Ep: Clone { match &self { &Event::Line { from, .. } | &Event::Quadratic { from, .. } | &Event::Cubic { from, .. } | &Event::Begin { at: from } | &Event::End { last: from, .. } => { from.clone() } } } pub fn to(&self) -> Ep where Ep: Clone { match &self { &Event::Line { to, .. } | &Event::Quadratic { to, .. } | &Event::Cubic { to, .. } | &Event::Begin { at: to } | &Event::End { first: to, .. } => { to.clone() } } } pub fn with_points(&self) -> PathEvent where Ep: Position, Cp: Position, { match self { Event::Line { from, to } => Event::Line { from: from.position(), to: to.position(), }, Event::Quadratic { from, ctrl, to } => Event::Quadratic { from: from.position(), ctrl: ctrl.position(), to: to.position(), }, Event::Cubic { from, ctrl1, ctrl2, to } => Event::Cubic { from: from.position(), ctrl1: ctrl1.position(), ctrl2: ctrl2.position(), to: to.position(), }, Event::Begin { at } => Event::Begin { at: at.position(), }, Event::End { last, first, close } => Event::End { last: last.position(), first: first.position(), close: *close }, } } } impl PathEvent { pub fn transformed>(&self, mat: &T) -> Self { match self { Event::Line { from, to } => Event::Line { from: mat.transform_point(*from), to: mat.transform_point(*to), }, Event::Quadratic { from, ctrl, to } => Event::Quadratic { from: mat.transform_point(*from), ctrl: mat.transform_point(*ctrl), to: mat.transform_point(*to), }, Event::Cubic { from, ctrl1, ctrl2, to } => Event::Cubic { from: mat.transform_point(*from), ctrl1: mat.transform_point(*ctrl1), ctrl2: mat.transform_point(*ctrl2), to: mat.transform_point(*to), }, Event::Begin { at } => Event::Begin { at: mat.transform_point(*at), }, Event::End { first, last, close } => Event::End { last: mat.transform_point(*last), first: mat.transform_point(*first), close: *close, }, } } } lyon_path-0.15.1/src/iterator.rs010064400017500001750000000276471360117331400150210ustar0000000000000000//! Tools to iterate over paths. //! //! # Lyon path iterators //! //! ## Overview //! //! This module provides a collection of traits to extend the `Iterator` trait when //! iterating over paths. //! //! ## Examples //! //! ``` //! use lyon_path::iterator::*; //! use lyon_path::math::{point, vector}; //! use lyon_path::geom::BezierSegment; //! use lyon_path::{Path, PathEvent}; //! //! fn main() { //! // Start with a path. //! let mut builder = Path::builder(); //! builder.move_to(point(0.0, 0.0)); //! builder.line_to(point(10.0, 0.0)); //! builder.cubic_bezier_to(point(10.0, 10.0), point(0.0, 10.0), point(0.0, 5.0)); //! builder.close(); //! let path = builder.build(); //! //! // A simple std::iter::Iterator, //! let simple_iter = path.iter(); //! //! // Make it an iterator over simpler primitives flattened events, //! // which do not contain any curve. To do so we approximate each curve //! // linear segments according to a tolerance threshold which controls //! // the tradeoff between fidelity of the approximation and amount of //! // generated events. Let's use a tolerance threshold of 0.01. //! // The beauty of this approach is that the flattening happens lazily //! // while iterating without allocating memory for the path. //! let flattened_iter = path.iter().flattened(0.01); //! //! for evt in flattened_iter { //! match evt { //! PathEvent::Begin { at } => { println!(" - move to {:?}", at); } //! PathEvent::Line { from, to } => { println!(" - line {:?} -> {:?}", from, to); } //! PathEvent::End { last, first, close } => { //! if close { //! println!(" - close {:?} -> {:?}", last, first); //! } else { //! println!(" - end"); //! } //! } //! _ => { panic!() } //! } //! } //! //! // Sometimes, working with segments directly without dealing with Begin/End events //! // can be more convenient: //! for segment in path.iter().bezier_segments() { //! match segment { //! BezierSegment::Linear(segment) => { println!("{:?}", segment); } //! BezierSegment::Quadratic(segment) => { println!("{:?}", segment); } //! BezierSegment::Cubic(segment) => { println!("{:?}", segment); } //! } //! } //! } //! ``` //! //! Chaining the provided iterators allow performing some path manipulations lazily //! without allocating actual path objects to hold the result of the transformations. //! //! ``` //! extern crate lyon_path; //! use lyon_path::iterator::*; //! use lyon_path::math::{point, Angle, Rotation}; //! use lyon_path::Path; //! //! fn main() { //! // In practice it is more common to iterate over Path objects than vectors //! // of SVG commands (the former can be constructed from the latter). //! let mut builder = Path::builder(); //! builder.move_to(point(1.0, 1.0)); //! builder.line_to(point(2.0, 1.0)); //! builder.quadratic_bezier_to(point(2.0, 2.0), point(1.0, 2.0)); //! builder.cubic_bezier_to(point(0.0, 2.0), point(0.0, 0.0), point(1.0, 0.0)); //! builder.close(); //! let path = builder.build(); //! //! let transform = Rotation::new(Angle::radians(1.0)); //! //! for evt in path.iter().transformed(&transform).bezier_segments() { //! // ... //! } //! } //! ``` use crate::math::*; use crate::PathEvent; use crate::geom::{BezierSegment, QuadraticBezierSegment, CubicBezierSegment, LineSegment, quadratic_bezier, cubic_bezier}; use crate::geom::traits::Transformation; /// An extension trait for `PathEvent` iterators. pub trait PathIterator: Iterator + Sized { /// Returns an iterator that turns curves into line segments. fn flattened(self, tolerance: f32) -> Flattened { Flattened::new(tolerance, self) } /// Returns an iterator applying a 2D transform to all of its events. fn transformed<'l, T: Transformation>(self, mat: &'l T) -> Transformed<'l, Self, T> { Transformed::new(mat, self) } /// Returns an iterator of segments. fn bezier_segments(self) -> BezierSegments { BezierSegments { iter: self } } } impl PathIterator for Iter where Iter: Iterator, {} /// An iterator that consumes `Event` iterator and yields flattend path events (with no curves). pub struct Flattened { it: Iter, current_position: Point, current_curve: TmpFlatteningIter, tolerance: f32, } enum TmpFlatteningIter { Quadratic(quadratic_bezier::Flattened), Cubic(cubic_bezier::Flattened), None, } impl> Flattened { /// Create the iterator. pub fn new(tolerance: f32, it: Iter) -> Self { Flattened { it, current_position: point(0.0, 0.0), current_curve: TmpFlatteningIter::None, tolerance, } } } impl Iterator for Flattened where Iter: Iterator, { type Item = PathEvent; fn next(&mut self) -> Option { match self.current_curve { TmpFlatteningIter::Quadratic(ref mut it) => { if let Some(to) = it.next() { let from = self.current_position; self.current_position = to; return Some(PathEvent::Line { from, to }); } } TmpFlatteningIter::Cubic(ref mut it) => { if let Some(to) = it.next() { let from = self.current_position; self.current_position = to; return Some(PathEvent::Line { from, to }); } } _ => {} } self.current_curve = TmpFlatteningIter::None; match self.it.next() { Some(PathEvent::Begin { at }) => Some(PathEvent::Begin { at }), Some(PathEvent::Line { from, to }) => Some(PathEvent::Line { from, to }), Some(PathEvent::End { last, first, close }) => Some(PathEvent::End { last, first, close }), Some(PathEvent::Quadratic { from, ctrl, to }) => { self.current_position = from; self.current_curve = TmpFlatteningIter::Quadratic( QuadraticBezierSegment { from, ctrl, to }.flattened(self.tolerance) ); self.next() } Some(PathEvent::Cubic { from, ctrl1, ctrl2, to }) => { self.current_position = from; self.current_curve = TmpFlatteningIter::Cubic( CubicBezierSegment { from, ctrl1, ctrl2, to }.flattened(self.tolerance) ); self.next() } None => None, } } } /// Applies a 2D transform to a path iterator and yields the resulting path iterator. pub struct Transformed<'l, I, T> { it: I, transform: &'l T, } impl<'l, I, T: Transformation> Transformed<'l, I, T> where I: Iterator, { /// Creates a new transformed path iterator from a path iterator. #[inline] pub fn new(transform: &'l T, it: I) -> Transformed<'l, I, T> { Transformed { it, transform, } } } impl<'l, I, T> Iterator for Transformed<'l, I, T> where I: Iterator, T: Transformation { type Item = PathEvent; fn next(&mut self) -> Option { match self.it.next() { None => None, Some(ref evt) => Some(evt.transformed(self.transform)), } } } /// An iterator that consumes an iterator of `Point`s and produces `Event`s. /// /// # Example /// /// ``` /// # extern crate lyon_path; /// # use lyon_path::iterator::FromPolyline; /// # use lyon_path::math::point; /// # fn main() { /// let points = [ /// point(1.0, 1.0), /// point(2.0, 1.0), /// point(1.0, 2.0) /// ]; /// let iter = FromPolyline::closed(points.iter().cloned()); /// # } /// ``` pub struct FromPolyline { iter: Iter, current: Point, first: Point, is_first: bool, done: bool, close: bool, } impl> FromPolyline { pub fn new(close: bool, iter: Iter) -> Self { FromPolyline { iter, current: point(0.0, 0.0), first: point(0.0, 0.0), is_first: true, done: false, close, } } pub fn closed(iter: Iter) -> Self { FromPolyline::new(true, iter) } pub fn open(iter: Iter) -> Self { FromPolyline::new(false, iter) } } impl Iterator for FromPolyline where Iter: Iterator, { type Item = PathEvent; fn next(&mut self) -> Option { if self.done { return None; } if let Some(next) = self.iter.next() { debug_assert!(next.x.is_finite()); debug_assert!(next.y.is_finite()); let from = self.current; self.current = next; return if self.is_first { self.is_first = false; self.first = next; Some(PathEvent::Begin { at: next }) } else { Some(PathEvent::Line { from, to: next }) } } self.done = true; Some(PathEvent::End { last: self.current, first: self.first, close: self.close, }) } } /// Turns an iterator of `Event` into an iterator of `BezierSegment`. pub struct BezierSegments { iter: Iter } impl Iterator for BezierSegments where Iter: Iterator { type Item = BezierSegment; fn next(&mut self) -> Option> { match self.iter.next() { Some(PathEvent::Line { from, to }) => Some(BezierSegment::Linear(LineSegment { from, to })), Some(PathEvent::End { last, first, close: true })=> Some(BezierSegment::Linear(LineSegment { from: last, to: first })), Some(PathEvent::End { close: false, .. }) => self.next(), Some(PathEvent::Quadratic { from, ctrl, to }) => Some(BezierSegment::Quadratic(QuadraticBezierSegment { from, ctrl, to })), Some(PathEvent::Cubic { from, ctrl1, ctrl2, to }) => Some(BezierSegment::Cubic(CubicBezierSegment { from, ctrl1, ctrl2, to })), Some(PathEvent::Begin { .. }) => self.next(), None => None, } } } #[test] fn test_from_polyline_open() { let points = &[ point(1.0, 1.0), point(3.0, 1.0), point(4.0, 5.0), point(5.0, 2.0), ]; let mut evts = FromPolyline::open(points.iter().cloned()); assert_eq!(evts.next(), Some(PathEvent::Begin { at: point(1.0, 1.0) })); assert_eq!(evts.next(), Some(PathEvent::Line { from: point(1.0, 1.0), to: point(3.0, 1.0) })); assert_eq!(evts.next(), Some(PathEvent::Line { from: point(3.0, 1.0), to: point(4.0, 5.0) })); assert_eq!(evts.next(), Some(PathEvent::Line { from: point(4.0, 5.0), to: point(5.0, 2.0) })); assert_eq!(evts.next(), Some(PathEvent::End { last: point(5.0, 2.0), first: point(1.0, 1.0), close: false })); assert_eq!(evts.next(), None); } #[test] fn test_from_polyline_closed() { let points = &[ point(1.0, 1.0), point(3.0, 1.0), point(4.0, 5.0), point(5.0, 2.0), ]; let mut evts = FromPolyline::closed(points.iter().cloned()); assert_eq!(evts.next(), Some(PathEvent::Begin { at: point(1.0, 1.0) })); assert_eq!(evts.next(), Some(PathEvent::Line { from: point(1.0, 1.0), to: point(3.0, 1.0) })); assert_eq!(evts.next(), Some(PathEvent::Line { from: point(3.0, 1.0), to: point(4.0, 5.0) })); assert_eq!(evts.next(), Some(PathEvent::Line { from: point(4.0, 5.0), to: point(5.0, 2.0) })); assert_eq!(evts.next(), Some(PathEvent::End { last: point(5.0, 2.0), first: point(1.0, 1.0), close: true })); assert_eq!(evts.next(), None); } lyon_path-0.15.1/src/lib.rs010064400017500001750000000136431360010744200137230ustar0000000000000000#![doc(html_logo_url = "https://nical.github.io/lyon-doc/lyon-logo.svg")] #![deny(bare_trait_objects)] //! Data structures and traits to work with paths (vector graphics). //! //! To build and consume paths, see the [builder](builder/index.html) and //! [iterator](iterator/index.html) modules. //! //! This crate is reexported in [lyon](https://docs.rs/lyon/). //! //! # Examples //! //! ``` //! # extern crate lyon_path; //! # fn main() { //! use lyon_path::Path; //! use lyon_path::math::{point}; //! use lyon_path::builder::*; //! //! // Create a builder object to build the path. //! let mut builder = Path::builder(); //! //! // Build a simple path. //! let mut builder = Path::builder(); //! builder.move_to(point(0.0, 0.0)); //! builder.line_to(point(1.0, 2.0)); //! builder.line_to(point(2.0, 0.0)); //! builder.line_to(point(1.0, 1.0)); //! builder.close(); //! //! // Generate the actual path object. //! let path = builder.build(); //! //! for event in &path { //! println!("{:?}", event); //! } //! # } //! ``` //! pub use lyon_geom as geom; #[cfg(feature = "serialization")] #[macro_use] pub extern crate serde; mod events; mod path_state; mod path; pub mod commands; pub mod polygon; pub mod iterator; pub mod builder; pub use crate::path::*; pub use crate::events::*; pub use crate::path_state::*; pub use crate::geom::ArcFlags; pub use crate::geom::math as math; use std::u32; use std::fmt; use math::Point; /// The fill rule defines how to determine what is inside and what is outside of the shape. /// /// See the SVG specification. #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] pub enum FillRule { EvenOdd, NonZero, } impl FillRule { #[inline] pub fn is_in(&self, winding_number: i16) -> bool { match *self { FillRule::EvenOdd => { winding_number % 2 != 0 } FillRule::NonZero => { winding_number != 0 } } } #[inline] pub fn is_out(&self, winding_number: i16) -> bool { !self.is_in(winding_number) } } /// ID of a control point in a path. #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] pub struct ControlPointId(pub u32); impl ControlPointId { pub const INVALID: Self = ControlPointId(u32::MAX); pub fn offset(self) -> usize { self.0 as usize } pub fn to_usize(self) -> usize { self.0 as usize } pub fn from_usize(val: usize) -> Self { ControlPointId(val as u32) } } impl fmt::Debug for ControlPointId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "#{}", self.0) } } /// ID of an endpoint point in a path. #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] pub struct EndpointId(pub u32); impl EndpointId { pub const INVALID: Self = EndpointId(u32::MAX); pub fn offset(self) -> usize { self.0 as usize } pub fn to_usize(self) -> usize { self.0 as usize } pub fn from_usize(val: usize) -> Self { EndpointId(val as u32) } } impl fmt::Debug for EndpointId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "#{}", self.0) } } /// Refers to an event in a path. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] pub struct EventId( #[doc(hidden)] pub u32 ); impl EventId { pub const INVALID: Self = EventId(std::u32::MAX); pub fn to_usize(&self) -> usize { self.0 as usize } } /// Interface for types types (typically endpoints and control points) that have /// a 2D position. pub trait Position { fn position(&self) -> Point; } impl Position for crate::geom::euclid::Point2D { fn position(&self) -> Point { self.to_untyped() } } impl<'l, T: Position> Position for &'l T { fn position(&self) -> Point { (*self).position() } } impl Position for (f32, f32) { fn position(&self) -> Point { Point::new(self.0, self.1) } } impl Position for [f32; 2] { fn position(&self) -> Point { Point::new(self[0], self[1]) } } /// Interface for objects storing endpoints and control points positions. /// /// This interface can be implemented by path objects themselves or via external /// data structures. pub trait PositionStore { fn get_endpoint(&self, id: EndpointId) -> Point; fn get_control_point(&self, id: ControlPointId) -> Point; } impl<'l> PositionStore for (&'l [Point], &'l [Point]) { fn get_endpoint(&self, id: EndpointId) -> Point { self.0[id.to_usize()] } fn get_control_point(&self, id: ControlPointId) -> Point { self.1[id.to_usize()] } } /// Interface for objects storing custom attributes associated with endpoints. /// /// This interface can be implemented by path objects themselves or via external /// data structures. pub trait AttributeStore { /// Returns the endpoint's custom attributes as a slice of 32 bits floats. /// /// The size of the slice must be equal to the result of `num_attributes()`. fn get(&self, id: EndpointId) -> &[f32]; /// Returns the number of float attributes per endpoint. /// /// All endpoints must have the same number of attributes. fn num_attributes(&self) -> usize; } impl AttributeStore for () { fn num_attributes(&self) -> usize { 0 } fn get(&self, _: EndpointId) -> &[f32] { &[] } } /// A view over a contiguous storage of custom attributes. pub struct AttributeSlice<'l> { data: &'l [f32], stride: usize, } impl<'l> AttributeSlice<'l> { pub fn new(data: &'l[f32], num_attributes: usize) -> Self { AttributeSlice { data, stride: num_attributes, } } } impl<'l> AttributeStore for AttributeSlice<'l> { fn get(&self, id: EndpointId) -> &[f32] { let start = id.to_usize() * self.stride; let end = start + self.stride; &self.data[start..end] } fn num_attributes(&self) -> usize { self.stride } } lyon_path-0.15.1/src/path.rs010064400017500001750000001273311360117331400141130ustar0000000000000000//! The default path data structure. //! use crate::math::*; use crate::builder::*; use crate::{Event, PathEvent, IdEvent, EndpointId, ControlPointId, AttributeStore, PositionStore}; use crate::geom::Arc; use crate::geom::traits::Transformation; use std::iter::IntoIterator; use std::u32; /// Enumeration corresponding to the [Event](https://docs.rs/lyon_core/*/lyon_core/events/enum.Event.html) enum /// without the parameters. /// /// This is used by the [Path](struct.Path.html) data structure to store path events a tad /// more efficiently. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] enum Verb { LineTo, QuadraticTo, CubicTo, Begin, Close, End, } /// A simple path data structure. /// /// # Custom attributes /// /// Paths can store a fixed number of extra `f32` values per endpoint, called /// "custom attributes" or "interpolated attributes" through the documentation. /// These can be handy to represent arbitrary attributes such as variable colors, /// line width, etc. /// /// See also: /// - [`BuilderWithAttributes`](struct.BuilderWithAttributes.html). /// - [`Path::builder_with_attributes`](struct.Path.html#method.builder_with_attributes). /// - [`Path::attributes`](struct.Path.html#method.attributes). /// /// # Representation /// /// Paths contain two buffers: /// - a buffer of commands (Begin, Line, Quadratic, Cubic, Close or End), /// - and a buffer of pairs of floats that can be endpoints control points or custom attributes. /// /// The order of storage for points is determined by the sequence of commands. /// Custom attributes (if any) always directly follow endpoints. If there is an odd number /// of attributes, the last float of the each attribute sequence is set to zero and is not used. /// /// ```ascii /// __________________________ /// | | | | /// | Begin | Line |Quadratic| ... /// |_______|______|_________|_ /// __________________________________________________________________________ /// | | | | | | | | /// |start x,y|attributes| to x, y |attributes|ctrl x,y | to x, y |attributes| ... /// |_________|__________|_________|__________|_________|_________|__________|_ /// ``` /// #[derive(Clone, Debug, Default)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))] pub struct Path { points: Box<[Point]>, verbs: Box<[Verb]>, num_attributes: usize, } /// A view on a `Path`. #[derive(Copy, Clone, Debug)] pub struct PathSlice<'l> { points: &'l [Point], verbs: &'l [Verb], num_attributes: usize, } impl Path { /// Creates a [Builder](struct.Builder.html) to build a path. pub fn builder() -> Builder { Builder::new() } /// Creates a [BuilderWithAttributes](struct.BuilderWithAttributes.html) to build a path /// with custom attributes. pub fn builder_with_attributes(num_attributes: usize) -> BuilderWithAttributes { BuilderWithAttributes::new(num_attributes) } /// Creates an Empty `Path`. #[inline] pub fn new() -> Path { Path { points: Box::new([]), verbs: Box::new([]), num_attributes: 0, } } /// Returns a view on this `Path`. #[inline] pub fn as_slice(&self) -> PathSlice { PathSlice { points: &self.points[..], verbs: &self.verbs[..], num_attributes: self.num_attributes, } } /// Returns a slice over an endpoint's custom attributes. #[inline] pub fn attributes(&self, endpoint: EndpointId) -> &[f32] { interpolated_attributes(self.num_attributes, &self.points, endpoint) } /// Iterates over the entire `Path`. pub fn iter(&self) -> Iter { Iter::new(self.num_attributes, &self.points[..], &self.verbs[..]) } /// Iterates over the endpoint and control point ids of the `Path`. pub fn id_iter(&self) -> IdIter { IdIter::new(self.num_attributes, &self.verbs[..]) } pub fn iter_with_attributes(&self) -> IterWithAttributes { IterWithAttributes::new( self.num_attributes(), &self.points[..], &self.verbs[..], ) } /// Applies a transform to all endpoints and control points of this path and /// Returns the result. pub fn transformed>(&self, transform: &T) -> Self { let mut result = self.clone(); result.apply_transform(transform); result } /// Reversed version of this path with edge loops are specified in the opposite /// order. pub fn reversed(&self) -> Self { reverse_path(self.as_slice()) } fn apply_transform>(&mut self, transform: &T) { let iter = IdIter::new(self.num_attributes, &self.verbs[..]); for evt in iter { match evt { IdEvent::Begin { at } => { self.points[at.to_usize()] = transform.transform_point(self.points[at.to_usize()]); } IdEvent::Line { to, .. } => { self.points[to.to_usize()] = transform.transform_point(self.points[to.to_usize()]); } IdEvent::Quadratic { ctrl, to, .. } => { self.points[ctrl.to_usize()] = transform.transform_point(self.points[ctrl.to_usize()]); self.points[to.to_usize()] = transform.transform_point(self.points[to.to_usize()]); } IdEvent::Cubic { ctrl1, ctrl2, to, .. } => { self.points[ctrl1.to_usize()] = transform.transform_point(self.points[ctrl1.to_usize()]); self.points[ctrl2.to_usize()] = transform.transform_point(self.points[ctrl2.to_usize()]); self.points[to.to_usize()] = transform.transform_point(self.points[to.to_usize()]); } IdEvent::End { .. } => {} } } } /// Concatenate two paths. /// /// They must have the same number of custom attributes. pub fn merge(&self, other: &Self) -> Self { assert_eq!(self.num_attributes, other.num_attributes); let mut verbs = Vec::with_capacity(self.verbs.len() + other.verbs.len()); let mut points = Vec::with_capacity(self.points.len() + other.points.len()); verbs.extend_from_slice(&self.verbs); verbs.extend_from_slice(&other.verbs); points.extend_from_slice(&self.points); points.extend_from_slice(&other.points); Path { verbs: verbs.into_boxed_slice(), points: points.into_boxed_slice(), num_attributes: self.num_attributes, } } } impl std::ops::Index for Path { type Output = Point; fn index(&self, id: EndpointId) -> &Point { &self.points[id.to_usize()] } } impl std::ops::Index for Path { type Output = Point; fn index(&self, id: ControlPointId) -> &Point { &self.points[id.to_usize()] } } impl<'l> IntoIterator for &'l Path { type Item = PathEvent; type IntoIter = Iter<'l>; fn into_iter(self) -> Iter<'l> { self.iter() } } impl<'l> Into> for &'l Path { fn into(self) -> PathSlice<'l> { self.as_slice() } } impl PositionStore for Path { fn get_endpoint(&self, id: EndpointId) -> Point { self.points[id.to_usize()] } fn get_control_point(&self, id: ControlPointId) -> Point { self.points[id.to_usize()] } } impl AttributeStore for Path { fn get(&self, id: EndpointId) -> &[f32] { interpolated_attributes(self.num_attributes, &self.points, id) } fn num_attributes(&self) -> usize { self.num_attributes } } /// An immutable view over a Path. impl<'l> PathSlice<'l> { /// Iterates over the path. pub fn iter<'a>(&'a self) -> Iter<'l> { Iter::new(self.num_attributes, self.points, self.verbs) } /// Iterates over the endpoint and control point ids of the `Path`. pub fn id_iter(&self) -> IdIter { IdIter::new(self.num_attributes, self.verbs) } pub fn is_empty(&self) -> bool { self.verbs.is_empty() } /// Returns a slice over an endpoint's custom attributes. #[inline] pub fn attributes(&self, endpoint: EndpointId) -> &[f32] { interpolated_attributes(self.num_attributes, &self.points, endpoint) } } impl<'l> IntoIterator for PathSlice<'l> { type Item = PathEvent; type IntoIter = Iter<'l>; fn into_iter(self) -> Iter<'l> { self.iter() } } impl<'l, 'a> IntoIterator for &'a PathSlice<'l> { type Item = PathEvent; type IntoIter = Iter<'l>; fn into_iter(self) -> Iter<'l> { self.iter() } } impl<'l> PositionStore for PathSlice<'l> { fn get_endpoint(&self, id: EndpointId) -> Point { self.points[id.to_usize()] } fn get_control_point(&self, id: ControlPointId) -> Point { self.points[id.to_usize()] } } impl<'l> AttributeStore for PathSlice<'l> { fn get(&self, id: EndpointId) -> &[f32] { interpolated_attributes(self.num_attributes, self.points, id) } fn num_attributes(&self) -> usize { self.num_attributes } } /// Builds path objects. pub struct Builder { points: Vec, verbs: Vec, current_position: Point, first_position: Point, first_vertex: EndpointId, first_verb: u32, need_moveto: bool, last_cmd: Verb, } impl Builder { pub fn new() -> Self { Builder::with_capacity(0, 0) } pub fn with_capacity(points: usize, edges: usize) -> Self { Builder { points: Vec::with_capacity(points), verbs: Vec::with_capacity(edges), current_position: Point::new(0.0, 0.0), first_position: Point::new(0.0, 0.0), first_vertex: EndpointId(0), first_verb: 0, need_moveto: true, last_cmd: Verb::End, } } pub fn with_svg(self) -> SvgPathBuilder { SvgPathBuilder::new(self) } pub fn flattened(self, tolerance: f32) -> FlatteningBuilder { FlatteningBuilder::new(self, tolerance) } pub fn move_to(&mut self, to: Point) -> EndpointId { nan_check(to); self.end_if_needed(); self.need_moveto = false; self.first_position = to; let id = EndpointId(self.points.len() as u32); self.first_vertex = id; self.first_verb = self.verbs.len() as u32; self.current_position = to; self.points.push(to); self.verbs.push(Verb::Begin); self.last_cmd = Verb::Begin; id } pub fn line_to(&mut self, to: Point) -> EndpointId { nan_check(to); self.move_to_if_needed(); let id = EndpointId(self.points.len() as u32); self.points.push(to); self.verbs.push(Verb::LineTo); self.current_position = to; self.last_cmd = Verb::LineTo; id } pub fn close(&mut self) { // Relative path ops tend to accumulate small floating point imprecisions // which results in the last segment ending almost but not quite at the // start of the sub-path, causing a new edge to be inserted which often // intersects with the first or last edge. This can affect algorithms that // Don't handle self-intersecting paths. // Deal with this by snapping the last point if it is very close to the // start of the sub path. if let Some(p) = self.points.last_mut() { let d = (*p - self.first_position).abs(); if d.x + d.y < 0.0001 { *p = self.first_position; } } self.verbs.push(Verb::Close); self.current_position = self.first_position; self.need_moveto = true; self.last_cmd = Verb::Close; } pub fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) -> EndpointId { nan_check(ctrl); nan_check(to); self.move_to_if_needed(); self.points.push(ctrl); let id = EndpointId(self.points.len() as u32); self.points.push(to); self.verbs.push(Verb::QuadraticTo); self.current_position = to; self.last_cmd = Verb::QuadraticTo; id } pub fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) -> EndpointId { nan_check(ctrl1); nan_check(ctrl2); nan_check(to); self.move_to_if_needed(); self.points.push(ctrl1); self.points.push(ctrl2); let id = EndpointId(self.points.len() as u32); self.points.push(to); self.verbs.push(Verb::CubicTo); self.current_position = to; self.last_cmd = Verb::CubicTo; id } pub fn arc( &mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle ) { nan_check(center); nan_check(radii.to_point()); debug_assert!(!sweep_angle.get().is_nan()); debug_assert!(!x_rotation.get().is_nan()); let start_angle = (self.current_position - center).angle_from_x_axis() - x_rotation; let arc = Arc { start_angle, center, radii, sweep_angle, x_rotation }; arc.for_each_quadratic_bezier(&mut|curve| { self.quadratic_bezier_to(curve.ctrl, curve.to); }); } /// Add a closed polygon. pub fn polygon(&mut self, points: &[Point]) { self.points.reserve(points.len()); self.verbs.reserve(points.len() + 1); build_polygon(self, points); } fn move_to_if_needed(&mut self) { if self.need_moveto { let first = self.first_position; self.move_to(first); } } fn end_if_needed(&mut self) { if (self.last_cmd as u8) <= (Verb::Begin as u8) { self.verbs.push(Verb::End); } } pub fn current_position(&self) -> Point { self.current_position } pub fn build(mut self) -> Path { self.end_if_needed(); Path { points: self.points.into_boxed_slice(), verbs: self.verbs.into_boxed_slice(), num_attributes: 0, } } } impl Build for Builder { type PathType = Path; fn build(self) -> Path { self.build() } fn build_and_reset(&mut self) -> Path { self.current_position = Point::new(0.0, 0.0); self.first_position = Point::new(0.0, 0.0); Path { points: std::mem::replace(&mut self.points, Vec::new()).into_boxed_slice(), verbs: std::mem::replace(&mut self.verbs, Vec::new()).into_boxed_slice(), num_attributes: 0, } } } impl FlatPathBuilder for Builder { fn move_to(&mut self, to: Point) { self.move_to(to); } fn line_to(&mut self, to: Point) { self.line_to(to); } fn close(&mut self) { self.close(); } fn current_position(&self) -> Point { self.current_position } } impl PolygonBuilder for Builder { fn polygon(&mut self, points: &[Point]) { self.polygon(points); } } impl PathBuilder for Builder { fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) { self.quadratic_bezier_to(ctrl, to); } fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) { self.cubic_bezier_to(ctrl1, ctrl2, to); } fn arc( &mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle ) { self.arc(center, radii, sweep_angle, x_rotation); } } /// Builds path objects with custom attributes. pub struct BuilderWithAttributes { points: Vec, verbs: Vec, current_position: Point, first_position: Point, first_vertex: EndpointId, first_verb: u32, need_moveto: bool, last_cmd: Verb, num_attributes: usize, } impl BuilderWithAttributes { pub fn new(num_attributes: usize) -> Self { BuilderWithAttributes::with_capacity(num_attributes, 0, 0) } pub fn with_capacity(num_attributes: usize, points: usize, edges: usize) -> Self { BuilderWithAttributes { points: Vec::with_capacity(points), verbs: Vec::with_capacity(edges), current_position: Point::new(0.0, 0.0), first_position: Point::new(0.0, 0.0), first_vertex: EndpointId(0), first_verb: 0, need_moveto: true, last_cmd: Verb::End, num_attributes, } } fn push_attributes(&mut self, attributes: &[f32]) { assert_eq!(attributes.len(), self.num_attributes); for i in 0..(self.num_attributes/2) { let x = attributes[i*2]; let y = attributes[i*2 + 1]; self.points.push(point(x, y)); } if self.num_attributes % 2 == 1 { let x = attributes[self.num_attributes - 1]; self.points.push(point(x, 0.0)); } } pub fn move_to(&mut self, to: Point, attributes: &[f32]) -> EndpointId { nan_check(to); self.end_if_needed(); let id = EndpointId(self.points.len() as u32); self.need_moveto = false; self.first_position = to; self.first_vertex = id; self.first_verb = self.verbs.len() as u32; self.current_position = to; self.points.push(to); self.push_attributes(attributes); self.verbs.push(Verb::Begin); self.last_cmd = Verb::Begin; id } pub fn line_to(&mut self, to: Point, attributes: &[f32]) -> EndpointId { nan_check(to); self.move_to_if_needed(); let id = EndpointId(self.points.len() as u32); self.points.push(to); self.verbs.push(Verb::LineTo); self.push_attributes(attributes); self.current_position = to; self.last_cmd = Verb::LineTo; id } pub fn close(&mut self) { // Relative path ops tend to accumulate small floating point imprecisions // which results in the last segment ending almost but not quite at the // start of the sub-path, causing a new edge to be inserted which often // intersects with the first or last edge. This can affect algorithms that // Don't handle self-intersecting paths. // Deal with this by snapping the last point if it is very close to the // start of the sub path. if let Some(p) = self.points.last_mut() { let d = (*p - self.first_position).abs(); if d.x + d.y < 0.0001 { *p = self.first_position; } } self.verbs.push(Verb::Close); self.current_position = self.first_position; self.need_moveto = true; self.last_cmd = Verb::Close; } pub fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point, attributes: &[f32]) -> EndpointId { nan_check(ctrl); nan_check(to); self.move_to_if_needed(); self.points.push(ctrl); let id = EndpointId(self.points.len() as u32); self.points.push(to); self.push_attributes(attributes); self.verbs.push(Verb::QuadraticTo); self.current_position = to; self.last_cmd = Verb::QuadraticTo; id } pub fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point, attributes: &[f32]) -> EndpointId { nan_check(ctrl1); nan_check(ctrl2); nan_check(to); self.move_to_if_needed(); self.points.push(ctrl1); self.points.push(ctrl2); let id = EndpointId(self.points.len() as u32); self.points.push(to); self.push_attributes(attributes); self.verbs.push(Verb::CubicTo); self.current_position = to; self.last_cmd = Verb::CubicTo; id } fn move_to_if_needed(&mut self) { if !self.need_moveto { return; } assert!(!self.points.is_empty()); let first = self.first_position; self.need_moveto = false; self.current_position = first; self.points.push(first); let first_idx = self.first_vertex.to_usize(); for i in 0..(self.num_attributes + 1) / 2 { let val = self.points[first_idx + i]; self.points.push(val); } self.verbs.push(Verb::Begin); self.last_cmd = Verb::Begin; } fn end_if_needed(&mut self) { if (self.last_cmd as u8) <= (Verb::Begin as u8) { self.verbs.push(Verb::End); } } pub fn current_position(&self) -> Point { self.current_position } pub fn build(mut self) -> Path { self.end_if_needed(); Path { points: self.points.into_boxed_slice(), verbs: self.verbs.into_boxed_slice(), num_attributes: self.num_attributes, } } } #[inline] fn nan_check(p: Point) { debug_assert!(p.x.is_finite()); debug_assert!(p.y.is_finite()); } /// An iterator for `Path` and `PathSlice`. #[derive(Clone)] pub struct Iter<'l> { points: PointIter<'l>, verbs: ::std::slice::Iter<'l, Verb>, current: Point, first: Point, num_attributes: usize, // Number of slots in the points array occupied by the custom attributes. attrib_stride: usize, } impl<'l> Iter<'l> { fn new(num_attributes: usize, points: &'l [Point], verbs: &'l [Verb]) -> Self { Iter { points: PointIter::new(points), verbs: verbs.iter(), current: point(0.0, 0.0), first: point(0.0, 0.0), num_attributes, attrib_stride: (num_attributes + 1) / 2, } } #[inline] fn skip_attributes(&mut self) { self.points.advance_n(self.attrib_stride); } } impl<'l> Iterator for Iter<'l> { type Item = PathEvent; #[inline] fn next(&mut self) -> Option { match self.verbs.next() { Some(&Verb::Begin) => { self.current = self.points.next(); self.skip_attributes(); self.first = self.current; Some(PathEvent::Begin { at: self.current }) } Some(&Verb::LineTo) => { let from = self.current; self.current = self.points.next(); self.skip_attributes(); Some(PathEvent::Line { from, to: self.current }) } Some(&Verb::QuadraticTo) => { let from = self.current; let ctrl = self.points.next(); self.current = self.points.next(); self.skip_attributes(); Some(PathEvent::Quadratic { from, ctrl, to: self.current }) } Some(&Verb::CubicTo) => { let from = self.current; let ctrl1 = self.points.next(); let ctrl2 = self.points.next(); self.current = self.points.next(); self.skip_attributes(); Some(PathEvent::Cubic { from, ctrl1, ctrl2, to: self.current }) } Some(&Verb::Close) => { let last = self.current; self.current = self.first; Some(PathEvent::End { last, first: self.first, close: true, }) } Some(&Verb::End) => { let last = self.current; self.current = self.first; Some(PathEvent::End { last, first: self.first, close: false, }) } None => None, } } } /// Manually implemented to avoid iterator overhead when skipping over /// several points where the custom attributes are stored. /// /// It makes an unfortunately large difference (the simple iterator /// benchmarks are 2 to 3 times faster). #[derive(Copy, Clone)] struct PointIter<'l> { ptr: *const Point, end: *const Point, _marker: std::marker::PhantomData<&'l Point>, } impl<'l> PointIter<'l> { fn new(slice: &[Point]) -> Self { let ptr = slice.as_ptr(); let end = unsafe { ptr.offset(slice.len() as isize) }; PointIter { ptr, end, _marker: std::marker::PhantomData, } } #[inline] fn next(&mut self) -> Point { // Don't bother panicking here. calls to next // are always followed by advance_n which will // catch the issue and panic. if self.ptr >= self.end { return point(std::f32::NAN, std::f32::NAN); } unsafe { let output = *self.ptr; self.ptr = self.ptr.offset(1); return output; } } #[inline] fn advance_n(&mut self, n: usize) { unsafe { self.ptr = self.ptr.offset(n as isize); assert!(self.ptr <= self.end) } } } /// An iterator for `Path` and `PathSlice`. #[derive(Clone)] pub struct IterWithAttributes<'l> { points: PointIter<'l>, verbs: ::std::slice::Iter<'l, Verb>, current: (Point, &'l[f32]), first: (Point, &'l[f32]), num_attributes: usize, attrib_stride: usize, } impl<'l> IterWithAttributes<'l> { fn new(num_attributes: usize, points: &'l[Point], verbs: &'l[Verb]) -> Self { IterWithAttributes { points: PointIter::new(points), verbs: verbs.iter(), current: (point(0.0, 0.0), &[]), first: (point(0.0, 0.0), &[]), num_attributes, attrib_stride: (num_attributes + 1) / 2, } } pub fn points(self) -> Iter<'l> { Iter { points: self.points, verbs: self.verbs, current: self.current.0, first: self.first.0, num_attributes: self.num_attributes, attrib_stride: self.attrib_stride, } } #[inline] fn pop_endpoint(&mut self) -> (Point, &'l[f32]) { let position = self.points.next(); let attributes = unsafe { let ptr = &(*self.points.ptr).x as *const f32; std::slice::from_raw_parts(ptr, self.num_attributes) }; self.points.advance_n(self.attrib_stride); (position, attributes) } } impl<'l> Iterator for IterWithAttributes<'l> { type Item = Event<(Point, &'l[f32]), Point>; #[inline] fn next(&mut self) -> Option { match self.verbs.next() { Some(&Verb::Begin) => { self.current = self.pop_endpoint(); self.first = self.current; Some(Event::Begin { at: self.current, }) } Some(&Verb::LineTo) => { let from = self.current; self.current = self.pop_endpoint(); Some(Event::Line { from, to: self.current }) } Some(&Verb::QuadraticTo) => { let from = self.current; let ctrl = self.points.next(); self.current = self.pop_endpoint(); Some(Event::Quadratic { from, ctrl, to: self.current }) } Some(&Verb::CubicTo) => { let from = self.current; let ctrl1 = self.points.next(); let ctrl2 = self.points.next(); self.current = self.pop_endpoint(); Some(Event::Cubic { from, ctrl1, ctrl2, to: self.current }) } Some(&Verb::Close) => { let last = self.current; self.current = self.first; Some(Event::End { last, first: self.first, close: true, }) } Some(&Verb::End) => { let last = self.current; self.current = self.first; Some(Event::End { last, first: self.first, close: false, }) } None => None, } } } /// An iterator of endpoint and control point ids for `Path` and `PathSlice`. #[derive(Clone, Debug)] pub struct IdIter<'l> { verbs: ::std::slice::Iter<'l, Verb>, current: u32, first: u32, evt: u32, endpoint_stride: u32, } impl<'l> IdIter<'l> { fn new(num_attributes: usize, verbs: &'l [Verb]) -> Self { IdIter { verbs: verbs.iter(), current: 0, first: 0, evt: 0, endpoint_stride: (num_attributes as u32 + 1) / 2 + 1, } } } impl<'l> Iterator for IdIter<'l> { type Item = IdEvent; #[inline] fn next(&mut self) -> Option { match self.verbs.next() { Some(&Verb::Begin) => { let at = self.current; self.first = at; Some(IdEvent::Begin { at: EndpointId(at) }) } Some(&Verb::LineTo) => { let from = EndpointId(self.current); self.current += self.endpoint_stride; let to = EndpointId(self.current); self.evt += 1; Some(IdEvent::Line { from, to }) } Some(&Verb::QuadraticTo) => { let from = EndpointId(self.current); let base = self.current + self.endpoint_stride; let ctrl = ControlPointId(base); let to = EndpointId(base + 1); self.current = base + 1; self.evt += 1; Some(IdEvent::Quadratic { from, ctrl, to }) } Some(&Verb::CubicTo) => { let from = EndpointId(self.current); let base = self.current + self.endpoint_stride; let ctrl1 = ControlPointId(base); let ctrl2 = ControlPointId(base + 1); let to = EndpointId(base + 2); self.current = base + 2; self.evt += 1; Some(IdEvent::Cubic { from, ctrl1, ctrl2, to }) } Some(&Verb::Close) => { let last = EndpointId(self.current); let first = EndpointId(self.first); self.current += self.endpoint_stride; self.evt += 1; Some(IdEvent::End { last, first, close: true }) } Some(&Verb::End) => { let last = EndpointId(self.current); let first = EndpointId(self.first); self.current += self.endpoint_stride; self.evt += 1; Some(IdEvent::End { last, first, close: false }) } None => None, } } } #[inline] fn interpolated_attributes(num_attributes: usize, points: &[Point], endpoint: EndpointId) -> &[f32] { if num_attributes == 0 { return &[]; } let idx = endpoint.0 as usize + 1; assert!(idx + (num_attributes + 1) / 2 <= points.len()); unsafe { let ptr = &points[idx].x as *const f32; std::slice::from_raw_parts(ptr, num_attributes) } } fn reverse_path(path: PathSlice) -> Path { let mut builder = Path::builder_with_attributes(path.num_attributes()); let attrib_stride = (path.num_attributes() + 1) / 2; let points = &path.points[..]; // At each iteration, p points to the first point after the current verb. let mut p = points.len(); let mut need_close = false; for v in path.verbs.iter().rev().cloned() { match v { Verb::Close => { let idx = p - 1 - attrib_stride; need_close = true; builder.move_to(points[idx], path.attributes(EndpointId(idx as u32))); } Verb::End => { let idx = p - 1 - attrib_stride; need_close = false; builder.move_to(points[idx], path.attributes(EndpointId(idx as u32))); } Verb::Begin => { if need_close { need_close = false; builder.close(); } } Verb::LineTo => { let idx = p - 2 - attrib_stride * 2; builder.line_to(points[idx], path.attributes(EndpointId(idx as u32))); } Verb::QuadraticTo => { let ctrl_idx = p - attrib_stride - 2; let to_idx = ctrl_idx - attrib_stride - 1; builder.quadratic_bezier_to(points[ctrl_idx], points[to_idx], path.attributes(EndpointId(to_idx as u32))); } Verb::CubicTo => { let ctrl1_idx = p - attrib_stride - 2; let ctrl2_idx = ctrl1_idx - 1; let to_idx = ctrl2_idx - attrib_stride - 1; builder.cubic_bezier_to(points[ctrl1_idx], points[ctrl2_idx], points[to_idx], path.attributes(EndpointId(to_idx as u32))); } } p -= n_stored_points(v, attrib_stride); } builder.build() } fn n_stored_points(verb: Verb, attrib_stride: usize) -> usize { match verb { Verb::Begin => attrib_stride + 1, Verb::LineTo => attrib_stride + 1, Verb::QuadraticTo => attrib_stride + 2, Verb::CubicTo => attrib_stride + 3, Verb::Close => 0, Verb::End => 0, } } #[test] fn test_reverse_path() { let mut builder = Path::builder_with_attributes(1); builder.move_to(point(0.0, 0.0), &[1.0]); builder.line_to(point(1.0, 0.0), &[2.0]); builder.line_to(point(1.0, 1.0), &[3.0]); builder.line_to(point(0.0, 1.0), &[4.0]); builder.move_to(point(10.0, 0.0), &[5.0]); builder.line_to(point(11.0, 0.0), &[6.0]); builder.line_to(point(11.0, 1.0), &[7.0]); builder.line_to(point(10.0, 1.0), &[8.0]); builder.close(); builder.move_to(point(20.0, 0.0), &[9.0]); builder.quadratic_bezier_to(point(21.0, 0.0), point(21.0, 1.0), &[10.0]); let p1 = builder.build(); let p2 = p1.reversed(); let mut it = p2.iter_with_attributes(); // Using a function that explicits the argument types works around type inference issue. fn check<'l>( a: Option>, b: Option>, ) -> bool { if a != b { println!("left: {:?}", a); println!("right: {:?}", b); } a == b } assert!(check(it.next(), Some(Event::Begin { at: (point(21.0, 1.0), &[10.0]) }))); assert!(check(it.next(), Some(Event::Quadratic { from: (point(21.0, 1.0), &[10.0]), ctrl: point(21.0, 0.0), to: (point(20.0, 0.0), &[9.0]), }))); assert!(check(it.next(), Some(Event::End { last: (point(20.0, 0.0), &[9.0]), first: (point(21.0, 1.0), &[10.0]), close: false }))); assert!(check(it.next(), Some(Event::Begin { at: (point(10.0, 1.0), &[8.0]) }))); assert!(check(it.next(), Some(Event::Line { from: (point(10.0, 1.0), &[8.0]), to: (point(11.0, 1.0), &[7.0]) }))); assert!(check(it.next(), Some(Event::Line { from: (point(11.0, 1.0), &[7.0]), to: (point(11.0, 0.0), &[6.0]) }))); assert!(check(it.next(), Some(Event::Line { from: (point(11.0, 0.0), &[6.0]), to: (point(10.0, 0.0), &[5.0]) }))); assert!(check(it.next(), Some(Event::End { last: (point(10.0, 0.0), &[5.0]), first: (point(10.0, 1.0), &[8.0]), close: true }))); assert!(check(it.next(), Some(Event::Begin { at: (point(0.0, 1.0), &[4.0]) }))); assert!(check(it.next(), Some(Event::Line { from: (point(0.0, 1.0), &[4.0]), to: (point(1.0, 1.0), &[3.0]) }))); assert!(check(it.next(), Some(Event::Line { from: (point(1.0, 1.0), &[3.0]), to: (point(1.0, 0.0), &[2.0]) }))); assert!(check(it.next(), Some(Event::Line { from: (point(1.0, 0.0), &[2.0]), to: (point(0.0, 0.0), &[1.0]) }))); assert!(check(it.next(), Some(Event::End { last: (point(0.0, 0.0), &[1.0]), first: (point(0.0, 1.0), &[4.0]), close: false }))); assert!(check(it.next(), None)); } #[test] fn test_reverse_path_no_close() { let mut builder = Path::builder(); builder.move_to(point(0.0, 0.0)); builder.line_to(point(1.0, 0.0)); builder.line_to(point(1.0, 1.0)); let p1 = builder.build(); let p2 = p1.reversed(); let mut it = p2.iter(); assert_eq!(it.next(), Some(PathEvent::Begin { at: point(1.0, 1.0) })); assert_eq!(it.next(), Some(PathEvent::Line { from: point(1.0, 1.0), to: point(1.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::Line { from: point(1.0, 0.0), to: point(0.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::End { last: point(0.0, 0.0), first: point(1.0, 1.0), close: false })); assert_eq!(it.next(), None); } #[test] fn test_reverse_empty_path() { let p1 = Path::builder().build(); let p2 = p1.reversed(); assert_eq!(p2.iter().next(), None); } #[test] fn test_reverse_single_moveto() { let mut builder = Path::builder(); builder.move_to(point(0.0, 0.0)); let p1 = builder.build(); let p2 = p1.reversed(); let mut it = p2.iter(); assert_eq!(it.next(), Some(PathEvent::Begin { at: point(0.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::End { last: point(0.0, 0.0), first: point(0.0, 0.0), close: false })); assert_eq!(it.next(), None); } #[test] fn test_path_builder_1() { let mut p = BuilderWithAttributes::new(1); p.move_to(point(0.0, 0.0), &[0.0]); p.line_to(point(1.0, 0.0), &[1.0]); p.line_to(point(2.0, 0.0), &[2.0]); p.line_to(point(3.0, 0.0), &[3.0]); p.quadratic_bezier_to(point(4.0, 0.0), point(4.0, 1.0), &[4.0]); p.cubic_bezier_to(point(5.0, 0.0), point(5.0, 1.0), point(5.0, 2.0), &[5.0]); p.close(); p.move_to(point(10.0, 0.0), &[6.0]); p.line_to(point(11.0, 0.0), &[7.0]); p.line_to(point(12.0, 0.0), &[8.0]); p.line_to(point(13.0, 0.0), &[9.0]); p.quadratic_bezier_to(point(14.0, 0.0), point(14.0, 1.0), &[10.0]); p.cubic_bezier_to(point(15.0, 0.0), point(15.0, 1.0), point(15.0, 2.0), &[11.0]); p.close(); p.close(); p.move_to(point(1.0, 1.0), &[12.0]); p.move_to(point(2.0, 2.0), &[13.0]); p.move_to(point(3.0, 3.0), &[14.0]); p.line_to(point(4.0, 4.0), &[15.0]); let path = p.build(); let mut it = path.iter_with_attributes(); assert_eq!(it.next(), Some(Event::Begin { at: (point(0.0, 0.0), &[0.0][..]) })); assert_eq!(it.next(), Some(Event::Line { from: (point(0.0, 0.0), &[0.0][..]), to: (point(1.0, 0.0), &[1.0][..]) })); assert_eq!(it.next(), Some(Event::Line { from: (point(1.0, 0.0), &[1.0][..]), to: (point(2.0, 0.0), &[2.0][..]) })); assert_eq!(it.next(), Some(Event::Line { from: (point(2.0, 0.0), &[2.0][..]), to: (point(3.0, 0.0), &[3.0][..]) })); assert_eq!(it.next(), Some(Event::Quadratic { from: (point(3.0, 0.0), &[3.0][..]), ctrl: point(4.0, 0.0), to: (point(4.0, 1.0), &[4.0][..]) })); assert_eq!( it.next(), Some(Event::Cubic { from: (point(4.0, 1.0), &[4.0][..]), ctrl1: point(5.0, 0.0), ctrl2: point(5.0, 1.0), to: (point(5.0, 2.0), &[5.0][..]), }) ); assert_eq!(it.next(), Some(Event::End { last: (point(5.0, 2.0), &[5.0][..]), first: (point(0.0, 0.0), &[0.0][..]), close: true })); assert_eq!(it.next(), Some(Event::Begin { at: (point(10.0, 0.0), &[6.0][..]) })); assert_eq!(it.next(), Some(Event::Line { from: (point(10.0, 0.0), &[6.0][..]), to: (point(11.0, 0.0), &[7.0][..]) })); assert_eq!(it.next(), Some(Event::Line { from: (point(11.0, 0.0), &[7.0][..]), to: (point(12.0, 0.0), &[8.0][..]) })); assert_eq!(it.next(), Some(Event::Line { from: (point(12.0, 0.0), &[8.0][..]), to: (point(13.0, 0.0), &[9.0][..]) })); assert_eq!(it.next(), Some(Event::Quadratic { from: (point(13.0, 0.0), &[9.0][..]), ctrl: point(14.0, 0.0), to: (point(14.0, 1.0), &[10.0][..]), })); assert_eq!( it.next(), Some(Event::Cubic { from: (point(14.0, 1.0), &[10.0][..]), ctrl1: point(15.0, 0.0), ctrl2: point(15.0, 1.0), to: (point(15.0, 2.0), &[11.0][..]), }) ); assert_eq!(it.next(), Some(Event::End { last: (point(15.0, 2.0), &[11.0][..]), first: (point(10.0, 0.0), &[6.0][..]), close: true })); // Not clear that this is the most useful behavior. // Closing when there is no path should probably be dropped. assert_eq!(it.next(), Some(Event::End { last: (point(10.0, 0.0), &[6.0][..]), first: (point(10.0, 0.0), &[6.0][..]), close: true, })); assert_eq!(it.next(), Some(Event::Begin { at: (point(1.0, 1.0), &[12.0][..]) })); assert_eq!(it.next(), Some(Event::End { last: (point(1.0, 1.0), &[12.0][..]), first: (point(1.0, 1.0), &[12.0][..]), close: false })); assert_eq!(it.next(), Some(Event::Begin { at: (point(2.0, 2.0), &[13.0][..]) })); assert_eq!(it.next(), Some(Event::End { last: (point(2.0, 2.0), &[13.0][..]), first: (point(2.0, 2.0), &[13.0][..]), close: false })); assert_eq!(it.next(), Some(Event::Begin { at: (point(3.0, 3.0), &[14.0][..]) })); assert_eq!(it.next(), Some(Event::Line { from: (point(3.0, 3.0), &[14.0][..]), to: (point(4.0, 4.0), &[15.0][..]) })); assert_eq!(it.next(), Some(Event::End { last: (point(4.0, 4.0), &[15.0][..]), first: (point(3.0, 3.0), &[14.0][..]), close: false })); assert_eq!(it.next(), None); assert_eq!(it.next(), None); assert_eq!(it.next(), None); } #[test] fn test_path_builder_empty() { let path = Path::builder_with_attributes(5).build(); let mut it = path.iter(); assert_eq!(it.next(), None); assert_eq!(it.next(), None); } #[test] fn test_path_builder_empty_move_to() { let mut p = Path::builder_with_attributes(1); p.move_to(point(1.0, 2.0), &[0.0]); p.move_to(point(3.0, 4.0), &[1.0]); p.move_to(point(5.0, 6.0), &[2.0]); let path = p.build(); let mut it = path.iter(); assert_eq!(it.next(), Some(PathEvent::Begin { at: point(1.0, 2.0) })); assert_eq!(it.next(), Some(PathEvent::End { last: point(1.0, 2.0), first: point(1.0, 2.0), close: false, })); assert_eq!(it.next(), Some(PathEvent::Begin { at: point(3.0, 4.0) })); assert_eq!(it.next(), Some(PathEvent::End { last: point(3.0, 4.0), first: point(3.0, 4.0), close: false, })); assert_eq!(it.next(), Some(PathEvent::Begin { at: point(5.0, 6.0) })); assert_eq!(it.next(), Some(PathEvent::End { last: point(5.0, 6.0), first: point(5.0, 6.0), close: false, })); assert_eq!(it.next(), None); assert_eq!(it.next(), None); } #[test] fn test_path_builder_line_to_after_close() { let mut p = Path::builder(); p.line_to(point(1.0, 0.0)); p.close(); p.line_to(point(2.0, 0.0)); let path = p.build(); let mut it = path.iter(); assert_eq!(it.next(), Some(PathEvent::Begin { at: point(0.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::Line { from: point(0.0, 0.0), to: point(1.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::End { last: point(1.0, 0.0), first: point(0.0, 0.0), close: true })); assert_eq!(it.next(), Some(PathEvent::Begin { at: point(0.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::Line { from: point(0.0, 0.0), to: point(2.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::End { last: point(2.0, 0.0), first: point(0.0, 0.0), close: false })); assert_eq!(it.next(), None); } #[test] fn test_merge_paths() { let mut builder = Path::builder(); builder.move_to(point(0.0, 0.0)); builder.line_to(point(5.0, 0.0)); builder.line_to(point(5.0, 5.0)); builder.close(); let path1 = builder.build(); let mut builder = Path::builder(); builder.move_to(point(1.0, 1.0)); builder.line_to(point(4.0, 0.0)); builder.line_to(point(4.0, 4.0)); builder.close(); let path2 = builder.build(); let path = path1.merge(&path2); let mut it = path.iter(); assert_eq!(it.next(), Some(PathEvent::Begin { at: point(0.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::Line { from: point(0.0, 0.0), to: point(5.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::Line { from: point(5.0, 0.0), to: point(5.0, 5.0) })); assert_eq!(it.next(), Some(PathEvent::End { last: point(5.0, 5.0), first: point(0.0, 0.0), close: true })); assert_eq!(it.next(), Some(PathEvent::Begin { at: point(1.0, 1.0) })); assert_eq!(it.next(), Some(PathEvent::Line { from: point(1.0, 1.0), to: point(4.0, 0.0) })); assert_eq!(it.next(), Some(PathEvent::Line { from: point(4.0, 0.0), to: point(4.0, 4.0) })); assert_eq!(it.next(), Some(PathEvent::End { last: point(4.0, 4.0), first: point(1.0, 1.0), close: true })); assert_eq!(it.next(), None); } lyon_path-0.15.1/src/path_state.rs010064400017500001750000000142221357773320200153170ustar0000000000000000use crate::math::{Point, Vector, point, vector, Angle}; use crate::geom::{Arc, ArcFlags}; use crate::builder::{FlatPathBuilder, PathBuilder, SvgBuilder, PolygonBuilder}; #[derive(Copy, Clone, Debug, PartialEq)] enum LastCtrl { Cubic(Point), Quad(Point), None, } /// Represents the current state of a path while it is being built. #[derive(Copy, Clone, Debug, PartialEq)] pub struct PathState { /// The current point. current: Point, /// The first point of the current sub-path. first: Point, /// The last control point. last_ctrl: LastCtrl, } impl PathState { pub fn new() -> Self { PathState { current: point(0.0, 0.0), first: point(0.0, 0.0), last_ctrl: LastCtrl::None, } } /// The current position. pub fn current_position(&self) -> Point { self.current } /// The position at the start of the current sub-path. pub fn start_position(&self) -> Point { self.first } pub fn move_to(&mut self, to: Point) { self.last_ctrl = LastCtrl::None; self.current = to; self.first = to; } pub fn line_to(&mut self, to: Point) { self.last_ctrl = LastCtrl::None; self.current = to; } pub fn close(&mut self) { self.last_ctrl = LastCtrl::None; self.current = self.first; } pub fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) { self.last_ctrl = LastCtrl::Quad(ctrl); self.current = to; } pub fn cubic_bezier_to(&mut self, _ctrl1: Point, ctrl2: Point, to: Point) { self.last_ctrl = LastCtrl::Cubic(ctrl2); self.current = to; } pub fn arc(&mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle) { let start_angle = (self.current - center).angle_from_x_axis() - x_rotation; let arc = Arc { center, radii, start_angle, sweep_angle, x_rotation, }; let to = arc.to(); self.last_ctrl = LastCtrl::None; self.current = to; } pub fn get_smooth_cubic_ctrl(&self) -> Point { match self.last_ctrl { LastCtrl::Cubic(ctrl) => self.current + (self.current - ctrl), _ => self.current, } } pub fn get_smooth_quadratic_ctrl(&self) -> Point { match self.last_ctrl { LastCtrl::Quad(ctrl) => self.current + (self.current - ctrl), _ => self.current, } } pub fn relative_to_absolute(&self, v: Vector) -> Point { self.current + v } } impl FlatPathBuilder for PathState { fn move_to(&mut self, to: Point) { self.move_to(to); } fn line_to(&mut self, to: Point) { self.line_to(to); } fn close(&mut self) { self.close(); } fn current_position(&self) -> Point { self.current } } impl PathBuilder for PathState { fn quadratic_bezier_to(&mut self, ctrl: Point, to: Point) { self.quadratic_bezier_to(ctrl, to); } fn cubic_bezier_to(&mut self, ctrl1: Point, ctrl2: Point, to: Point) { self.cubic_bezier_to(ctrl1, ctrl2, to); } fn arc(&mut self, center: Point, radii: Vector, sweep_angle: Angle, x_rotation: Angle) { self.arc(center, radii, sweep_angle, x_rotation); } } impl SvgBuilder for PathState { fn relative_move_to(&mut self, to: Vector) { let to = self.relative_to_absolute(to); self.move_to(to); } fn relative_line_to(&mut self, to: Vector) { let to = self.relative_to_absolute(to); self.line_to(to); } fn relative_quadratic_bezier_to(&mut self, ctrl: Vector, to: Vector) { let to = self.relative_to_absolute(to); let ctrl = self.relative_to_absolute(ctrl); self.last_ctrl = LastCtrl::Quad(ctrl); self.current = to; } fn relative_cubic_bezier_to(&mut self, _ctrl1: Vector, ctrl2: Vector, to: Vector) { let to = self.relative_to_absolute(to); let ctrl2 = self.relative_to_absolute(ctrl2); self.last_ctrl = LastCtrl::Cubic(ctrl2); self.current = to; } fn smooth_cubic_bezier_to(&mut self, ctrl2: Point, to: Point) { self.last_ctrl = LastCtrl::Cubic(ctrl2); self.current = to; } fn smooth_relative_cubic_bezier_to(&mut self, ctrl2: Vector, to: Vector) { self.last_ctrl = LastCtrl::Cubic(self.relative_to_absolute(ctrl2)); self.current = self.relative_to_absolute(to); } fn smooth_quadratic_bezier_to(&mut self, to: Point) { let last_ctrl = match self.last_ctrl { LastCtrl::Quad(ctrl) => ctrl, _ => self.current, }; self.last_ctrl = LastCtrl::Quad(to + (to - last_ctrl)); self.current = to; } fn smooth_relative_quadratic_bezier_to(&mut self, to: Vector) { let to = self.relative_to_absolute(to); let last_ctrl = match self.last_ctrl { LastCtrl::Quad(ctrl) => ctrl, _ => self.current, }; self.last_ctrl = LastCtrl::Quad(to + (to - last_ctrl)); self.current = to; } fn horizontal_line_to(&mut self, x: f32) { let to = point(x, self.current.y); self.line_to(to); } fn relative_horizontal_line_to(&mut self, dx: f32) { let to = self.current + vector(dx, 0.0); self.line_to(to); } fn vertical_line_to(&mut self, y: f32) { let to = point(self.current.x, y); self.line_to(to); } fn relative_vertical_line_to(&mut self, dy: f32) { let to = self.current + vector(0.0, dy); self.line_to(to); } fn arc_to(&mut self, _radii: Vector, _x_rotation: Angle, _flags: ArcFlags, to: Point) { self.last_ctrl = LastCtrl::None; self.current = to; } fn relative_arc_to( &mut self, _radii: Vector, _x_rotation: Angle, _flags: ArcFlags, to: Vector, ) { let to = self.relative_to_absolute(to); self.last_ctrl = LastCtrl::None; self.current = to; } } impl PolygonBuilder for PathState { fn polygon(&mut self, points: &[Point]) { self.last_ctrl = LastCtrl::None; if let Some(p) = points.first() { self.current = *p; } } } lyon_path-0.15.1/src/polygon.rs010064400017500001750000000176401360142424100146450ustar0000000000000000//! Specific path types for polygons. use crate::{EndpointId, ControlPointId, EventId, Event, IdEvent, Position, PositionStore}; use crate::math::Point; /// A view over a sequence of endpoint IDs forming a polygon. pub struct IdPolygonSlice<'l> { pub points: &'l[EndpointId], pub closed: bool, } impl<'l> IdPolygonSlice<'l> { // Returns an iterator over the endpoint IDs of the polygon. pub fn iter(&self) -> IdPolygonIter<'l> { IdPolygonIter { points: self.points.iter(), idx: 0, prev: None, first: EndpointId(0), closed: self.closed, } } /// Returns the event for a given event ID. pub fn event(&self, id: EventId) -> IdEvent { let idx = id.0 as usize; if idx == 0 { IdEvent::Begin { at: self.points[0] } } else if idx as usize == self.points.len() { IdEvent::End { last: self.points[self.points.len() - 1], first: self.points[0], close: self.closed, } } else { IdEvent::Line { from: self.points[idx - 1], to: self.points[idx], } } } } // An iterator of `Event`. pub struct IdPolygonIter<'l> { points: std::slice::Iter<'l, EndpointId>, idx: u32, prev: Option, first: EndpointId, closed: bool, } impl<'l> Iterator for IdPolygonIter<'l> { type Item = IdEvent; fn next(&mut self) -> Option { match (self.prev, self.points.next()) { (Some(from), Some(to)) => { self.prev = Some(*to); self.idx += 1; Some(IdEvent::Line { from, to: *to }) } (None, Some(at)) => { self.prev = Some(*at); self.first = *at; self.idx += 1; Some(IdEvent::Begin { at: *at }) } (Some(last), None) => { self.prev = None; Some(IdEvent::End { last, first: self.first, close: self.closed, }) } (None, None) => None, } } } /// A view over a sequence of endpoints forming a polygon. pub struct PolygonSlice<'l, T> { pub points: &'l[T], pub closed: bool, } impl<'l, T> PolygonSlice<'l, T> { pub fn iter(&self) -> PolygonIter<'l, T> { PolygonIter { points: self.points.iter(), prev: None, first: None, closed: self.closed, } } pub fn id_iter(&self) -> PolygonIdIter { PolygonIdIter::new(0..(self.points.len() as u32), self.closed) } /// Returns the event for a given event ID. pub fn event(&self, id: EventId) -> Event<&T, ()> { let idx = id.0 as usize; if idx == 0 { Event::Begin { at: &self.points[0] } } else if idx as usize == self.points.len() - 1 { Event::End { last: &self.points[self.points.len() - 1], first: &self.points[0], close: self.closed, } } else { Event::Line { from: &self.points[idx - 1], to: &self.points[idx], } } } } impl<'l, T> std::ops::Index for PolygonSlice<'l, T> { type Output = T; fn index(&self, id: EndpointId) -> &T { &self.points[id.to_usize()] } } // An iterator of `Event<&Endpoint, ()>`. pub struct PolygonIter<'l, T> { points: std::slice::Iter<'l, T>, prev: Option<&'l T>, first: Option<&'l T>, closed: bool, } impl<'l, T> Iterator for PolygonIter<'l, T> { type Item = Event<&'l T, ()>; fn next(&mut self) -> Option> { match (self.prev, self.points.next()) { (Some(from), Some(to)) => { self.prev = Some(to); Some(Event::Line { from, to }) } (None, Some(at)) => { self.prev = Some(at); self.first = Some(at); Some(Event::Begin { at }) } (Some(last), None) => { self.prev = None; Some(Event::End { last, first: self.first.unwrap(), close: self.closed, }) } (None, None) => None, } } } #[derive(Clone)] // An iterator of `IdEvent` for `PolygonSlice`. pub struct PolygonIdIter { idx: u32, start: u32, end: u32, closed: bool, } impl PolygonIdIter { #[inline] pub fn new(range: std::ops::Range, closed: bool) -> Self { PolygonIdIter { idx: range.start, start: range.start, end: range.end, closed, } } } impl Iterator for PolygonIdIter { type Item = IdEvent; fn next(&mut self) -> Option { let idx = self.idx; self.idx += 1; return if idx == self.start { Some(IdEvent::Begin { at: EndpointId(self.start) }) } else if idx < self.end { Some(IdEvent::Line { from: EndpointId(idx - 1), to: EndpointId(idx) }) } else if idx == self.end { Some(IdEvent::End { last: EndpointId(self.end - 1), first: EndpointId(self.start), close: self.closed }) } else { None }; } } impl<'l, Endpoint> PositionStore for PolygonSlice<'l, Endpoint> where Endpoint: Position, { fn get_endpoint(&self, id: EndpointId) -> Point { self.points[id.to_usize()].position() } fn get_control_point(&self, _: ControlPointId) -> Point { panic!("Polygons do not have control points."); } } #[test] fn event_ids() { let poly = IdPolygonSlice { points: &[EndpointId(0), EndpointId(1), EndpointId(2), EndpointId(3)], closed: true, }; assert_eq!(poly.event(EventId(0)), IdEvent::Begin { at: EndpointId(0) }); assert_eq!(poly.event(EventId(1)), IdEvent::Line { from: EndpointId(0), to: EndpointId(1) }); assert_eq!(poly.event(EventId(2)), IdEvent::Line { from: EndpointId(1), to: EndpointId(2) }); assert_eq!(poly.event(EventId(3)), IdEvent::Line { from: EndpointId(2), to: EndpointId(3) }); assert_eq!(poly.event(EventId(4)), IdEvent::End { last: EndpointId(3), first: EndpointId(0), close: true }); let mut iter = poly.iter(); assert_eq!(iter.next(), Some(IdEvent::Begin { at: EndpointId(0) })); assert_eq!(iter.next(), Some(IdEvent::Line { from: EndpointId(0), to: EndpointId(1) })); assert_eq!(iter.next(), Some(IdEvent::Line { from: EndpointId(1), to: EndpointId(2) })); assert_eq!(iter.next(), Some(IdEvent::Line { from: EndpointId(2), to: EndpointId(3) })); assert_eq!(iter.next(), Some(IdEvent::End { last: EndpointId(3), first: EndpointId(0), close: true })); assert_eq!(iter.next(), None); assert_eq!(iter.next(), None); } #[test] fn polygon_slice_id_ite() { let points: &[u32] = &[0, 1, 2, 3, 4, 5, 6]; let polygon = PolygonSlice { points, closed: true, }; let mut it = polygon.id_iter(); assert_eq!(it.next(), Some(IdEvent::Begin { at: EndpointId(0) })); assert_eq!(it.next(), Some(IdEvent::Line { from: EndpointId(0), to: EndpointId(1) })); assert_eq!(it.next(), Some(IdEvent::Line { from: EndpointId(1), to: EndpointId(2) })); assert_eq!(it.next(), Some(IdEvent::Line { from: EndpointId(2), to: EndpointId(3) })); assert_eq!(it.next(), Some(IdEvent::Line { from: EndpointId(3), to: EndpointId(4) })); assert_eq!(it.next(), Some(IdEvent::Line { from: EndpointId(4), to: EndpointId(5) })); assert_eq!(it.next(), Some(IdEvent::Line { from: EndpointId(5), to: EndpointId(6) })); assert_eq!(it.next(), Some(IdEvent::End { last: EndpointId(6), first: EndpointId(0), close: true })); assert_eq!(it.next(), None); assert_eq!(it.next(), None); assert_eq!(it.next(), None); } lyon_path-0.15.1/.cargo_vcs_info.json0000644000000001121360142427200132060ustar00{ "git": { "sha1": "32111821249aecda1c340e773a5acd905a833e96" } }