File size: 8,412 Bytes
2409829
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
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<string, number>, _: 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<string, number>, _: undefined): string => subpath.area(options.error, options.minimum_separation),
		inputOptions: [intersectionErrorOptions, minimumSeparationOptions],
	},
	"area-centroid": {
		name: "Area Centroid",
		callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: 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<string, number>, _: undefined): string => subpath.poisson_disk_points(options.separation_disk_diameter),
		inputOptions: [separationDiskDiameter],
	},
	evaluate: {
		name: "Evaluate",
		callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: 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<string, number>, _: 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<string, number>, mouseLocation?: [number, number]): string =>
			mouseLocation ? subpath.project(mouseLocation[0], mouseLocation[1]) : subpath.to_svg(),
		triggerOnMouseMove: true,
	},
	tangent: {
		name: "Tangent",
		callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: undefined): string => subpath.tangent(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]),
		inputOptions: [subpathTValueVariantOptions, tSliderOptions],
	},
	normal: {
		name: "Normal",
		callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: 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, number>): 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, number>): 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, number>): 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, number>): string => subpath.self_intersections(options.error, options.minimum_separation),
		inputOptions: [intersectionErrorOptions, minimumSeparationOptions],
	},
	"intersect-rectangle": {
		name: "Intersect (Rectangle)",
		callback: (subpath: WasmSubpathInstance, options: Record<string, number>): 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, number>): 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<string, number>, _: 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<string, number>, _: undefined): string => subpath.split(options.t, SUBPATH_T_VALUE_VARIANTS[options.TVariant]),
		inputOptions: [subpathTValueVariantOptions, tSliderOptions],
	},
	trim: {
		name: "Trim",
		callback: (subpath: WasmSubpathInstance, options: Record<string, number>, _: 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, number>): 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, number>): 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, number>): 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<SubpathFeatureKey, SubpathFeatureOptions>;