Bezier-rs: Add calculations for area and centroid of subpaths (#1729)

* add code to calculate area and centroid of subpath

* change library to poly_it

* add a demo of area and centroid

* modify algorithm to consider negetive area as positive

* add code for manipulating polynomials in bezier-rs

* remove `poly_it` dependency and use custom Polynomial

* formatting floats to skip last zero

* add debug mechanism

* collect both intersection points instead of one

* fix test and cargo fmt

* apply minimum separation filtering in self_intersection and use better endpoint filtering algorithm

* remove debug mechanism and cargo fmt

* consider the subpath as closed for intersection calculation

* add documentation for polynomial.rs

* impl display for Polynomial

* make area always positive

* add missing docs

* fix test and cargo fmt

* Naming/formatting code review

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Elbert Ronnie
2024-04-30 07:49:12 +05:30
committed by GitHub
parent e769f50877
commit beb88d280c
11 changed files with 577 additions and 15 deletions

View File

@@ -453,7 +453,7 @@ const bezierFeatures = {
},
"intersect-self": {
name: "Intersect (Self)",
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.intersect_self(options.error),
callback: (bezier: WasmBezierInstance, options: Record<string, number>): string => bezier.intersect_self(options.error, options.minimum_separation),
demoOptions: {
Linear: {
disabled: true,
@@ -462,7 +462,7 @@ const bezierFeatures = {
disabled: true,
},
Cubic: {
inputOptions: [errorOptions],
inputOptions: [errorOptions, minimumSeparationOptions],
customPoints: [
[160, 180],
[170, 10],

View File

@@ -16,6 +16,16 @@ const subpathFeatures = {
name: "Length",
callback: (subpath: WasmSubpathInstance): string => subpath.length(),
},
area: {
name: "Area",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.area(options.error, options.minimum_separation),
inputOptions: [intersectionErrorOptions, minimumSeparationOptions],
},
centroid: {
name: "Centroid",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.centroid(options.error, options.minimum_separation),
inputOptions: [intersectionErrorOptions, minimumSeparationOptions],
},
evaluate: {
name: "Evaluate",
callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.evaluate(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]),

View File

@@ -498,11 +498,11 @@ impl WasmBezier {
}
/// The wrapped return type is `Vec<[f64; 2]>`.
pub fn intersect_self(&self, error: f64) -> String {
pub fn intersect_self(&self, error: f64, minimum_separation: f64) -> String {
let bezier_curve_svg = self.get_bezier_path();
let intersect_self_svg = self
.0
.self_intersections(Some(error))
.self_intersections(Some(error), Some(minimum_separation))
.iter()
.map(|intersection_t| {
let point = &self.0.evaluate(TValue::Parametric(intersection_t[0]));

View File

@@ -92,6 +92,16 @@ impl WasmSubpath {
wrap_svg_tag(format!("{}{}", self.to_default_svg(), length_text))
}
pub fn area(&self, error: f64, minimum_separation: f64) -> String {
let area_text = draw_text(format!("Area: {}", self.0.area(Some(error), Some(minimum_separation))), 5., 193., BLACK);
wrap_svg_tag(format!("{}{}", self.to_default_svg(), area_text))
}
pub fn centroid(&self, error: f64, minimum_separation: f64) -> String {
let point_text = draw_circle(self.0.centroid(Some(error), Some(minimum_separation)).unwrap(), 4., RED, 1.5, WHITE);
wrap_svg_tag(format!("{}{}", self.to_default_svg(), point_text))
}
pub fn evaluate(&self, t: f64, t_variant: String) -> String {
let t = parse_t_variant(&t_variant, t);
let point = self.0.evaluate(t);