UNPKG

3.94 kBJavaScriptView Raw
1/*
2Copyright 2019 Adobe. All rights reserved.
3This file is licensed to you under the Apache License, Version 2.0 (the "License");
4you may not use this file except in compliance with the License. You may obtain a copy
5of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7Unless required by applicable law or agreed to in writing, software distributed under
8the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9OF ANY KIND, either express or implied. See the License for the specific language
10governing permissions and limitations under the License.
11*/
12
13const base3 = (t, p1, p2, p3, p4) => {
14 const t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4;
15 const t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
16 return t * t2 - 3 * p1 + 3 * p2;
17};
18
19const bezlen = (x1, y1, x2, y2, x3, y3, x4, y4, z) => {
20 if (z == null) {
21 z = 1;
22 }
23 z = Math.max(0, Math.min(z, 1));
24 const z2 = z / 2;
25 const n = 12;
26 const Tvalues = [-.1252, .1252, -.3678, .3678, -.5873, .5873, -.7699, .7699, -.9041, .9041, -.9816, .9816];
27 const Cvalues = [0.2491, 0.2491, 0.2335, 0.2335, 0.2032, 0.2032, 0.1601, 0.1601, 0.1069, 0.1069, 0.0472, 0.0472];
28 let sum = 0;
29 for (let i = 0; i < n; i++) {
30 const ct = z2 * Tvalues[i] + z2;
31 const xbase = base3(ct, x1, x2, x3, x4);
32 const ybase = base3(ct, y1, y2, y3, y4);
33 const comb = xbase * xbase + ybase * ybase;
34 sum += Cvalues[i] * Math.sqrt(comb);
35 }
36 return z2 * sum;
37};
38exports.bezlen = bezlen;
39
40const findDotsAtSegment = (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) => {
41 const t1 = 1 - t;
42 const t12 = t1 * t1;
43 const t13 = t12 * t1;
44 const t2 = t * t;
45 const t3 = t2 * t;
46 const x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x;
47 const y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y;
48 return { x, y };
49};
50exports.findDotsAtSegment = findDotsAtSegment;
51
52exports.catmullRom2bezier = (crp, z) => {
53 const d = [];
54 let end = { x: +crp[0], y: +crp[1] };
55 for (let i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
56 const p = [
57 { x: +crp[i - 2], y: +crp[i - 1] },
58 { x: +crp[i], y: +crp[i + 1] },
59 { x: +crp[i + 2], y: +crp[i + 3] },
60 { x: +crp[i + 4], y: +crp[i + 5] },
61 ];
62 if (z) {
63 if (!i) {
64 p[0] = { x: +crp[iLen - 2], y: +crp[iLen - 1] };
65 } else if (iLen - 4 === i) {
66 p[3] = { x: +crp[0], y: +crp[1] };
67 } else if (iLen - 2 === i) {
68 p[2] = { x: +crp[0], y: +crp[1] };
69 p[3] = { x: +crp[2], y: +crp[3] };
70 }
71 } else if (iLen - 4 === i) {
72 p[3] = p[2];
73 } else if (!i) {
74 p[0] = { x: +crp[i], y: +crp[i + 1] };
75 }
76 d.push([
77 end.x,
78 end.y,
79 (-p[0].x + 6 * p[1].x + p[2].x) / 6,
80 (-p[0].y + 6 * p[1].y + p[2].y) / 6,
81 (p[1].x + 6 * p[2].x - p[3].x) / 6,
82 (p[1].y + 6 * p[2].y - p[3].y) / 6,
83 p[2].x,
84 p[2].y,
85 ]);
86 end = p[2];
87 }
88
89 return d;
90};
91
92const bezlen2 = (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) => {
93 const n = 5;
94 let x0 = p1x;
95 let y0 = p1y;
96 let len = 0;
97 for (let i = 1; i < n; i++) {
98 const { x, y } = findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / n);
99 len += Math.hypot(x - x0, y - y0);
100 x0 = x;
101 y0 = y;
102 }
103 len += Math.hypot(p2x - x0, p2y - y0);
104 return len;
105};
106
107exports.prepareCurve = (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) => {
108 const len = Math.floor(bezlen2(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) * .75);
109 const fs = [];
110 let oldi = 0;
111 for (let i = 0; i <= len; i++) {
112 const t = i / len;
113 const xy = findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t);
114 const index = Math.round(xy.x);
115 fs[index] = xy.y;
116 if (index - oldi > 1) {
117 const s = fs[oldi];
118 const f = fs[index];
119 for (let j = oldi + 1; j < index; j++) {
120 fs[j] = s + ((f - s) / (index - oldi)) * (j - oldi);
121 }
122 }
123 oldi = index;
124 }
125 return (x) => fs[Math.round(x)] || null;
126};