UNPKG

6.94 kBJavaScriptView Raw
1import { cubicSubdivide } from '../core/curve.js';
2import PathProxy from '../core/PathProxy.js';
3var CMD = PathProxy.CMD;
4function aroundEqual(a, b) {
5 return Math.abs(a - b) < 1e-5;
6}
7export function pathToBezierCurves(path) {
8 var data = path.data;
9 var len = path.len();
10 var bezierArrayGroups = [];
11 var currentSubpath;
12 var xi = 0;
13 var yi = 0;
14 var x0 = 0;
15 var y0 = 0;
16 function createNewSubpath(x, y) {
17 if (currentSubpath && currentSubpath.length > 2) {
18 bezierArrayGroups.push(currentSubpath);
19 }
20 currentSubpath = [x, y];
21 }
22 function addLine(x0, y0, x1, y1) {
23 if (!(aroundEqual(x0, x1) && aroundEqual(y0, y1))) {
24 currentSubpath.push(x0, y0, x1, y1, x1, y1);
25 }
26 }
27 function addArc(startAngle, endAngle, cx, cy, rx, ry) {
28 var delta = Math.abs(endAngle - startAngle);
29 var len = Math.tan(delta / 4) * 4 / 3;
30 var dir = endAngle < startAngle ? -1 : 1;
31 var c1 = Math.cos(startAngle);
32 var s1 = Math.sin(startAngle);
33 var c2 = Math.cos(endAngle);
34 var s2 = Math.sin(endAngle);
35 var x1 = c1 * rx + cx;
36 var y1 = s1 * ry + cy;
37 var x4 = c2 * rx + cx;
38 var y4 = s2 * ry + cy;
39 var hx = rx * len * dir;
40 var hy = ry * len * dir;
41 currentSubpath.push(x1 - hx * s1, y1 + hy * c1, x4 + hx * s2, y4 - hy * c2, x4, y4);
42 }
43 var x1;
44 var y1;
45 var x2;
46 var y2;
47 for (var i = 0; i < len;) {
48 var cmd = data[i++];
49 var isFirst = i === 1;
50 if (isFirst) {
51 xi = data[i];
52 yi = data[i + 1];
53 x0 = xi;
54 y0 = yi;
55 if (cmd === CMD.L || cmd === CMD.C || cmd === CMD.Q) {
56 currentSubpath = [x0, y0];
57 }
58 }
59 switch (cmd) {
60 case CMD.M:
61 xi = x0 = data[i++];
62 yi = y0 = data[i++];
63 createNewSubpath(x0, y0);
64 break;
65 case CMD.L:
66 x1 = data[i++];
67 y1 = data[i++];
68 addLine(xi, yi, x1, y1);
69 xi = x1;
70 yi = y1;
71 break;
72 case CMD.C:
73 currentSubpath.push(data[i++], data[i++], data[i++], data[i++], xi = data[i++], yi = data[i++]);
74 break;
75 case CMD.Q:
76 x1 = data[i++];
77 y1 = data[i++];
78 x2 = data[i++];
79 y2 = data[i++];
80 currentSubpath.push(xi + 2 / 3 * (x1 - xi), yi + 2 / 3 * (y1 - yi), x2 + 2 / 3 * (x1 - x2), y2 + 2 / 3 * (y1 - y2), x2, y2);
81 xi = x2;
82 yi = y2;
83 break;
84 case CMD.A:
85 var cx = data[i++];
86 var cy = data[i++];
87 var rx = data[i++];
88 var ry = data[i++];
89 var startAngle = data[i++];
90 var endAngle = data[i++] + startAngle;
91 i += 1;
92 var anticlockwise = !data[i++];
93 x1 = Math.cos(startAngle) * rx + cx;
94 y1 = Math.sin(startAngle) * ry + cy;
95 if (isFirst) {
96 x0 = x1;
97 y0 = y1;
98 createNewSubpath(x0, y0);
99 }
100 else {
101 addLine(xi, yi, x1, y1);
102 }
103 xi = Math.cos(endAngle) * rx + cx;
104 yi = Math.sin(endAngle) * ry + cy;
105 var step = (anticlockwise ? -1 : 1) * Math.PI / 2;
106 for (var angle = startAngle; anticlockwise ? angle > endAngle : angle < endAngle; angle += step) {
107 var nextAngle = anticlockwise ? Math.max(angle + step, endAngle)
108 : Math.min(angle + step, endAngle);
109 addArc(angle, nextAngle, cx, cy, rx, ry);
110 }
111 break;
112 case CMD.R:
113 x0 = xi = data[i++];
114 y0 = yi = data[i++];
115 x1 = x0 + data[i++];
116 y1 = y0 + data[i++];
117 createNewSubpath(x1, y0);
118 addLine(x1, y0, x1, y1);
119 addLine(x1, y1, x0, y1);
120 addLine(x0, y1, x0, y0);
121 addLine(x0, y0, x1, y0);
122 break;
123 case CMD.Z:
124 currentSubpath && addLine(xi, yi, x0, y0);
125 xi = x0;
126 yi = y0;
127 break;
128 }
129 }
130 if (currentSubpath && currentSubpath.length > 2) {
131 bezierArrayGroups.push(currentSubpath);
132 }
133 return bezierArrayGroups;
134}
135function adpativeBezier(x0, y0, x1, y1, x2, y2, x3, y3, out, scale) {
136 if (aroundEqual(x0, x1) && aroundEqual(y0, y1) && aroundEqual(x2, x3) && aroundEqual(y2, y3)) {
137 out.push(x3, y3);
138 return;
139 }
140 var PIXEL_DISTANCE = 2 / scale;
141 var PIXEL_DISTANCE_SQR = PIXEL_DISTANCE * PIXEL_DISTANCE;
142 var dx = x3 - x0;
143 var dy = y3 - y0;
144 var d = Math.sqrt(dx * dx + dy * dy);
145 dx /= d;
146 dy /= d;
147 var dx1 = x1 - x0;
148 var dy1 = y1 - y0;
149 var dx2 = x2 - x3;
150 var dy2 = y2 - y3;
151 var cp1LenSqr = dx1 * dx1 + dy1 * dy1;
152 var cp2LenSqr = dx2 * dx2 + dy2 * dy2;
153 if (cp1LenSqr < PIXEL_DISTANCE_SQR && cp2LenSqr < PIXEL_DISTANCE_SQR) {
154 out.push(x3, y3);
155 return;
156 }
157 var projLen1 = dx * dx1 + dy * dy1;
158 var projLen2 = -dx * dx2 - dy * dy2;
159 var d1Sqr = cp1LenSqr - projLen1 * projLen1;
160 var d2Sqr = cp2LenSqr - projLen2 * projLen2;
161 if (d1Sqr < PIXEL_DISTANCE_SQR && projLen1 >= 0
162 && d2Sqr < PIXEL_DISTANCE_SQR && projLen2 >= 0) {
163 out.push(x3, y3);
164 return;
165 }
166 var tmpSegX = [];
167 var tmpSegY = [];
168 cubicSubdivide(x0, x1, x2, x3, 0.5, tmpSegX);
169 cubicSubdivide(y0, y1, y2, y3, 0.5, tmpSegY);
170 adpativeBezier(tmpSegX[0], tmpSegY[0], tmpSegX[1], tmpSegY[1], tmpSegX[2], tmpSegY[2], tmpSegX[3], tmpSegY[3], out, scale);
171 adpativeBezier(tmpSegX[4], tmpSegY[4], tmpSegX[5], tmpSegY[5], tmpSegX[6], tmpSegY[6], tmpSegX[7], tmpSegY[7], out, scale);
172}
173export function pathToPolygons(path, scale) {
174 var bezierArrayGroups = pathToBezierCurves(path);
175 var polygons = [];
176 scale = scale || 1;
177 for (var i = 0; i < bezierArrayGroups.length; i++) {
178 var beziers = bezierArrayGroups[i];
179 var polygon = [];
180 var x0 = beziers[0];
181 var y0 = beziers[1];
182 polygon.push(x0, y0);
183 for (var k = 2; k < beziers.length;) {
184 var x1 = beziers[k++];
185 var y1 = beziers[k++];
186 var x2 = beziers[k++];
187 var y2 = beziers[k++];
188 var x3 = beziers[k++];
189 var y3 = beziers[k++];
190 adpativeBezier(x0, y0, x1, y1, x2, y2, x3, y3, polygon, scale);
191 x0 = x3;
192 y0 = y3;
193 }
194 polygons.push(polygon);
195 }
196 return polygons;
197}