UNPKG

3.95 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};
38
39const findDotsAtSegment = (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) => {
40 const t1 = 1 - t;
41 const t12 = t1 * t1;
42 const t13 = t12 * t1;
43 const t2 = t * t;
44 const t3 = t2 * t;
45 const x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x;
46 const y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y;
47 return { x, y };
48};
49
50const catmullRom2bezier = (crp, z) => {
51 const d = [];
52 let end = { x: +crp[0], y: +crp[1] };
53 for (let i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) {
54 const p = [
55 { x: +crp[i - 2], y: +crp[i - 1] },
56 { x: +crp[i], y: +crp[i + 1] },
57 { x: +crp[i + 2], y: +crp[i + 3] },
58 { x: +crp[i + 4], y: +crp[i + 5] },
59 ];
60 if (z) {
61 if (!i) {
62 p[0] = { x: +crp[iLen - 2], y: +crp[iLen - 1] };
63 } else if (iLen - 4 === i) {
64 p[3] = { x: +crp[0], y: +crp[1] };
65 } else if (iLen - 2 === i) {
66 p[2] = { x: +crp[0], y: +crp[1] };
67 p[3] = { x: +crp[2], y: +crp[3] };
68 }
69 } else if (iLen - 4 === i) {
70 p[3] = p[2];
71 } else if (!i) {
72 p[0] = { x: +crp[i], y: +crp[i + 1] };
73 }
74 d.push([
75 end.x,
76 end.y,
77 (-p[0].x + 6 * p[1].x + p[2].x) / 6,
78 (-p[0].y + 6 * p[1].y + p[2].y) / 6,
79 (p[1].x + 6 * p[2].x - p[3].x) / 6,
80 (p[1].y + 6 * p[2].y - p[3].y) / 6,
81 p[2].x,
82 p[2].y,
83 ]);
84 end = p[2];
85 }
86
87 return d;
88};
89
90const bezlen2 = (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) => {
91 const n = 5;
92 let x0 = p1x;
93 let y0 = p1y;
94 let len = 0;
95 for (let i = 1; i < n; i++) {
96 const { x, y } = findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / n);
97 len += Math.hypot(x - x0, y - y0);
98 x0 = x;
99 y0 = y;
100 }
101 len += Math.hypot(p2x - x0, p2y - y0);
102 return len;
103};
104
105const prepareCurve = (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) => {
106 const len = Math.floor(bezlen2(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) * .75);
107 const fs = [];
108 let oldi = 0;
109 for (let i = 0; i <= len; i++) {
110 const t = i / len;
111 const xy = findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t);
112 const index = Math.round(xy.x);
113 fs[index] = xy.y;
114 if (index - oldi > 1) {
115 const s = fs[oldi];
116 const f = fs[index];
117 for (let j = oldi + 1; j < index; j++) {
118 fs[j] = s + ((f - s) / (index - oldi)) * (j - oldi);
119 }
120 }
121 oldi = index;
122 }
123 return (x) => fs[Math.round(x)] || null;
124};
125
126
127export {
128 bezlen,
129 findDotsAtSegment,
130 prepareCurve,
131 catmullRom2bezier
132};
133