Bezier split and trim implementation (#680)

* Added split implementation and UI

Co-authored-by: Thomas Cheng <Androxium@users.noreply.github.com>

* Added bezier split impl

* Adjust struct traits

* Implement trim and adjust FE code to handle multiple sliders per feature

Co-authored-by: Thomas Cheng <contact.chengthomas@gmail.com>
Co-authored-by: Rob Nadal <robnadal44@gmail.com>

* Fix edge case in trim and add rust doc comments

* Stylistic changes per review

* More stylistic changes per review

* replaced last explicit color usages

Co-authored-by: Robert Nadal <Robnadal44@gmail.com>
Co-authored-by: Thomas Cheng <Androxium@users.noreply.github.com>
Co-authored-by: Thomas Cheng <contact.chengthomas@gmail.com>
This commit is contained in:
Hannah Li
2022-06-27 19:33:56 -04:00
committed by GitHub
co-authored by Thomas Cheng Thomas Cheng Rob Nadal
parent 55444eea86
commit 79944b54c8
8 changed files with 224 additions and 102 deletions
+73 -38
View File
@@ -2,7 +2,7 @@
<div class="App">
<h1>Bezier-rs Interactive Documentation</h1>
<p>This is the interactive documentation for the <b>bezier-rs</b> library. Click and drag on the endpoints of the example curves to visualize the various Bezier utilities and functions.</p>
<div v-for="feature in features" :key="feature.id">
<div v-for="(feature, index) in features" :key="index">
<ExamplePane :template="feature.template" :templateOptions="feature.templateOptions" :name="feature.name" :callback="feature.callback" />
</div>
<br />
@@ -13,7 +13,7 @@
<script lang="ts">
import { defineComponent, markRaw } from "vue";
import { drawText, drawPoint, drawLine, getContextFromCanvas } from "@/utils/drawing";
import { drawText, drawPoint, drawBezier, drawLine, getContextFromCanvas, drawBezierHelper, COLORS } from "@/utils/drawing";
import { WasmBezierInstance } from "@/utils/types";
import ExamplePane from "@/components/ExamplePane.vue";
@@ -51,57 +51,55 @@ export default defineComponent({
return {
features: [
{
id: 0,
name: "Constructor",
// eslint-disable-next-line
callback: (): void => {},
},
{
id: 2,
name: "Length",
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance): void => {
drawText(getContextFromCanvas(canvas), `Length: ${bezier.length().toFixed(2)}`, 5, canvas.height - 7);
},
},
{
id: 3,
name: "Compute",
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: string): void => {
const point = JSON.parse(bezier.compute(parseFloat(options)));
drawPoint(getContextFromCanvas(canvas), point, 4, "Red");
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>): void => {
const point = JSON.parse(bezier.compute(options.t));
drawPoint(getContextFromCanvas(canvas), point, 4, COLORS.NON_INTERACTIVE.STROKE_1);
},
template: markRaw(SliderExample),
templateOptions: tSliderOptions,
templateOptions: { sliders: [tSliderOptions] },
},
{
id: 4,
name: "Lookup Table",
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: string): void => {
const lookupPoints = bezier.compute_lookup_table(Number(options));
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>): void => {
const lookupPoints = bezier.compute_lookup_table(options.steps);
lookupPoints.forEach((serialisedPoint, index) => {
if (index !== 0 && index !== lookupPoints.length - 1) {
drawPoint(getContextFromCanvas(canvas), JSON.parse(serialisedPoint), 3, "Red");
drawPoint(getContextFromCanvas(canvas), JSON.parse(serialisedPoint), 3, COLORS.NON_INTERACTIVE.STROKE_1);
}
});
},
template: markRaw(SliderExample),
templateOptions: {
min: 2,
max: 15,
step: 1,
default: 5,
variable: "Steps",
sliders: [
{
min: 2,
max: 15,
step: 1,
default: 5,
variable: "steps",
},
],
},
},
{
id: 5,
name: "Derivative",
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: string): void => {
const t = parseFloat(options);
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>): void => {
const context = getContextFromCanvas(canvas);
const intersection = JSON.parse(bezier.compute(t));
const derivative = JSON.parse(bezier.derivative(t));
const intersection = JSON.parse(bezier.compute(options.t));
const derivative = JSON.parse(bezier.derivative(options.t));
const curveFactor = bezier.get_points().length - 1;
const tangentStart = {
@@ -113,23 +111,21 @@ export default defineComponent({
y: intersection.y + derivative.y / curveFactor,
};
drawLine(context, tangentStart, tangentEnd, "Red");
drawPoint(context, tangentStart, 3, "Red");
drawPoint(context, intersection, 3, "Red");
drawPoint(context, tangentEnd, 3, "Red");
drawLine(context, tangentStart, tangentEnd, COLORS.NON_INTERACTIVE.STROKE_1);
drawPoint(context, tangentStart, 3, COLORS.NON_INTERACTIVE.STROKE_1);
drawPoint(context, intersection, 3, COLORS.NON_INTERACTIVE.STROKE_1);
drawPoint(context, tangentEnd, 3, COLORS.NON_INTERACTIVE.STROKE_1);
},
template: markRaw(SliderExample),
templateOptions: tSliderOptions,
templateOptions: { sliders: [tSliderOptions] },
},
{
id: 6,
name: "Normal",
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: string): void => {
const t = parseFloat(options);
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>): void => {
const context = getContextFromCanvas(canvas);
const intersection = JSON.parse(bezier.compute(t));
const normal = JSON.parse(bezier.normal(t));
const intersection = JSON.parse(bezier.compute(options.t));
const normal = JSON.parse(bezier.normal(options.t));
const normalStart = {
x: intersection.x - normal.x * 20,
@@ -140,13 +136,52 @@ export default defineComponent({
y: intersection.y + normal.y * 20,
};
drawLine(context, normalStart, normalEnd, "Red");
drawPoint(context, normalStart, 3, "Red");
drawPoint(context, intersection, 3, "Red");
drawPoint(context, normalEnd, 3, "Red");
drawLine(context, normalStart, normalEnd, COLORS.NON_INTERACTIVE.STROKE_1);
drawPoint(context, normalStart, 3, COLORS.NON_INTERACTIVE.STROKE_1);
drawPoint(context, intersection, 3, COLORS.NON_INTERACTIVE.STROKE_1);
drawPoint(context, normalEnd, 3, COLORS.NON_INTERACTIVE.STROKE_1);
},
template: markRaw(SliderExample),
templateOptions: tSliderOptions,
templateOptions: { sliders: [tSliderOptions] },
},
{
name: "Split",
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>): void => {
const context = getContextFromCanvas(canvas);
const bezierPairPoints = JSON.parse(bezier.split(options.t));
drawBezier(context, bezierPairPoints[0], null, COLORS.NON_INTERACTIVE.STROKE_2, 3.5);
drawBezier(context, bezierPairPoints[1], null, COLORS.NON_INTERACTIVE.STROKE_1, 3.5);
},
template: markRaw(SliderExample),
templateOptions: { sliders: [tSliderOptions] },
},
{
name: "Trim",
callback: (canvas: HTMLCanvasElement, bezier: WasmBezierInstance, options: Record<string, number>): void => {
const context = getContextFromCanvas(canvas);
const trimmedBezier = bezier.trim(options.t1, options.t2);
drawBezierHelper(context, trimmedBezier, COLORS.NON_INTERACTIVE.STROKE_1, 3.5);
},
template: markRaw(SliderExample),
templateOptions: {
sliders: [
{
variable: "t1",
min: 0,
max: 1,
step: 0.01,
default: 0.25,
},
{
variable: "t2",
min: 0,
max: 1,
step: 0.01,
default: 0.75,
},
],
},
},
],
};