Implement curvature function in Bezier math library (#725)
* bezier curvature * change comment Co-authored-by: Jackie Chen <jackiechen73>
This commit is contained in:
parent
30e5d3c8ec
commit
8c1e6455eb
|
|
@ -25,7 +25,7 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, markRaw } from "vue";
|
||||
|
||||
import { drawBezier, drawBezierHelper, drawCurve, drawLine, drawPoint, drawText, getContextFromCanvas, COLORS } from "@/utils/drawing";
|
||||
import { drawBezier, drawBezierHelper, drawCircle, drawCurve, drawLine, drawPoint, drawText, getContextFromCanvas, COLORS } from "@/utils/drawing";
|
||||
import { BezierCurveType, Point, WasmBezierInstance, WasmSubpathInstance } from "@/utils/types";
|
||||
|
||||
import ExamplePane from "@/components/ExamplePane.vue";
|
||||
|
|
@ -205,6 +205,26 @@ export default defineComponent({
|
|||
template: markRaw(SliderExample),
|
||||
templateOptions: { sliders: [tSliderOptions] },
|
||||
},
|
||||
{
|
||||
name: "Curvature",
|
||||
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>): void => {
|
||||
const context = getContextFromCanvas(canvas);
|
||||
const point = JSON.parse(bezier.evaluate(options.t));
|
||||
const normal = JSON.parse(bezier.normal(options.t));
|
||||
const curvature = bezier.curvature(options.t);
|
||||
const radius = 1 / curvature;
|
||||
|
||||
const curvatureCenter = { x: point.x + normal.x * radius, y: point.y + normal.y * radius };
|
||||
|
||||
drawCircle(context, curvatureCenter, Math.abs(radius), COLORS.NON_INTERACTIVE.STROKE_1);
|
||||
drawLine(context, point, curvatureCenter, COLORS.NON_INTERACTIVE.STROKE_1);
|
||||
drawPoint(context, point, 3, COLORS.NON_INTERACTIVE.STROKE_1);
|
||||
drawPoint(context, curvatureCenter, 3, COLORS.NON_INTERACTIVE.STROKE_1);
|
||||
},
|
||||
curveDegrees: new Set([BezierCurveType.Quadratic, BezierCurveType.Cubic]),
|
||||
template: markRaw(SliderExample),
|
||||
templateOptions: { sliders: [tSliderOptions] },
|
||||
},
|
||||
{
|
||||
name: "Split",
|
||||
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>): void => {
|
||||
|
|
|
|||
|
|
@ -73,6 +73,14 @@ export const drawCurve = (ctx: CanvasRenderingContext2D, points: Point[], stroke
|
|||
ctx.stroke();
|
||||
};
|
||||
|
||||
export const drawCircle = (ctx: CanvasRenderingContext2D, point: Point, radius: number, strokeColor = COLORS.INTERACTIVE.STROKE_1): void => {
|
||||
ctx.strokeStyle = strokeColor;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.arc(point.x, point.y, radius, 0, 2 * Math.PI, false);
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
export const drawBezierHelper = (ctx: CanvasRenderingContext2D, bezier: WasmBezierInstance, bezierStyleConfig: Partial<BezierStyleConfig> = {}): void => {
|
||||
const points = bezier.get_points().map((p: string) => JSON.parse(p));
|
||||
drawBezier(ctx, points, null, bezierStyleConfig);
|
||||
|
|
|
|||
|
|
@ -166,4 +166,8 @@ impl WasmBezier {
|
|||
let bezier_points: Vec<Vec<Point>> = self.0.offset(distance).into_iter().map(bezier_to_points).collect();
|
||||
to_js_value(bezier_points)
|
||||
}
|
||||
|
||||
pub fn curvature(&self, t: f64) -> f64 {
|
||||
self.0.curvature(t)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,6 +394,26 @@ impl Bezier {
|
|||
self.tangent(t).perp()
|
||||
}
|
||||
|
||||
/// Returns the curvature, a scalar value for the derivative at the given `t`-value along the curve.
|
||||
/// Curvature is 1 over the radius of a circle with an equivalent derivative.
|
||||
pub fn curvature(&self, t: f64) -> f64 {
|
||||
let (d, dd) = match &self.derivative() {
|
||||
Some(first_derivative) => match first_derivative.derivative() {
|
||||
Some(second_derivative) => (first_derivative.evaluate(t), second_derivative.evaluate(t)),
|
||||
None => (first_derivative.evaluate(t), first_derivative.end - first_derivative.start),
|
||||
},
|
||||
None => (self.end - self.start, DVec2::new(0., 0.)),
|
||||
};
|
||||
|
||||
let numerator = d.x * dd.y - d.y * dd.x;
|
||||
let denominator = (d.x.powf(2.) + d.y.powf(2.)).powf(1.5);
|
||||
if denominator == 0. {
|
||||
0.
|
||||
} else {
|
||||
numerator / denominator
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the pair of Bezier curves that result from splitting the original curve at the point corresponding to `t`.
|
||||
pub fn split(&self, t: f64) -> [Bezier; 2] {
|
||||
let split_point = self.evaluate(t);
|
||||
|
|
|
|||
Loading…
Reference in New Issue