import type { SubpathCallback, SubpathInputOption, WasmSubpathInstance } from "@/types"; import { capOptions, joinOptions, tSliderOptions, subpathTValueVariantOptions, intersectionErrorOptions, minimumSeparationOptions, separationDiskDiameter, SUBPATH_T_VALUE_VARIANTS } from "@/types"; const subpathFeatures = { constructor: { name: "Constructor", callback: (subpath: WasmSubpathInstance): string => subpath.to_svg(), }, insert: { name: "Insert", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.insert(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]), inputOptions: [subpathTValueVariantOptions, tSliderOptions], }, length: { name: "Length", callback: (subpath: WasmSubpathInstance): string => subpath.length(), }, "length-centroid": { name: "Length Centroid", callback: (subpath: WasmSubpathInstance): string => subpath.length_centroid(), }, area: { name: "Area", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.area(options.error, options.minimum_separation), inputOptions: [intersectionErrorOptions, minimumSeparationOptions], }, "area-centroid": { name: "Area Centroid", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.area_centroid(options.error, options.minimum_separation), inputOptions: [intersectionErrorOptions, minimumSeparationOptions], }, "poisson-disk-points": { name: "Poisson-Disk Points", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.poisson_disk_points(options.separation_disk_diameter), inputOptions: [separationDiskDiameter], }, evaluate: { name: "Evaluate", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.evaluate(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]), inputOptions: [subpathTValueVariantOptions, tSliderOptions], }, "lookup-table": { name: "Lookup Table", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.compute_lookup_table(options.steps, SUBPATH_T_VALUE_VARIANTS[options.TVariant]), inputOptions: [ subpathTValueVariantOptions, { variable: "steps", inputType: "slider", min: 2, max: 30, step: 1, default: 5, }, ], }, project: { name: "Project", callback: (subpath: WasmSubpathInstance, _: Record, mouseLocation?: [number, number]): string => mouseLocation ? subpath.project(mouseLocation[0], mouseLocation[1]) : subpath.to_svg(), triggerOnMouseMove: true, }, tangent: { name: "Tangent", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.tangent(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]), inputOptions: [subpathTValueVariantOptions, tSliderOptions], }, normal: { name: "Normal", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.normal(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]), inputOptions: [subpathTValueVariantOptions, tSliderOptions], }, "local-extrema": { name: "Local Extrema", callback: (subpath: WasmSubpathInstance): string => subpath.local_extrema(), }, "bounding-box": { name: "Bounding Box", callback: (subpath: WasmSubpathInstance): string => subpath.bounding_box(), }, inflections: { name: "Inflections", callback: (subpath: WasmSubpathInstance): string => subpath.inflections(), }, "intersect-linear": { name: "Intersect (Linear Segment)", callback: (subpath: WasmSubpathInstance, options: Record): string => subpath.intersect_line_segment( [ [80, 30], [210, 150], ], options.error, options.minimum_separation, ), inputOptions: [intersectionErrorOptions, minimumSeparationOptions], }, "intersect-quadratic": { name: "Intersect (Quadratic Segment)", callback: (subpath: WasmSubpathInstance, options: Record): string => subpath.intersect_quadratic_segment( [ [25, 50], [205, 10], [135, 180], ], options.error, options.minimum_separation, ), inputOptions: [intersectionErrorOptions, minimumSeparationOptions], }, "intersect-cubic": { name: "Intersect (Cubic Segment)", callback: (subpath: WasmSubpathInstance, options: Record): string => subpath.intersect_cubic_segment( [ [65, 20], [125, 40], [65, 120], [200, 140], ], options.error, options.minimum_separation, ), inputOptions: [intersectionErrorOptions, minimumSeparationOptions], }, "intersect-self": { name: "Intersect (Self)", callback: (subpath: WasmSubpathInstance, options: Record): string => subpath.self_intersections(options.error, options.minimum_separation), inputOptions: [intersectionErrorOptions, minimumSeparationOptions], }, "intersect-rectangle": { name: "Intersect (Rectangle)", callback: (subpath: WasmSubpathInstance, options: Record): string => subpath.intersect_rectangle( [ [75, 50], [175, 150], ], options.error, options.minimum_separation, ), inputOptions: [intersectionErrorOptions, minimumSeparationOptions], }, "inside-other": { name: "Inside (Other Subpath)", callback: (subpath: WasmSubpathInstance, options: Record): string => subpath.inside_subpath( [ [40, 40], [160, 40], [160, 80], [200, 100], [160, 120], [160, 160], [40, 160], [40, 120], [80, 100], [40, 80], ], options.error, options.minimum_separation, ), inputOptions: [intersectionErrorOptions, minimumSeparationOptions], }, curvature: { name: "Curvature", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.curvature(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]), inputOptions: [subpathTValueVariantOptions, { ...tSliderOptions, default: 0.2 }], }, split: { name: "Split", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.split(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]), inputOptions: [subpathTValueVariantOptions, tSliderOptions], }, trim: { name: "Trim", callback: (subpath: WasmSubpathInstance, options: Record, _: undefined): string => subpath.trim(options.t1, options.t2, SUBPATH_T_VALUE_VARIANTS[options.TVariant]), inputOptions: [subpathTValueVariantOptions, { ...tSliderOptions, default: 0.2, variable: "t1" }, { ...tSliderOptions, variable: "t2" }], }, offset: { name: "Offset", callback: (subpath: WasmSubpathInstance, options: Record): string => subpath.offset(options.distance, options.join, options.miter_limit), inputOptions: [ { variable: "distance", inputType: "slider", min: -25, max: 25, step: 1, default: 10, }, joinOptions, { variable: "join: Miter - limit", inputType: "slider", min: 1, max: 10, step: 0.25, default: 4, }, ], }, outline: { name: "Outline", callback: (subpath: WasmSubpathInstance, options: Record): string => subpath.outline(options.distance, options.join, options.cap, options.miter_limit), inputOptions: [ { variable: "distance", inputType: "slider", min: 0, max: 25, step: 1, default: 10, }, joinOptions, { variable: "join: Miter - limit", inputType: "slider", min: 1, max: 10, step: 0.25, default: 4, }, { ...capOptions, isDisabledForClosed: true }, ], }, rotate: { name: "Rotate", callback: (subpath: WasmSubpathInstance, options: Record): string => subpath.rotate(options.angle * Math.PI, 125, 100), inputOptions: [ { variable: "angle", inputType: "slider", min: 0, max: 2, step: 1 / 50, default: 0.12, unit: "π", }, ], }, }; export type SubpathFeatureKey = keyof typeof subpathFeatures; export type SubpathFeatureOptions = { name: string; callback: SubpathCallback; inputOptions?: SubpathInputOption[]; triggerOnMouseMove?: boolean; }; export default subpathFeatures as Record;