1use std::convert::TryInto as _;
16
17pub mod bezctx_oplist;
18pub mod bezctx_ps;
19use bezctx_oplist::Operation;
20
21#[derive(Copy, Clone)]
22pub struct BezierContext<T> {
23 pub move_fn: fn(&mut Self, f64, f64, bool) -> (),
24 pub line_fn: fn(&mut Self, f64, f64) -> (),
25 pub curve_fn: fn(&mut Self, f64, f64, f64, f64, f64, f64) -> (),
26 pub mark_knot_fn: fn(&mut Self, usize) -> (),
28 pub data: Option<T>,
29}
30
31impl<T> BezierContext<T> {
32 pub fn move_to(&mut self, x: f64, y: f64, is_open: bool) {
33 (self.move_fn)(self, x, y, is_open);
34 }
35 pub fn line_to(&mut self, x: f64, y: f64) {
36 (self.line_fn)(self, x, y);
37 }
38 pub fn curve_to(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) {
40 (self.curve_fn)(self, x1, y1, x2, y2, x3, y3);
41 }
42 pub fn mark_knot(&mut self, knot_idx: usize) {
43 (self.mark_knot_fn)(self, knot_idx);
44 }
45}
46
47impl<T> Default for BezierContext<T> {
48 fn default() -> Self {
49 Self {
50 move_fn: |_, _, _, _| {},
51 line_fn: |_, _, _| {},
52 curve_fn: |_, _, _, _, _, _, _| {},
53 mark_knot_fn: |_, _| {},
54 data: None,
55 }
56 }
57}
58
59#[derive(Copy, Clone, Debug)]
60pub struct SpiroCP {
61 pub x: f64,
62 pub y: f64,
63 pub ty: char,
64}
65
66#[derive(Copy, Clone, Debug, Default)]
79pub struct SpiroSegment {
80 x: f64,
81 y: f64,
82 ty: char,
83 bend_th: f64,
84 ks: [f64; 4],
85 seg_ch: f64,
86 seg_th: f64,
87}
88#[derive(Copy, Clone, Debug, Default)]
89pub struct BandMath {
90 a: [f64; 11],
91 al: [f64; 5],
92}
93pub fn integrate_spiro(ks: [f64; 4], xy: &mut [f64; 2]) {
96 let th1: f64 = ks[0];
97 let th2: f64 = 0.5 * ks[1];
98 let th3: f64 = 1.0 / 6. * ks[2];
99 let th4: f64 = 1.0 / 24. * ks[3];
100 let mut x: f64 = 0.;
101 let mut y: f64 = 0.;
102 let ds: f64 = 1.0 / 4 as f64;
103 let ds2: f64 = ds * ds;
104 let ds3: f64 = ds2 * ds;
105 let k0: f64 = ks[0] * ds;
106 let k1: f64 = ks[1] * ds;
107 let k2: f64 = ks[2] * ds;
108 let k3: f64 = ks[3] * ds;
109 let mut i: isize = 0;
110 let mut s: f64 = 0.5 * ds - 0.5;
111 while i < 4 {
112 let mut u;
113 let mut v;
114 let km0;
115 let km1;
116 let km2;
117 let km3;
118
119 km0 = ((1.0 / 6. * k3 * s + 0.5 * k2) * s + k1) * s + k0;
120 km1 = ((0.5 * k3 * s + k2) * s + k1) * ds;
121 km2 = (k3 * s + k2) * ds2;
122
123 km3 = k3 * ds3;
124 let t1_1: f64 = km0;
125 let t1_2: f64 = 0.5 * km1;
126 let t1_3: f64 = 1.0 / 6. * km2;
127 let t1_4: f64 = 1.0 / 24. * km3;
128 let t2_2: f64 = t1_1 * t1_1;
129 let t2_3: f64 = 2. * (t1_1 * t1_2);
130 let t2_4: f64 = 2. * (t1_1 * t1_3) + t1_2 * t1_2;
131 let t2_5: f64 = 2. * (t1_1 * t1_4 + t1_2 * t1_3);
132 let t2_6: f64 = 2. * (t1_2 * t1_4) + t1_3 * t1_3;
133 let t2_7: f64 = 2. * (t1_3 * t1_4);
134 let t2_8: f64 = t1_4 * t1_4;
135 let t3_4: f64 = t2_2 * t1_2 + t2_3 * t1_1;
136 let t3_6: f64 = t2_2 * t1_4 + t2_3 * t1_3 + t2_4 * t1_2 + t2_5 * t1_1;
137 let t3_8: f64 = t2_4 * t1_4 + t2_5 * t1_3 + t2_6 * t1_2 + t2_7 * t1_1;
138 let t3_10: f64 = t2_6 * t1_4 + t2_7 * t1_3 + t2_8 * t1_2;
139 let t4_4: f64 = t2_2 * t2_2;
140 let t4_5: f64 = 2. * (t2_2 * t2_3);
141 let t4_6: f64 = 2. * (t2_2 * t2_4) + t2_3 * t2_3;
142 let t4_7: f64 = 2. * (t2_2 * t2_5 + t2_3 * t2_4);
143 let t4_8: f64 = 2. * (t2_2 * t2_6 + t2_3 * t2_5) + t2_4 * t2_4;
144 let t4_9: f64 = 2. * (t2_2 * t2_7 + t2_3 * t2_6 + t2_4 * t2_5);
145 let t4_10: f64 = 2. * (t2_2 * t2_8 + t2_3 * t2_7 + t2_4 * t2_6) + t2_5 * t2_5;
146 let t5_6: f64 = t4_4 * t1_2 + t4_5 * t1_1;
147 let t5_8: f64 = t4_4 * t1_4 + t4_5 * t1_3 + t4_6 * t1_2 + t4_7 * t1_1;
148 let t5_10: f64 = t4_6 * t1_4 + t4_7 * t1_3 + t4_8 * t1_2 + t4_9 * t1_1;
149 let t6_6: f64 = t4_4 * t2_2;
150 let t6_7: f64 = t4_4 * t2_3 + t4_5 * t2_2;
151 let t6_8: f64 = t4_4 * t2_4 + t4_5 * t2_3 + t4_6 * t2_2;
152 let t6_9: f64 = t4_4 * t2_5 + t4_5 * t2_4 + t4_6 * t2_3 + t4_7 * t2_2;
153 let t6_10: f64 = t4_4 * t2_6 + t4_5 * t2_5 + t4_6 * t2_4 + t4_7 * t2_3 + t4_8 * t2_2;
154 let t7_8: f64 = t6_6 * t1_2 + t6_7 * t1_1;
155 let t7_10: f64 = t6_6 * t1_4 + t6_7 * t1_3 + t6_8 * t1_2 + t6_9 * t1_1;
156 let t8_8: f64 = t6_6 * t2_2;
157 let t8_9: f64 = t6_6 * t2_3 + t6_7 * t2_2;
158 let t8_10: f64 = t6_6 * t2_4 + t6_7 * t2_3 + t6_8 * t2_2;
159 let t9_10: f64 = t8_8 * t1_2 + t8_9 * t1_1;
160 let t10_10: f64 = t8_8 * t2_2;
161 u = 1.;
162 v = 0.;
163 v += 1.0 / 12. * t1_2 + 1.0 / 80. * t1_4;
164 u -= 1.0 / 24. * t2_2 + 1.0 / 160. * t2_4 + 1.0 / 896. * t2_6 + 1.0 / 4608. * t2_8;
165 v -= 1.0 / 480. * t3_4 + 1.0 / 2688. * t3_6 + 1.0 / 13824. * t3_8 + 1.0 / 67584. * t3_10;
166 u += 1.0 / 1920. * t4_4 + 1.0 / 10752. * t4_6 + 1.0 / 55296. * t4_8 + 1.0 / 270336. * t4_10;
167 v += 1.0 / 53760. * t5_6 + 1.0 / 276480. * t5_8 + 1.0 / 1.35168e+06 * t5_10;
168 u -= 1.0 / 322560. * t6_6 + 1.0 / 1.65888e+06 * t6_8 + 1.0 / 8.11008e+06 * t6_10;
169 v -= 1.0 / 1.16122e+07 * t7_8 + 1.0 / 5.67706e+07 * t7_10;
170 u += 1.0 / 9.28973e+07 * t8_8 + 1.0 / 4.54164e+08 * t8_10;
171 v += 1.0 / 4.08748e+09 * t9_10;
172 u -= 1.0 / 4.08748e+10 * t10_10;
173
174 let th: f64 = (((th4 * s + th3) * s + th2) * s + th1) * s;
175 let cth: f64 = (th).cos();
176 let sth: f64 = (th).sin();
177 x += cth * u - sth * v;
178 y += cth * v + sth * u;
179 s += ds;
180
181 i += 1
182 }
183 xy[0] = x * ds;
184 xy[1] = y * ds;
185}
186
187pub fn compute_ends(ks: [f64; 4], ends: &mut [[f64; 4]; 2], seg_ch: f64) -> f64 {
188 let mut xy: [f64; 2] = [0.; 2];
189 let ch;
190 let th;
191 let l;
192 let l2;
193 let l3;
194 let th_even;
195 let th_odd;
196 let k0_even;
197 let k0_odd;
198 let k1_even;
199 let k1_odd;
200 let k2_even;
201 let k2_odd;
202 integrate_spiro(ks, &mut xy);
203 ch = xy[0].hypot(xy[1]);
204 th = xy[1].atan2(xy[0]);
205 l = ch / seg_ch;
206 th_even = 0.5 * ks[0] + 1.0 / 48. * ks[2];
207 th_odd = 0.125 * ks[1] + 1.0 / 384. * ks[3] - th;
208 (ends[0])[0] = th_even - th_odd;
209 (ends[1])[0] = th_even + th_odd;
210 k0_even = l * (ks[0] + 0.125 * ks[2]);
211 k0_odd = l * (0.5 * ks[1] + 1.0 / 48. * ks[3]);
212 (ends[0])[1] = k0_even - k0_odd;
213 (ends[1])[1] = k0_even + k0_odd;
214 l2 = l * l;
215 k1_even = l2 * (ks[1] + 0.125 * ks[3]);
216 k1_odd = l2 * 0.5 * ks[2];
217 (ends[0])[2] = k1_even - k1_odd;
218 (ends[1])[2] = k1_even + k1_odd;
219 l3 = l2 * l;
220 k2_even = l3 * ks[2];
221 k2_odd = l3 * 0.5 * ks[3];
222 (ends[0])[3] = k2_even - k2_odd;
223 (ends[1])[3] = k2_even + k2_odd;
224 return l;
225}
226
227pub fn compute_pderivs(s: &SpiroSegment, ends: &mut [[f64; 4]; 2], derivs: &mut [[[f64; 4]; 2]; 4], jinc: isize) {
228 let recip_d: f64 = 2e6;
229 let delta: f64 = 1.0 / recip_d;
230 let mut try_ks: [f64; 4] = [0.; 4];
231 let mut try_ends: [[f64; 4]; 2] = [[0.; 4]; 2];
232 let mut i: usize = 0;
233 let mut j;
234 let mut k;
235 compute_ends(s.ks, ends, s.seg_ch);
236 while (i as isize) < jinc {
237 j = 0;
238 while j < 4 {
239 try_ks[j] = s.ks[j];
240 j += 1
241 }
242 try_ks[i] += delta;
243 compute_ends(try_ks, &mut try_ends, s.seg_ch);
244 k = 0;
245 while k < 2 {
246 j = 0;
247 while j < 4 {
248 (derivs[j])[k][i] = recip_d * (try_ends[k][j] - (ends[k])[j]);
249 j += 1
250 }
251 k += 1
252 }
253 i += 1
254 }
255}
256
257use std::f64::consts::PI;
258fn mod2pi(th: f64) -> f64 {
259 let u = th / (2. * PI);
260 return 2. * PI * (u - (u + 0.5).floor());
261}
262
263pub fn setup_path(src: &[SpiroCP]) -> Vec<SpiroSegment> {
264 let mut n = src.len();
265
266 if n == 0 {
267 return Vec::new();
268 }
269
270 if (src[0]).ty == '{' {
271 n -= 1;
272 };
273
274 let mut r = vec![SpiroSegment::default(); n + 1];
275
276 let mut i = 0;
277 let mut ilast;
278 while i < n {
279 r[i].x = src[i].x;
280 r[i].y = src[i].y;
281 r[i].ty = src[i].ty;
282 r[i].ks[0] = 0.0;
283 r[i].ks[1] = 0.0;
284 r[i].ks[2] = 0.0;
285 r[i].ks[3] = 0.0;
286 i += 1
287 }
288 r[n].x = src[n % src.len()].x;
289 r[n].y = src[n % src.len()].y;
290 r[n].ty = src[n % src.len()].ty;
291 i = 0;
292 while i < n {
293 let dx: f64 = r[i + 1].x - r[i].x;
294 let dy: f64 = r[i + 1].y - r[i].y;
295 r[i].seg_ch = dx.hypot(dy);
296 r[i].seg_th = dy.atan2(dx);
297 i += 1
298 }
299 ilast = n - 1;
300 i = 0;
301 while i < n {
302 if (r[i].ty == '{') || (r[i].ty == '}') || (r[i].ty == 'v') {
303 r[i].bend_th = 0.0;
304 } else {
305 r[i].bend_th = mod2pi(r[i].seg_th - r[ilast].seg_th);
306 }
307 ilast = i;
308 i += 1
309 }
310 r
311}
312
313pub fn bandec11(m: &mut [BandMath], perm: &mut [isize], n: isize) {
314 let mut i: isize = 0;
315 let mut j;
316 let mut k: isize = 0;
317 let mut l: isize = 5;
318 while i < 5 {
320 j = 0;
321 while j < i + 6 {
322 m[i as usize].a[j as usize] = m[i as usize].a[(j + 5 - i) as usize];
323 j += 1
324 }
325 while j < 11 {
326 m[i as usize].a[j as usize] = 0.0;
327 j += 1
328 }
329 i += 1
330 }
331 while k < n {
332 let mut pivot: isize = k;
333 let mut pivot_val: f64 = m[k as usize].a[0];
334 if l < n {
335 l += 1
336 }
337 j = k + 1;
338 while j < l {
339 if m[j as usize].a[0].abs() > pivot_val.abs() {
340 pivot_val = m[j as usize].a[0];
341 pivot = j;
342 }
343 j += 1
344 }
345 perm[k as usize] = pivot;
346 if pivot != k {
347 j = 0;
348 while j < 11 {
349 let tmp: f64 = m[k as usize].a[j as usize];
350 m[k as usize].a[j as usize] = m[pivot as usize].a[j as usize];
351 m[pivot as usize].a[j as usize] = tmp;
352 j += 1
353 }
354 }
355 if pivot_val.abs() < 1e-12 {
356 pivot_val = 1e-12
357 }
358 let pivot_scale = 1.0 / pivot_val;
359 i = k + 1;
360 while i < l {
361 let x: f64 = m[i as usize].a[0] * pivot_scale;
362 m[k as usize].al[(i - k - 1) as usize] = x;
363 j = 1;
364 while j < 11 {
365 m[i as usize].a[(j - 1) as usize] = m[i as usize].a[j as usize] - x * m[k as usize].a[j as usize];
366 j += 1
367 }
368 m[i as usize].a[10] = 0.0;
369 i += 1
370 }
371 k += 1
372 }
373}
374
375pub fn banbks11(m: &[BandMath], perm: &[isize], v: &mut [f64], n: isize) {
376 let mut i;
377 let mut k: isize = 0;
378 let mut l: isize = 5;
379 while k < n {
381 i = perm[k as usize];
382 if i != k {
383 let tmp = v[k as usize];
384 v[k as usize] = v[i as usize];
385 v[i as usize] = tmp;
386 }
387 if l < n {
388 l += 1
389 }
390 i = k + 1;
391 while i < l {
392 v[i as usize] -= m[k as usize].al[(i - k - 1) as usize] * v[k as usize];
393 i += 1
394 }
395 k += 1
396 }
397 l = 1;
399 i = n - 1;
400 while i >= 0 {
401 let mut x: f64 = v[i as usize];
402 k = 1;
403 while k < l {
404 x -= m[i as usize].a[k as usize] * v[(k + i) as usize];
405 k += 1
406 }
407 v[i as usize] = x / m[i as usize].a[0];
408 if l < 11 {
409 l += 1
410 }
411 i -= 1
412 }
413}
414
415pub fn compute_jinc(ty0: char, ty1: char) -> isize {
416 if ty0 == 'o' || ty1 == 'o' || ty0 == ']' || ty1 == '[' {
417 return 4;
418 } else if ty0 == 'c' && ty1 == 'c' {
419 return 2;
420 } else if (ty0 == '{' || ty0 == 'v' || ty0 == '[') && ty1 == 'c' || ty0 == 'c' && (ty1 == '}' || ty1 == 'v' || ty1 == ']') {
421 return 1;
422 } else {
423 return 0;
424 };
425}
426
427pub fn count_vec(s: &[SpiroSegment], nseg: isize) -> isize {
428 let mut i = 0;
429 let mut n: isize = 0;
430 while i < nseg as usize {
431 n += compute_jinc(s[i].ty, s[i + 1].ty);
432 i += 1
433 }
434 return n;
435}
436
437pub fn add_mat_line(m: &mut [BandMath], v: &mut [f64], derivs: &mut [f64], x: f64, y: f64, j: isize, jj: isize, jinc: isize, nmat: isize) {
438 let mut k: isize = 0;
439 if jj >= 0 {
440 let joff: isize = (j + 5 - jj + nmat) % nmat;
441 v[jj as usize] += x;
442 while k < jinc {
443 m[jj as usize].a[(joff + k) as usize] += y * derivs[k as usize];
444 k += 1
445 }
446 };
447}
448
449pub fn spiro_iter(s: &mut [SpiroSegment], m: &mut [BandMath], perm: &mut [isize], v: &mut [f64], n: isize) -> f64 {
450 let cyclic = s[0].ty != '{' && s[0].ty != 'v';
451 let mut i: isize = 0;
452 let mut j: isize;
453 let mut jj: isize;
454 let nmat: isize = count_vec(s, n);
455 let mut norm: f64;
456 let n_invert: isize;
457 while i < nmat {
458 v[i as usize] = 0.0;
459 j = 0;
460 while j < 11 {
461 m[i as usize].a[j as usize] = 0.0;
462 j += 1
463 }
464 j = 0;
465 while j < 5 {
466 m[i as usize].al[j as usize] = 0.0;
467 j += 1
468 }
469 i += 1
470 }
471 j = 0;
472 if s[0].ty == 'o' {
473 jj = nmat - 2;
474 } else if s[0].ty == 'c' || s[0].ty == '[' || s[0].ty == ']' {
475 jj = nmat - 1;
476 } else {
477 jj = 0;
478 }
479 i = 0;
480 while i < n {
481 let ty0: char = s[i as usize].ty;
482 let ty1: char = s[i as usize + 1].ty;
483 let jinc: isize = compute_jinc(ty0, ty1);
484 let th: f64 = s[i as usize].bend_th;
485 let mut ends: [[f64; 4]; 2] = [[0.; 4]; 2];
486 let mut derivs: [[[f64; 4]; 2]; 4] = [[[0.; 4]; 2]; 4];
487 let mut jthl: isize = -1;
488 let mut jk0l: isize = -1;
489 let mut jk1l: isize = -1;
490 let mut jk2l: isize = -1;
491 let mut jthr: isize = -1;
492 let mut jk0r: isize = -1;
493 let mut jk1r: isize = -1;
494 let mut jk2r: isize = -1;
495 compute_pderivs(&mut s[i as usize], &mut ends, &mut derivs, jinc);
496 if ty0 == 'o' || ty0 == 'c' || ty0 == '[' || ty0 == ']' {
498 let fresh0 = jj;
499 jj = jj + 1;
500 jthl = fresh0;
501 jj %= nmat;
502 let fresh1 = jj;
503 jj = jj + 1;
504 jk0l = fresh1
505 }
506 if ty0 == 'o' {
507 jj %= nmat;
508 let fresh2 = jj;
509 jj = jj + 1;
510 jk1l = fresh2;
511 let fresh3 = jj;
512 jj = jj + 1;
513 jk2l = fresh3
514 }
515 if (ty0 == '[' || ty0 == 'v' || ty0 == '{' || ty0 == 'c') && jinc == 4 {
517 if ty0 != 'c' {
518 let fresh4 = jj;
519 jj = jj + 1;
520 jk1l = fresh4
521 }
522 let fresh5 = jj;
523 jj = jj + 1;
524 jk2l = fresh5
525 }
526 if (ty1 == ']' || ty1 == 'v' || ty1 == '}' || ty1 == 'c') && jinc == 4 {
528 if ty1 != 'c' {
529 let fresh6 = jj;
530 jj = jj + 1;
531 jk1r = fresh6
532 }
533 let fresh7 = jj;
534 jj = jj + 1;
535 jk2r = fresh7
536 }
537 if ty1 == 'o' || ty1 == 'c' || ty1 == '[' || ty1 == ']' {
539 jthr = jj;
540 jk0r = (jj + 1) % nmat
541 }
542 if ty1 == 'o' {
543 jk1r = (jj + 2) % nmat;
544 jk2r = (jj + 3) % nmat
545 }
546
547 add_mat_line(m, v, &mut derivs[0][0], th - ends[0][0], 1., j, jthl, jinc, nmat);
548 add_mat_line(m, v, &mut derivs[1][0], ends[0][1], -1., j, jk0l, jinc, nmat);
549 add_mat_line(m, v, &mut derivs[2][0], ends[0][2], -1., j, jk1l, jinc, nmat);
550 add_mat_line(m, v, &mut derivs[3][0], ends[0][3], -1., j, jk2l, jinc, nmat);
551 add_mat_line(m, v, &mut derivs[0][1], -ends[1][0], 1., j, jthr, jinc, nmat);
552 add_mat_line(m, v, &mut derivs[1][1], -ends[1][1], 1., j, jk0r, jinc, nmat);
553 add_mat_line(m, v, &mut derivs[2][1], -ends[1][2], 1., j, jk1r, jinc, nmat);
554 add_mat_line(m, v, &mut derivs[3][1], -ends[1][3], 1., j, jk2r, jinc, nmat);
555
556 j += jinc;
557 i += 1
558 }
559 if cyclic {
560 let u_nmat: usize = nmat.try_into().unwrap();
561 m.copy_within(..u_nmat, u_nmat);
562 m.copy_within(..u_nmat, 2 * u_nmat);
563 v.copy_within(..u_nmat, u_nmat);
564 v.copy_within(..u_nmat, 2 * u_nmat);
565 n_invert = 3 * nmat;
566 j = nmat
567 } else {
568 n_invert = nmat;
569 j = 0
570 }
571 bandec11(m, perm, n_invert);
572 banbks11(m, perm, v, n_invert);
573 norm = 0.0;
574 i = 0;
575 while i < n {
576 let ty0_0: char = s[i as usize].ty;
577 let ty1_0: char = s[(i + 1) as usize].ty;
578 let jinc_0: isize = compute_jinc(ty0_0, ty1_0);
579 let mut k: isize = 0;
580 while k < jinc_0 {
581 let fresh8 = j;
582 j = j + 1;
583 let dk: f64 = v[fresh8 as usize];
584 s[i as usize].ks[k as usize] += dk;
585 norm += dk * dk;
586 k += 1
587 }
588 i += 1
589 }
590 return norm;
591}
592
593pub fn solve_spiro(s: &mut [SpiroSegment], nseg: isize) -> isize {
594 let nmat: isize = count_vec(s, nseg);
595 let mut n_alloc: usize = nmat.try_into().unwrap();
596 let mut norm: f64;
597 let mut i: isize;
598 if nmat == 0 {
599 return 0;
600 }
601 if s[0].ty != '{' && s[0].ty != 'v' {
602 n_alloc *= 3
603 }
604 if n_alloc < 5 {
605 n_alloc = 5
606 }
607
608 let mut m = vec![BandMath::default(); n_alloc];
609 let mut v = vec![0.0; n_alloc];
610 let mut perm = vec![0; n_alloc];
611
612 i = 0;
613 while i < 10 {
614 norm = spiro_iter(s, &mut m, &mut perm, &mut v, nseg);
615 if norm < 1e-12 {
616 break;
617 }
618 i += 1
619 }
620
621 return 0;
622}
623
624pub fn spiro_seg_to_bpath<T>(ks: [f64; 4], x0: f64, y0: f64, x1: f64, y1: f64, bc: &mut BezierContext<T>, depth: isize) {
625 let bend: f64 = (ks[0]).abs() + (0.5 * ks[1]).abs() + (0.125 * ks[2]).abs() + (1.0 / 48. * ks[3]).abs();
626 if bend == 0. {
627 bc.line_to(x1, y1);
628 } else {
629 let seg_ch: f64 = (x1 - x0).hypot(y1 - y0);
630 let seg_th: f64 = (y1 - y0).atan2(x1 - x0);
631 let mut xy: [f64; 2] = [0.; 2];
632 let ch: f64;
633 let th: f64;
634 let scale: f64;
635 let rot: f64;
636 let th_even: f64;
637 let th_odd: f64;
638 let ul: f64;
639 let vl: f64;
640 let ur: f64;
641 let vr: f64;
642 integrate_spiro(ks, &mut xy);
643 ch = xy[0].hypot(xy[1]);
644 th = xy[1].atan2(xy[0]);
645 scale = seg_ch / ch;
646 rot = seg_th - th;
647 if depth > 5 || bend < 1.0 {
648 th_even = 1.0 / 384. * ks[3] + 1.0 / 8. * ks[1] + rot;
649 th_odd = 1.0 / 48. * ks[2] + 0.5 * ks[0];
650 ul = scale * (1.0 / 3.) * (th_even - th_odd).cos();
651 vl = scale * (1.0 / 3.) * (th_even - th_odd).sin();
652 ur = scale * (1.0 / 3.) * (th_even + th_odd).cos();
653 vr = scale * (1.0 / 3.) * (th_even + th_odd).sin();
654 bc.curve_to(x0 + ul, y0 + vl, x1 - ur, y1 - vr, x1, y1);
655 } else {
656 let mut ksub: [f64; 4] = [0.; 4];
658 let thsub: f64;
659 let mut xysub: [f64; 2] = [0.; 2];
660 let xmid: f64;
661 let ymid: f64;
662 let cth: f64;
663 let sth: f64;
664 ksub[0] = 0.5 * ks[0] - 0.125 * ks[1] + 1.0 / 64. * ks[2] - 1.0 / 768. * ks[3];
665 ksub[1] = 0.25 * ks[1] - 1.0 / 16. * ks[2] + 1.0 / 128. * ks[3];
666 ksub[2] = 0.125 * ks[2] - 1.0 / 32. * ks[3];
667 ksub[3] = 1.0 / 16. * ks[3];
668 thsub = rot - 0.25 * ks[0] + 1.0 / 32. * ks[1] - 1.0 / 384. * ks[2] + 1.0 / 6144. * ks[3];
669 cth = 0.5 * scale * (thsub).cos();
670 sth = 0.5 * scale * (thsub).sin();
671 integrate_spiro(ksub, &mut xysub);
672 xmid = x0 + cth * xysub[0] - sth * xysub[1];
673 ymid = y0 + cth * xysub[1] + sth * xysub[0];
674 spiro_seg_to_bpath(ksub, x0, y0, xmid, ymid, bc, depth + 1);
675 ksub[0] += 0.25 * ks[1] + 1.0 / 384. * ks[3];
676 ksub[1] += 0.125 * ks[2];
677 ksub[2] += 1.0 / 16. * ks[3];
678 spiro_seg_to_bpath(ksub, xmid, ymid, x1, y1, bc, depth + 1);
679 }
680 };
681}
682
683pub fn spiro_to_bpath<T>(s: &[SpiroSegment], n: isize, bc: &mut BezierContext<T>) {
684 if n == 0 {
685 return;
686 }
687 let mut i = 0;
688 let nsegs: isize = if s[(n - 1) as usize].ty == '}' { (n) - 1 } else { n };
689 while i < nsegs {
690 let x0: f64 = s[i as usize].x;
691 let y0: f64 = s[i as usize].y;
692 let x1: f64 = s[(i + 1) as usize].x;
693 let y1: f64 = s[(i + 1) as usize].y;
694 if i == 0 {
695 bc.move_to(x0, y0, s[0 as usize].ty == '{');
696 }
697 bc.mark_knot(i.try_into().unwrap());
698 spiro_seg_to_bpath(s[i as usize].ks, x0, y0, x1, y1, bc, 0);
699 i += 1
700 }
701}
702
703pub fn get_knot_th(s: &[SpiroSegment], i: isize) -> f64 {
704 let mut ends: [[f64; 4]; 2] = [[0.; 4]; 2];
705 if i == 0 {
706 compute_ends(s[i as usize].ks, &mut ends, s[i as usize].seg_ch);
707 return s[i as usize].seg_th - ends[0][0];
708 } else {
709 compute_ends(s[(i - 1) as usize].ks, &mut ends, s[(i - 1) as usize].seg_ch);
710 return s[(i - 1) as usize].seg_th + ends[1][0];
711 };
712}
713
714pub fn run_spiro(path: &mut [SpiroCP]) -> Vec<Operation> {
715 let path_len = path.len().try_into().unwrap();
716 let mut ctx: BezierContext<Vec<Operation>> = BezierContext::new();
717 let mut segs = setup_path(path);
718 solve_spiro(&mut segs, path_len);
719
720 spiro_to_bpath(&mut segs, path_len, &mut ctx);
721 ctx.data.unwrap_or(vec![])
722}