Bezier-rs: Convert to_svg used in subpaths to match style used in beziers (#854)

Converted subpath::to_svg to Bezier style
This commit is contained in:
Rob Nadal 2022-11-14 22:37:06 -08:00 committed by Keavon Chambers
parent 9c87658ae4
commit 00c8fa83c2
5 changed files with 65 additions and 145 deletions

View file

@ -3,9 +3,7 @@
mod bezier;
mod consts;
mod subpath;
mod svg;
mod utils;
pub use bezier::*;
pub use subpath::*;
pub use svg::*;

View file

@ -1,6 +1,6 @@
use super::*;
use crate::consts::*;
use crate::ToSVGOptions;
use std::fmt::Write;
/// Functionality relating to core `Subpath` operations, such as constructors and `iter`.
impl Subpath {
@ -45,45 +45,59 @@ impl Subpath {
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();
}
/// Appends to the `svg` mutable string with an SVG shape representation of the curve.
pub fn curve_to_svg(&self, svg: &mut String, attributes: String) {
let curve_start_argument = format!("{SVG_ARG_MOVE}{} {}", self[0].anchor.x, self[0].anchor.y);
let mut curve_arguments: Vec<String> = 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
let _ = write!(svg, r#"<path d="{} {}" {attributes}/>"#, curve_start_argument, curve_arguments.join(" "));
}
/// Appends to the `svg` mutable string with an SVG shape representation of the handle lines.
pub fn handle_lines_to_svg(&self, svg: &mut String, attributes: String) {
let handle_lines: Vec<String> = self.iter().filter_map(|bezier| bezier.svg_handle_line_argument()).collect();
let _ = write!(svg, r#"<path d="{}" {attributes}/>"#, handle_lines.join(" "));
}
/// Appends to the `svg` mutable string with an SVG shape representation of the anchors.
pub fn anchors_to_svg(&self, svg: &mut String, attributes: String) {
let anchors = self
.manipulator_groups
.iter()
.map(|point| format!(r#"<circle cx="{}" cy="{}" {}/>"#, point.anchor.x, point.anchor.y, anchor_arguments))
.map(|point| format!(r#"<circle cx="{}" cy="{}" {attributes}/>"#, point.anchor.x, point.anchor.y))
.collect::<Vec<String>>();
let _ = write!(svg, "{}", anchors.concat());
}
let handle_point_arguments = options.formatted_handle_point_arguments();
let handle_circles: Vec<String> = self
/// Appends to the `svg` mutable string with an SVG shape representation of the handles.
pub fn handles_to_svg(&self, svg: &mut String, attributes: String) {
let handles = self
.manipulator_groups
.iter()
.flat_map(|group| [group.in_handle, group.out_handle])
.flatten()
.map(|handle| format!(r#"<circle cx="{}" cy="{}" {}/>"#, handle.x, handle.y, handle_point_arguments))
.collect();
.map(|handle| format!(r#"<circle cx="{}" cy="{}" {attributes}/>"#, handle.x, handle.y))
.collect::<Vec<String>>();
let _ = write!(svg, "{}", handles.concat());
}
let handle_pieces: Vec<String> = self.iter().filter_map(|bezier| bezier.svg_handle_line_argument()).collect();
format!(
r#"<path d="{} {}" {}/><path d="{}" {}/>{}{}"#,
curve_start_argument,
curve_arguments.join(" "),
options.formatted_curve_arguments(),
handle_pieces.join(" "),
options.formatted_handle_line_arguments(),
handle_circles.join(""),
anchor_circles.join(""),
)
/// Returns an SVG representation of the `Subpath`.
/// Appends to the `svg` mutable string with an SVG shape representation that includes the curve, the handle lines, the anchors, and the handles.
pub fn to_svg(&self, svg: &mut String, curve_attributes: String, anchor_attributes: String, handle_attributes: String, handle_line_attributes: String) {
if !curve_attributes.is_empty() {
self.curve_to_svg(svg, curve_attributes);
}
if !handle_line_attributes.is_empty() {
self.handle_lines_to_svg(svg, handle_line_attributes);
}
if !anchor_attributes.is_empty() {
self.anchors_to_svg(svg, anchor_attributes);
}
if !handle_attributes.is_empty() {
self.handles_to_svg(svg, handle_attributes);
}
}
}

View file

@ -1,74 +0,0 @@
/// Structure to represent optional parameters that can be passed to the `into_svg` function.
pub struct ToSVGOptions {
/// Color of the line segments along the `Subpath`. Defaulted to `black`.
pub curve_stroke_color: String,
/// Width of the line segments along the `Subpath`. Defaulted to `2.`.
pub curve_stroke_width: f64,
/// Stroke color outlining circles marking anchors on the `Subpath`. Defaulted to `black`.
pub anchor_stroke_color: String,
/// Stroke width outlining circles marking anchors on the `Subpath`. Defaulted to `2.`.
pub anchor_stroke_width: f64,
/// Radius of the circles marking anchors on the `Subpath`. Defaulted to `4.`.
pub anchor_radius: f64,
/// Fill color of the circles marking anchors on the `Subpath`. Defaulted to `white`.
pub anchor_fill: String,
/// Color of the line segments connecting anchors to handle points. Defaulted to `gray`.
pub handle_line_stroke_color: String,
/// Width of the line segments connecting anchors to handle points. Defaulted to `1.`.
pub handle_line_stroke_width: f64,
/// Stroke color outlining circles marking the handles of `Subpath`. Defaulted to `gray`.
pub handle_point_stroke_color: String,
/// Stroke color outlining circles marking the handles of `Subpath`. Defaulted to `1.5`.
pub handle_point_stroke_width: f64,
/// Radius of the circles marking the handles of `Subpath`. Defaulted to `3.`.
pub handle_point_radius: f64,
/// Fill color of the circles marking the handles of `Subpath`. Defaulted to `white`.
pub handle_point_fill: String,
}
impl ToSVGOptions {
/// Combine and format curve styling options for an SVG path.
pub fn formatted_curve_arguments(&self) -> String {
format!(r#"stroke="{}" stroke-width="{}" fill="none""#, self.curve_stroke_color, self.curve_stroke_width)
}
/// Combine and format anchor styling options an SVG circle.
pub fn formatted_anchor_arguments(&self) -> String {
format!(
r#"r="{}", stroke="{}" stroke-width="{}" fill="{}""#,
self.anchor_radius, self.anchor_stroke_color, self.anchor_stroke_width, self.anchor_fill
)
}
/// Combine and format handle point styling options for an SVG circle.
pub fn formatted_handle_point_arguments(&self) -> String {
format!(
r#"r="{}", stroke="{}" stroke-width="{}" fill="{}""#,
self.handle_point_radius, self.handle_point_stroke_color, self.handle_point_stroke_width, self.handle_point_fill
)
}
/// Combine and format handle line styling options an SVG path.
pub fn formatted_handle_line_arguments(&self) -> String {
format!(r#"stroke="{}" stroke-width="{}" fill="none""#, self.handle_line_stroke_color, self.handle_line_stroke_width)
}
}
impl Default for ToSVGOptions {
fn default() -> Self {
ToSVGOptions {
curve_stroke_color: String::from("black"),
curve_stroke_width: 2.,
anchor_stroke_color: String::from("black"),
anchor_stroke_width: 2.,
anchor_radius: 4.,
anchor_fill: String::from("white"),
handle_line_stroke_color: String::from("gray"),
handle_line_stroke_width: 1.,
handle_point_stroke_color: String::from("gray"),
handle_point_stroke_width: 1.5,
handle_point_radius: 3.,
handle_point_fill: String::from("white"),
}
}
}