UNPKG

9.87 kBJavaScriptView Raw
1import PathProxy from '../core/PathProxy.js';
2import * as line from './line.js';
3import * as cubic from './cubic.js';
4import * as quadratic from './quadratic.js';
5import * as arc from './arc.js';
6import * as curve from '../core/curve.js';
7import windingLine from './windingLine.js';
8var CMD = PathProxy.CMD;
9var PI2 = Math.PI * 2;
10var EPSILON = 1e-4;
11function isAroundEqual(a, b) {
12 return Math.abs(a - b) < EPSILON;
13}
14var roots = [-1, -1, -1];
15var extrema = [-1, -1];
16function swapExtrema() {
17 var tmp = extrema[0];
18 extrema[0] = extrema[1];
19 extrema[1] = tmp;
20}
21function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {
22 if ((y > y0 && y > y1 && y > y2 && y > y3)
23 || (y < y0 && y < y1 && y < y2 && y < y3)) {
24 return 0;
25 }
26 var nRoots = curve.cubicRootAt(y0, y1, y2, y3, y, roots);
27 if (nRoots === 0) {
28 return 0;
29 }
30 else {
31 var w = 0;
32 var nExtrema = -1;
33 var y0_ = void 0;
34 var y1_ = void 0;
35 for (var i = 0; i < nRoots; i++) {
36 var t = roots[i];
37 var unit = (t === 0 || t === 1) ? 0.5 : 1;
38 var x_ = curve.cubicAt(x0, x1, x2, x3, t);
39 if (x_ < x) {
40 continue;
41 }
42 if (nExtrema < 0) {
43 nExtrema = curve.cubicExtrema(y0, y1, y2, y3, extrema);
44 if (extrema[1] < extrema[0] && nExtrema > 1) {
45 swapExtrema();
46 }
47 y0_ = curve.cubicAt(y0, y1, y2, y3, extrema[0]);
48 if (nExtrema > 1) {
49 y1_ = curve.cubicAt(y0, y1, y2, y3, extrema[1]);
50 }
51 }
52 if (nExtrema === 2) {
53 if (t < extrema[0]) {
54 w += y0_ < y0 ? unit : -unit;
55 }
56 else if (t < extrema[1]) {
57 w += y1_ < y0_ ? unit : -unit;
58 }
59 else {
60 w += y3 < y1_ ? unit : -unit;
61 }
62 }
63 else {
64 if (t < extrema[0]) {
65 w += y0_ < y0 ? unit : -unit;
66 }
67 else {
68 w += y3 < y0_ ? unit : -unit;
69 }
70 }
71 }
72 return w;
73 }
74}
75function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {
76 if ((y > y0 && y > y1 && y > y2)
77 || (y < y0 && y < y1 && y < y2)) {
78 return 0;
79 }
80 var nRoots = curve.quadraticRootAt(y0, y1, y2, y, roots);
81 if (nRoots === 0) {
82 return 0;
83 }
84 else {
85 var t = curve.quadraticExtremum(y0, y1, y2);
86 if (t >= 0 && t <= 1) {
87 var w = 0;
88 var y_ = curve.quadraticAt(y0, y1, y2, t);
89 for (var i = 0; i < nRoots; i++) {
90 var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;
91 var x_ = curve.quadraticAt(x0, x1, x2, roots[i]);
92 if (x_ < x) {
93 continue;
94 }
95 if (roots[i] < t) {
96 w += y_ < y0 ? unit : -unit;
97 }
98 else {
99 w += y2 < y_ ? unit : -unit;
100 }
101 }
102 return w;
103 }
104 else {
105 var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;
106 var x_ = curve.quadraticAt(x0, x1, x2, roots[0]);
107 if (x_ < x) {
108 return 0;
109 }
110 return y2 < y0 ? unit : -unit;
111 }
112 }
113}
114function windingArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y) {
115 y -= cy;
116 if (y > r || y < -r) {
117 return 0;
118 }
119 var tmp = Math.sqrt(r * r - y * y);
120 roots[0] = -tmp;
121 roots[1] = tmp;
122 var dTheta = Math.abs(startAngle - endAngle);
123 if (dTheta < 1e-4) {
124 return 0;
125 }
126 if (dTheta >= PI2 - 1e-4) {
127 startAngle = 0;
128 endAngle = PI2;
129 var dir = anticlockwise ? 1 : -1;
130 if (x >= roots[0] + cx && x <= roots[1] + cx) {
131 return dir;
132 }
133 else {
134 return 0;
135 }
136 }
137 if (startAngle > endAngle) {
138 var tmp_1 = startAngle;
139 startAngle = endAngle;
140 endAngle = tmp_1;
141 }
142 if (startAngle < 0) {
143 startAngle += PI2;
144 endAngle += PI2;
145 }
146 var w = 0;
147 for (var i = 0; i < 2; i++) {
148 var x_ = roots[i];
149 if (x_ + cx > x) {
150 var angle = Math.atan2(y, x_);
151 var dir = anticlockwise ? 1 : -1;
152 if (angle < 0) {
153 angle = PI2 + angle;
154 }
155 if ((angle >= startAngle && angle <= endAngle)
156 || (angle + PI2 >= startAngle && angle + PI2 <= endAngle)) {
157 if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {
158 dir = -dir;
159 }
160 w += dir;
161 }
162 }
163 }
164 return w;
165}
166function containPath(path, lineWidth, isStroke, x, y) {
167 var data = path.data;
168 var len = path.len();
169 var w = 0;
170 var xi = 0;
171 var yi = 0;
172 var x0 = 0;
173 var y0 = 0;
174 var x1;
175 var y1;
176 for (var i = 0; i < len;) {
177 var cmd = data[i++];
178 var isFirst = i === 1;
179 if (cmd === CMD.M && i > 1) {
180 if (!isStroke) {
181 w += windingLine(xi, yi, x0, y0, x, y);
182 }
183 }
184 if (isFirst) {
185 xi = data[i];
186 yi = data[i + 1];
187 x0 = xi;
188 y0 = yi;
189 }
190 switch (cmd) {
191 case CMD.M:
192 x0 = data[i++];
193 y0 = data[i++];
194 xi = x0;
195 yi = y0;
196 break;
197 case CMD.L:
198 if (isStroke) {
199 if (line.containStroke(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {
200 return true;
201 }
202 }
203 else {
204 w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;
205 }
206 xi = data[i++];
207 yi = data[i++];
208 break;
209 case CMD.C:
210 if (isStroke) {
211 if (cubic.containStroke(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {
212 return true;
213 }
214 }
215 else {
216 w += windingCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y) || 0;
217 }
218 xi = data[i++];
219 yi = data[i++];
220 break;
221 case CMD.Q:
222 if (isStroke) {
223 if (quadratic.containStroke(xi, yi, data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {
224 return true;
225 }
226 }
227 else {
228 w += windingQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y) || 0;
229 }
230 xi = data[i++];
231 yi = data[i++];
232 break;
233 case CMD.A:
234 var cx = data[i++];
235 var cy = data[i++];
236 var rx = data[i++];
237 var ry = data[i++];
238 var theta = data[i++];
239 var dTheta = data[i++];
240 i += 1;
241 var anticlockwise = !!(1 - data[i++]);
242 x1 = Math.cos(theta) * rx + cx;
243 y1 = Math.sin(theta) * ry + cy;
244 if (!isFirst) {
245 w += windingLine(xi, yi, x1, y1, x, y);
246 }
247 else {
248 x0 = x1;
249 y0 = y1;
250 }
251 var _x = (x - cx) * ry / rx + cx;
252 if (isStroke) {
253 if (arc.containStroke(cx, cy, ry, theta, theta + dTheta, anticlockwise, lineWidth, _x, y)) {
254 return true;
255 }
256 }
257 else {
258 w += windingArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y);
259 }
260 xi = Math.cos(theta + dTheta) * rx + cx;
261 yi = Math.sin(theta + dTheta) * ry + cy;
262 break;
263 case CMD.R:
264 x0 = xi = data[i++];
265 y0 = yi = data[i++];
266 var width = data[i++];
267 var height = data[i++];
268 x1 = x0 + width;
269 y1 = y0 + height;
270 if (isStroke) {
271 if (line.containStroke(x0, y0, x1, y0, lineWidth, x, y)
272 || line.containStroke(x1, y0, x1, y1, lineWidth, x, y)
273 || line.containStroke(x1, y1, x0, y1, lineWidth, x, y)
274 || line.containStroke(x0, y1, x0, y0, lineWidth, x, y)) {
275 return true;
276 }
277 }
278 else {
279 w += windingLine(x1, y0, x1, y1, x, y);
280 w += windingLine(x0, y1, x0, y0, x, y);
281 }
282 break;
283 case CMD.Z:
284 if (isStroke) {
285 if (line.containStroke(xi, yi, x0, y0, lineWidth, x, y)) {
286 return true;
287 }
288 }
289 else {
290 w += windingLine(xi, yi, x0, y0, x, y);
291 }
292 xi = x0;
293 yi = y0;
294 break;
295 }
296 }
297 if (!isStroke && !isAroundEqual(yi, y0)) {
298 w += windingLine(xi, yi, x0, y0, x, y) || 0;
299 }
300 return w !== 0;
301}
302export function contain(pathProxy, x, y) {
303 return containPath(pathProxy, 0, false, x, y);
304}
305export function containStroke(pathProxy, lineWidth, x, y) {
306 return containPath(pathProxy, lineWidth, true, x, y);
307}