Bezier-rs: Add parametric evaluate and line intersect to subpath (#852)

* add slider to subpath component + change evaluate to take an enum

Co-authored-by: Rob Nadal <RobNadal@users.noreply.github.com>

wip - add intersect to subpath, TODO fix bug

Co-authored-by: Rob Nadal <RobNadal@users.noreply.github.com>

add unit tests to subpath intersections

stress, testing

Co-authored-by: Hannah Li <hannahli2010@gmail.com>

* add parametric eval impl to subpath

* add line intersection to subpath

* Uncomment and #[ignore] disabled tests

* Reorder a few imports

* change subpath:eval slider to radio button

* fixed bug with solve_cubic, fixed unit tests, improved intersection accuracy

* fix failing test

Co-authored-by: Hannah Li <hannahli2010@gmail.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Thomas Cheng
2022-12-11 00:41:02 -05:00
committed by Keavon Chambers
co-authored by Rob Nadal Hannah Li Keavon Chambers
parent 9a4af4f87a
commit 52cc770a1e
13 changed files with 713 additions and 54 deletions
@@ -2,6 +2,10 @@
<div>
<h4 class="example-header">{{ title }}</h4>
<figure @mousedown="onMouseDown" @mouseup="onMouseUp" @mousemove="onMouseMove" class="example-figure" v-html="subpathSVG"></figure>
<div v-for="(slider, index) in sliderOptions" :key="index">
<div class="slider-label">{{ slider.variable }} = {{ sliderData[slider.variable] }}{{ getSliderValue(sliderData[slider.variable], sliderUnits[slider.variable]) }}</div>
<input class="slider" v-model.number="sliderData[slider.variable]" type="range" :step="slider.step" :min="slider.min" :max="slider.max" />
</div>
</div>
</template>
@@ -11,7 +15,7 @@
import { defineComponent, PropType } from "vue";
import { WasmSubpath } from "@/../wasm/pkg";
import { SubpathCallback, WasmSubpathInstance, WasmSubpathManipulatorKey } from "@/utils/types";
import { SubpathCallback, WasmSubpathInstance, WasmSubpathManipulatorKey, SliderOption, ComputeType } from "@/utils/types";
const SELECTABLE_RANGE = 10;
const POINT_INDEX_TO_MANIPULATOR: WasmSubpathManipulatorKey[] = ["set_anchor", "set_in_handle", "set_out_handle"];
@@ -22,14 +26,22 @@ export default defineComponent({
triples: { type: Array as PropType<Array<Array<number[] | undefined>>>, mutable: true, required: true },
closed: { type: Boolean as PropType<boolean>, default: false },
callback: { type: Function as PropType<SubpathCallback>, required: true },
sliderOptions: { type: Object as PropType<Array<SliderOption>>, default: () => ({}) },
computeType: { type: String as PropType<ComputeType>, default: "Parametric" },
},
data() {
const subpath = WasmSubpath.from_triples(this.triples, this.closed) as WasmSubpathInstance;
const sliderData = Object.assign({}, ...this.sliderOptions.map((s) => ({ [s.variable]: s.default })));
const sliderUnits = Object.assign({}, ...this.sliderOptions.map((s) => ({ [s.variable]: s.unit })));
return {
subpath,
subpathSVG: this.callback(subpath),
subpathSVG: this.callback(subpath, sliderData, undefined, "Euclidean"),
activeIndex: undefined as number[] | undefined,
mutableTriples: JSON.parse(JSON.stringify(this.triples)),
sliderData,
sliderUnits,
};
},
methods: {
@@ -55,9 +67,23 @@ export default defineComponent({
if (this.activeIndex) {
this.subpath[POINT_INDEX_TO_MANIPULATOR[this.activeIndex[1]]](this.activeIndex[0], mx, my);
this.mutableTriples[this.activeIndex[0]][this.activeIndex[1]] = [mx, my];
this.subpathSVG = this.callback(this.subpath);
this.subpathSVG = this.callback(this.subpath, this.sliderData, [mx, my], this.computeType);
}
},
getSliderValue: (sliderValue: number, sliderUnit?: string | string[]) => (Array.isArray(sliderUnit) ? sliderUnit[sliderValue] : sliderUnit),
},
watch: {
sliderData: {
handler() {
this.subpathSVG = this.callback(this.subpath, this.sliderData, undefined, this.computeType);
},
deep: true,
},
computeType: {
handler() {
this.subpathSVG = this.callback(this.subpath, this.sliderData, undefined, this.computeType);
},
},
},
});
</script>
@@ -1,9 +1,18 @@
<template>
<div>
<h3 class="example-pane-header">{{ name }}</h3>
<div v-if="chooseComputeType" class="compute-type-choice">
<strong>ComputeType:</strong>
<input type="radio" :id="`${id}-parametric`" value="Parametric" v-model="computeTypeChoice" />
<label :for="`${id}-parametric`">Parametric</label>
<input type="radio" :id="`${id}-euclidean`" value="Euclidean" v-model="computeTypeChoice" />
<label :for="`${id}-euclidean`">Euclidean</label>
</div>
<div class="example-row">
<div v-for="(example, index) in examples" :key="index">
<SubpathExample :title="example.title" :triples="example.triples" :closed="example.closed" :callback="callback" />
<SubpathExample :title="example.title" :triples="example.triples" :closed="example.closed" :callback="callback" :sliderOptions="sliderOptions" :computeType="computeTypeChoice" />
</div>
</div>
</div>
@@ -14,7 +23,7 @@
<script lang="ts">
import { defineComponent, PropType } from "vue";
import { SubpathCallback } from "@/utils/types";
import { SubpathCallback, SliderOption, ComputeType } from "@/utils/types";
import SubpathExample from "@/components/SubpathExample.vue";
@@ -22,6 +31,8 @@ export default defineComponent({
props: {
name: { type: String as PropType<string>, required: true },
callback: { type: Function as PropType<SubpathCallback>, required: true },
sliderOptions: { type: Array as PropType<Array<SliderOption>>, default: () => [] },
chooseComputeType: { type: Boolean as PropType<boolean>, default: false },
},
data() {
return {
@@ -50,6 +61,8 @@ export default defineComponent({
closed: true,
},
],
id: `${Math.random()}`.substring(2),
computeTypeChoice: "Parametric" as ComputeType,
};
},
components: {