Bezier-rs: Added curve outline functions (#789)

* Implement offset and reverse

Co-authored-by: Rob Nadal <robnadal44@gmail.com>

* Initial work on graduated outline

Co-authored-by: Rob Nadal <robnadal44@gmail.com>

* Handle linear case for graduated scale

* Added skewed outline, fixed graduated scale hourglass bug

* Removed test code

* Update comments

* Fix linting issue

* Improve comments

* Comment fixes

Co-authored-by: Hannah Li <hannahli2010@gmail.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Rob Nadal
2022-11-06 21:25:00 -08:00
committed by Keavon Chambers
parent a695584d36
commit 56060b8e5f
6 changed files with 321 additions and 5 deletions

View File

@@ -295,6 +295,86 @@ export default defineComponent({
},
},
},
{
name: "Outline",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.outline(options.distance),
exampleOptions: {
[BezierCurveType.Quadratic]: {
sliderOptions: [
{
variable: "distance",
min: 0,
max: 50,
step: 1,
default: 20,
},
],
},
},
},
{
name: "Graduated Outline",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.graduated_outline(options.start_distance, options.end_distance),
exampleOptions: {
[BezierCurveType.Quadratic]: {
sliderOptions: [
{
variable: "start_distance",
min: 0,
max: 50,
step: 1,
default: 30,
},
{
variable: "end_distance",
min: 0,
max: 50,
step: 1,
default: 30,
},
],
},
},
},
{
name: "Skewed Outline",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string =>
bezier.skewed_outline(options.distance1, options.distance2, options.distance3, options.distance4),
exampleOptions: {
[BezierCurveType.Quadratic]: {
sliderOptions: [
{
variable: "distance1",
min: 0,
max: 50,
step: 1,
default: 20,
},
{
variable: "distance2",
min: 0,
max: 50,
step: 1,
default: 10,
},
{
variable: "distance3",
min: 0,
max: 50,
step: 1,
default: 30,
},
{
variable: "distance4",
min: 0,
max: 50,
step: 1,
default: 5,
},
],
},
},
},
{
name: "Arcs",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.arcs(options.error, options.max_iterations, options.strategy),

View File

@@ -571,6 +571,42 @@ impl WasmBezier {
wrap_svg_tag(bezier_curves_svg)
}
pub fn outline(&self, distance: f64) -> String {
let outline_beziers = self.0.outline(distance);
if outline_beziers.is_empty() {
return String::new();
}
let outline_svg = draw_beziers(outline_beziers, CURVE_ATTRIBUTES.to_string().replace(BLACK, RED));
let bezier_svg = self.get_bezier_path();
wrap_svg_tag(format!("{bezier_svg}{outline_svg}"))
}
pub fn graduated_outline(&self, start_distance: f64, end_distance: f64) -> String {
let outline_beziers = self.0.graduated_outline(start_distance, end_distance);
if outline_beziers.is_empty() {
return String::new();
}
let outline_svg = draw_beziers(outline_beziers, CURVE_ATTRIBUTES.to_string().replace(BLACK, RED));
let bezier_svg = self.get_bezier_path();
wrap_svg_tag(format!("{bezier_svg}{outline_svg}"))
}
pub fn skewed_outline(&self, distance1: f64, distance2: f64, distance3: f64, distance4: f64) -> String {
let outline_beziers = self.0.skewed_outline(distance1, distance2, distance3, distance4);
if outline_beziers.is_empty() {
return String::new();
}
let outline_svg = draw_beziers(outline_beziers, CURVE_ATTRIBUTES.to_string().replace(BLACK, RED));
let bezier_svg = self.get_bezier_path();
wrap_svg_tag(format!("{bezier_svg}{outline_svg}"))
}
/// The wrapped return type is `Vec<CircleSector>`.
pub fn arcs(&self, error: f64, max_iterations: usize, maximize_arcs: WasmMaximizeArcs) -> String {
let original_curve_svg = self.get_bezier_path();

View File

@@ -1,3 +1,6 @@
use bezier_rs::Bezier;
use std::fmt::Write;
// SVG drawing constants
pub const SVG_OPEN_TAG: &str = r#"<svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px">"#;
pub const SVG_CLOSE_TAG: &str = "</svg>";
@@ -37,6 +40,19 @@ pub fn draw_line(start_x: f64, start_y: f64, end_x: f64, end_y: f64, stroke: &st
format!(r#"<line x1="{start_x}" y1="{start_y}" x2="{end_x}" y2="{end_y}" stroke="{stroke}" stroke-width="{stroke_width}"/>"#)
}
/// Helper function to draw a list of beziers.
pub fn draw_beziers(beziers: Vec<Bezier>, options: String) -> String {
let start_point = beziers.first().unwrap().start();
let mut svg = format!("<path d=\"M {} {}", start_point.x, start_point.y);
beziers.iter().for_each(|bezier| {
let _ = write!(svg, " {}", bezier.svg_curve_argument());
});
let _ = write!(svg, " Z\" {}/>", options);
svg
}
// Helper function to convert polar to cartesian coordinates
fn polar_to_cartesian(center_x: f64, center_y: f64, radius: f64, angle_in_rad: f64) -> [f64; 2] {
let x = center_x + radius * angle_in_rad.cos();