use super::*; use crate::consts::*; use crate::ToSVGOptions; /// Functionality relating to core `Subpath` operations, such as constructors and `iter`. impl Subpath { /// Create a new `Subpath` using a list of [ManipulatorGroup]s. /// A `Subpath` with less than 2 [ManipulatorGroup]s may not be closed. pub fn new(manipulator_groups: Vec, closed: bool) -> Self { assert!(!closed || manipulator_groups.len() > 1, "A closed Subpath must contain more than 1 ManipulatorGroup."); Self { manipulator_groups, closed } } /// Create a `Subpath` consisting of 2 manipulator groups from a `Bezier`. pub fn from_bezier(bezier: Bezier) -> Self { Subpath::new( vec![ ManipulatorGroup { anchor: bezier.start(), in_handle: None, out_handle: bezier.handle_start(), }, ManipulatorGroup { anchor: bezier.end(), in_handle: bezier.handle_end(), out_handle: None, }, ], false, ) } /// Returns true if the `Subpath` contains no [ManipulatorGroup]. pub fn is_empty(&self) -> bool { self.manipulator_groups.is_empty() } /// Returns the number of [ManipulatorGroup]s contained within the `Subpath`. pub fn len(&self) -> usize { self.manipulator_groups.len() } /// Returns an iterator of the [Bezier]s along the `Subpath`. pub fn iter(&self) -> SubpathIter { SubpathIter { sub_path: self, index: 0 } } /// Returns an SVG representation of the `Subpath`. pub fn to_svg(&self, options: ToSVGOptions) -> String { if self.is_empty() { return String::new(); } let curve_start_argument = format!("{SVG_ARG_MOVE}{} {}", self[0].anchor.x, self[0].anchor.y); let mut curve_arguments: Vec = self.iter().map(|bezier| bezier.svg_curve_argument()).collect(); if self.closed { curve_arguments.push(String::from(SVG_ARG_CLOSED)); } let anchor_arguments = options.formatted_anchor_arguments(); let anchor_circles = self .manipulator_groups .iter() .map(|point| format!(r#""#, point.anchor.x, point.anchor.y, anchor_arguments)) .collect::>(); let handle_point_arguments = options.formatted_handle_point_arguments(); let handle_circles: Vec = self .manipulator_groups .iter() .flat_map(|group| [group.in_handle, group.out_handle]) .flatten() .map(|handle| format!(r#""#, handle.x, handle.y, handle_point_arguments)) .collect(); let handle_pieces: Vec = self.iter().filter_map(|bezier| bezier.svg_handle_line_argument()).collect(); format!( r#"{}{}"#, curve_start_argument, curve_arguments.join(" "), options.formatted_curve_arguments(), handle_pieces.join(" "), options.formatted_handle_line_arguments(), handle_circles.join(""), anchor_circles.join(""), ) } }