Implement bezier local_extrema function (#693)

* Implement backend of extrema in bezier-rs

* Added extrema frontend

* Added extrema interface

* Wrapped extrema in filter function to remove points not on the curve

* Saved intermediate results while computing extrema

* Fixed extrema bug when a in cubic formula is 0

* Removed extra prints

* Fixed quadratic extrema regression

* Moved helper functions to utils file

* Fixed bug in solve linear

* Stylistic changes per review

* Sentence comments

Co-authored-by: Linda Zheng <thelindazheng@gmail.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Rob Nadal
2022-07-01 23:00:51 -07:00
committed by GitHub
co-authored by Linda Zheng Keavon Chambers
parent 4775a23c17
commit 0ad6e41a59
4 changed files with 119 additions and 38 deletions
+15 -1
View File
@@ -228,7 +228,7 @@ export default defineComponent({
},
{
name: "Project",
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>, mouseLocation: Point | null): void => {
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>, mouseLocation?: Point): void => {
if (mouseLocation != null) {
const context = getContextFromCanvas(canvas);
const closestPoint = JSON.parse(bezier.project(mouseLocation.x, mouseLocation.y));
@@ -236,6 +236,20 @@ export default defineComponent({
}
},
},
{
name: "Local Extrema",
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance): void => {
const context = getContextFromCanvas(canvas);
const dimensionColors = [COLORS.NON_INTERACTIVE.STROKE_1, COLORS.NON_INTERACTIVE.STROKE_2];
const extrema: number[][] = JSON.parse(bezier.local_extrema());
extrema.forEach((tValues, index) => {
tValues.forEach((t) => {
const point = JSON.parse(bezier.compute(t));
drawPoint(context, point, 4, dimensionColors[index]);
});
});
},
},
],
};
},
@@ -14,20 +14,20 @@ struct Point {
#[derive(Clone)]
pub struct WasmBezier(Bezier);
/// Convert a `DVec2` into a `JsValue`
/// Convert a `DVec2` into a `JsValue`.
pub fn vec_to_point(p: &DVec2) -> JsValue {
JsValue::from_serde(&serde_json::to_string(&Point { x: p.x, y: p.y }).unwrap()).unwrap()
}
#[wasm_bindgen]
impl WasmBezier {
/// Expect js_points to be a list of 3 pairs
/// Expect js_points to be a list of 3 pairs.
pub fn new_quadratic(js_points: &JsValue) -> WasmBezier {
let points: [DVec2; 3] = js_points.into_serde().unwrap();
WasmBezier(Bezier::from_quadratic_dvec2(points[0], points[1], points[2]))
}
/// Expect js_points to be a list of 4 pairs
/// Expect js_points to be a list of 4 pairs.
pub fn new_cubic(js_points: &JsValue) -> WasmBezier {
let points: [DVec2; 4] = js_points.into_serde().unwrap();
WasmBezier(Bezier::from_cubic_dvec2(points[0], points[1], points[2], points[3]))
@@ -102,4 +102,9 @@ impl WasmBezier {
pub fn project(&self, x: f64, y: f64) -> JsValue {
vec_to_point(&self.0.project(DVec2::new(x, y), 20, 1e-4, 3, 10))
}
pub fn local_extrema(&self) -> JsValue {
let local_extrema = self.0.local_extrema();
JsValue::from_serde(&serde_json::to_string(&local_extrema).unwrap()).unwrap()
}
}