[d565449] | 1 | "use strict";
|
---|
| 2 | Object.defineProperty(exports, "__esModule", { value: true });
|
---|
| 3 | exports.Path = void 0;
|
---|
| 4 | const Factory_1 = require("../Factory");
|
---|
| 5 | const Shape_1 = require("../Shape");
|
---|
| 6 | const Global_1 = require("../Global");
|
---|
| 7 | const BezierFunctions_1 = require("../BezierFunctions");
|
---|
| 8 | class Path extends Shape_1.Shape {
|
---|
| 9 | constructor(config) {
|
---|
| 10 | super(config);
|
---|
| 11 | this.dataArray = [];
|
---|
| 12 | this.pathLength = 0;
|
---|
| 13 | this._readDataAttribute();
|
---|
| 14 | this.on('dataChange.konva', function () {
|
---|
| 15 | this._readDataAttribute();
|
---|
| 16 | });
|
---|
| 17 | }
|
---|
| 18 | _readDataAttribute() {
|
---|
| 19 | this.dataArray = Path.parsePathData(this.data());
|
---|
| 20 | this.pathLength = Path.getPathLength(this.dataArray);
|
---|
| 21 | }
|
---|
| 22 | _sceneFunc(context) {
|
---|
| 23 | var ca = this.dataArray;
|
---|
| 24 | context.beginPath();
|
---|
| 25 | var isClosed = false;
|
---|
| 26 | for (var n = 0; n < ca.length; n++) {
|
---|
| 27 | var c = ca[n].command;
|
---|
| 28 | var p = ca[n].points;
|
---|
| 29 | switch (c) {
|
---|
| 30 | case 'L':
|
---|
| 31 | context.lineTo(p[0], p[1]);
|
---|
| 32 | break;
|
---|
| 33 | case 'M':
|
---|
| 34 | context.moveTo(p[0], p[1]);
|
---|
| 35 | break;
|
---|
| 36 | case 'C':
|
---|
| 37 | context.bezierCurveTo(p[0], p[1], p[2], p[3], p[4], p[5]);
|
---|
| 38 | break;
|
---|
| 39 | case 'Q':
|
---|
| 40 | context.quadraticCurveTo(p[0], p[1], p[2], p[3]);
|
---|
| 41 | break;
|
---|
| 42 | case 'A':
|
---|
| 43 | var cx = p[0], cy = p[1], rx = p[2], ry = p[3], theta = p[4], dTheta = p[5], psi = p[6], fs = p[7];
|
---|
| 44 | var r = rx > ry ? rx : ry;
|
---|
| 45 | var scaleX = rx > ry ? 1 : rx / ry;
|
---|
| 46 | var scaleY = rx > ry ? ry / rx : 1;
|
---|
| 47 | context.translate(cx, cy);
|
---|
| 48 | context.rotate(psi);
|
---|
| 49 | context.scale(scaleX, scaleY);
|
---|
| 50 | context.arc(0, 0, r, theta, theta + dTheta, 1 - fs);
|
---|
| 51 | context.scale(1 / scaleX, 1 / scaleY);
|
---|
| 52 | context.rotate(-psi);
|
---|
| 53 | context.translate(-cx, -cy);
|
---|
| 54 | break;
|
---|
| 55 | case 'z':
|
---|
| 56 | isClosed = true;
|
---|
| 57 | context.closePath();
|
---|
| 58 | break;
|
---|
| 59 | }
|
---|
| 60 | }
|
---|
| 61 | if (!isClosed && !this.hasFill()) {
|
---|
| 62 | context.strokeShape(this);
|
---|
| 63 | }
|
---|
| 64 | else {
|
---|
| 65 | context.fillStrokeShape(this);
|
---|
| 66 | }
|
---|
| 67 | }
|
---|
| 68 | getSelfRect() {
|
---|
| 69 | var points = [];
|
---|
| 70 | this.dataArray.forEach(function (data) {
|
---|
| 71 | if (data.command === 'A') {
|
---|
| 72 | var start = data.points[4];
|
---|
| 73 | var dTheta = data.points[5];
|
---|
| 74 | var end = data.points[4] + dTheta;
|
---|
| 75 | var inc = Math.PI / 180.0;
|
---|
| 76 | if (Math.abs(start - end) < inc) {
|
---|
| 77 | inc = Math.abs(start - end);
|
---|
| 78 | }
|
---|
| 79 | if (dTheta < 0) {
|
---|
| 80 | for (let t = start - inc; t > end; t -= inc) {
|
---|
| 81 | const point = Path.getPointOnEllipticalArc(data.points[0], data.points[1], data.points[2], data.points[3], t, 0);
|
---|
| 82 | points.push(point.x, point.y);
|
---|
| 83 | }
|
---|
| 84 | }
|
---|
| 85 | else {
|
---|
| 86 | for (let t = start + inc; t < end; t += inc) {
|
---|
| 87 | const point = Path.getPointOnEllipticalArc(data.points[0], data.points[1], data.points[2], data.points[3], t, 0);
|
---|
| 88 | points.push(point.x, point.y);
|
---|
| 89 | }
|
---|
| 90 | }
|
---|
| 91 | }
|
---|
| 92 | else if (data.command === 'C') {
|
---|
| 93 | for (let t = 0.0; t <= 1; t += 0.01) {
|
---|
| 94 | const point = Path.getPointOnCubicBezier(t, data.start.x, data.start.y, data.points[0], data.points[1], data.points[2], data.points[3], data.points[4], data.points[5]);
|
---|
| 95 | points.push(point.x, point.y);
|
---|
| 96 | }
|
---|
| 97 | }
|
---|
| 98 | else {
|
---|
| 99 | points = points.concat(data.points);
|
---|
| 100 | }
|
---|
| 101 | });
|
---|
| 102 | var minX = points[0];
|
---|
| 103 | var maxX = points[0];
|
---|
| 104 | var minY = points[1];
|
---|
| 105 | var maxY = points[1];
|
---|
| 106 | var x, y;
|
---|
| 107 | for (var i = 0; i < points.length / 2; i++) {
|
---|
| 108 | x = points[i * 2];
|
---|
| 109 | y = points[i * 2 + 1];
|
---|
| 110 | if (!isNaN(x)) {
|
---|
| 111 | minX = Math.min(minX, x);
|
---|
| 112 | maxX = Math.max(maxX, x);
|
---|
| 113 | }
|
---|
| 114 | if (!isNaN(y)) {
|
---|
| 115 | minY = Math.min(minY, y);
|
---|
| 116 | maxY = Math.max(maxY, y);
|
---|
| 117 | }
|
---|
| 118 | }
|
---|
| 119 | return {
|
---|
| 120 | x: minX,
|
---|
| 121 | y: minY,
|
---|
| 122 | width: maxX - minX,
|
---|
| 123 | height: maxY - minY,
|
---|
| 124 | };
|
---|
| 125 | }
|
---|
| 126 | getLength() {
|
---|
| 127 | return this.pathLength;
|
---|
| 128 | }
|
---|
| 129 | getPointAtLength(length) {
|
---|
| 130 | return Path.getPointAtLengthOfDataArray(length, this.dataArray);
|
---|
| 131 | }
|
---|
| 132 | static getLineLength(x1, y1, x2, y2) {
|
---|
| 133 | return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
---|
| 134 | }
|
---|
| 135 | static getPathLength(dataArray) {
|
---|
| 136 | let pathLength = 0;
|
---|
| 137 | for (var i = 0; i < dataArray.length; ++i) {
|
---|
| 138 | pathLength += dataArray[i].pathLength;
|
---|
| 139 | }
|
---|
| 140 | return pathLength;
|
---|
| 141 | }
|
---|
| 142 | static getPointAtLengthOfDataArray(length, dataArray) {
|
---|
| 143 | var point, i = 0, ii = dataArray.length;
|
---|
| 144 | if (!ii) {
|
---|
| 145 | return null;
|
---|
| 146 | }
|
---|
| 147 | while (i < ii && length > dataArray[i].pathLength) {
|
---|
| 148 | length -= dataArray[i].pathLength;
|
---|
| 149 | ++i;
|
---|
| 150 | }
|
---|
| 151 | if (i === ii) {
|
---|
| 152 | point = dataArray[i - 1].points.slice(-2);
|
---|
| 153 | return {
|
---|
| 154 | x: point[0],
|
---|
| 155 | y: point[1],
|
---|
| 156 | };
|
---|
| 157 | }
|
---|
| 158 | if (length < 0.01) {
|
---|
| 159 | point = dataArray[i].points.slice(0, 2);
|
---|
| 160 | return {
|
---|
| 161 | x: point[0],
|
---|
| 162 | y: point[1],
|
---|
| 163 | };
|
---|
| 164 | }
|
---|
| 165 | var cp = dataArray[i];
|
---|
| 166 | var p = cp.points;
|
---|
| 167 | switch (cp.command) {
|
---|
| 168 | case 'L':
|
---|
| 169 | return Path.getPointOnLine(length, cp.start.x, cp.start.y, p[0], p[1]);
|
---|
| 170 | case 'C':
|
---|
| 171 | return Path.getPointOnCubicBezier((0, BezierFunctions_1.t2length)(length, Path.getPathLength(dataArray), (i) => {
|
---|
| 172 | return (0, BezierFunctions_1.getCubicArcLength)([cp.start.x, p[0], p[2], p[4]], [cp.start.y, p[1], p[3], p[5]], i);
|
---|
| 173 | }), cp.start.x, cp.start.y, p[0], p[1], p[2], p[3], p[4], p[5]);
|
---|
| 174 | case 'Q':
|
---|
| 175 | return Path.getPointOnQuadraticBezier((0, BezierFunctions_1.t2length)(length, Path.getPathLength(dataArray), (i) => {
|
---|
| 176 | return (0, BezierFunctions_1.getQuadraticArcLength)([cp.start.x, p[0], p[2]], [cp.start.y, p[1], p[3]], i);
|
---|
| 177 | }), cp.start.x, cp.start.y, p[0], p[1], p[2], p[3]);
|
---|
| 178 | case 'A':
|
---|
| 179 | var cx = p[0], cy = p[1], rx = p[2], ry = p[3], theta = p[4], dTheta = p[5], psi = p[6];
|
---|
| 180 | theta += (dTheta * length) / cp.pathLength;
|
---|
| 181 | return Path.getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi);
|
---|
| 182 | }
|
---|
| 183 | return null;
|
---|
| 184 | }
|
---|
| 185 | static getPointOnLine(dist, P1x, P1y, P2x, P2y, fromX, fromY) {
|
---|
| 186 | fromX = fromX !== null && fromX !== void 0 ? fromX : P1x;
|
---|
| 187 | fromY = fromY !== null && fromY !== void 0 ? fromY : P1y;
|
---|
| 188 | const len = this.getLineLength(P1x, P1y, P2x, P2y);
|
---|
| 189 | if (len < 1e-10) {
|
---|
| 190 | return { x: P1x, y: P1y };
|
---|
| 191 | }
|
---|
| 192 | if (P2x === P1x) {
|
---|
| 193 | return { x: fromX, y: fromY + (P2y > P1y ? dist : -dist) };
|
---|
| 194 | }
|
---|
| 195 | const m = (P2y - P1y) / (P2x - P1x);
|
---|
| 196 | const run = Math.sqrt((dist * dist) / (1 + m * m)) * (P2x < P1x ? -1 : 1);
|
---|
| 197 | const rise = m * run;
|
---|
| 198 | if (Math.abs(fromY - P1y - m * (fromX - P1x)) < 1e-10) {
|
---|
| 199 | return { x: fromX + run, y: fromY + rise };
|
---|
| 200 | }
|
---|
| 201 | const u = ((fromX - P1x) * (P2x - P1x) + (fromY - P1y) * (P2y - P1y)) / (len * len);
|
---|
| 202 | const ix = P1x + u * (P2x - P1x);
|
---|
| 203 | const iy = P1y + u * (P2y - P1y);
|
---|
| 204 | const pRise = this.getLineLength(fromX, fromY, ix, iy);
|
---|
| 205 | const pRun = Math.sqrt(dist * dist - pRise * pRise);
|
---|
| 206 | const adjustedRun = Math.sqrt((pRun * pRun) / (1 + m * m)) * (P2x < P1x ? -1 : 1);
|
---|
| 207 | const adjustedRise = m * adjustedRun;
|
---|
| 208 | return { x: ix + adjustedRun, y: iy + adjustedRise };
|
---|
| 209 | }
|
---|
| 210 | static getPointOnCubicBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y, P4x, P4y) {
|
---|
| 211 | function CB1(t) {
|
---|
| 212 | return t * t * t;
|
---|
| 213 | }
|
---|
| 214 | function CB2(t) {
|
---|
| 215 | return 3 * t * t * (1 - t);
|
---|
| 216 | }
|
---|
| 217 | function CB3(t) {
|
---|
| 218 | return 3 * t * (1 - t) * (1 - t);
|
---|
| 219 | }
|
---|
| 220 | function CB4(t) {
|
---|
| 221 | return (1 - t) * (1 - t) * (1 - t);
|
---|
| 222 | }
|
---|
| 223 | var x = P4x * CB1(pct) + P3x * CB2(pct) + P2x * CB3(pct) + P1x * CB4(pct);
|
---|
| 224 | var y = P4y * CB1(pct) + P3y * CB2(pct) + P2y * CB3(pct) + P1y * CB4(pct);
|
---|
| 225 | return {
|
---|
| 226 | x: x,
|
---|
| 227 | y: y,
|
---|
| 228 | };
|
---|
| 229 | }
|
---|
| 230 | static getPointOnQuadraticBezier(pct, P1x, P1y, P2x, P2y, P3x, P3y) {
|
---|
| 231 | function QB1(t) {
|
---|
| 232 | return t * t;
|
---|
| 233 | }
|
---|
| 234 | function QB2(t) {
|
---|
| 235 | return 2 * t * (1 - t);
|
---|
| 236 | }
|
---|
| 237 | function QB3(t) {
|
---|
| 238 | return (1 - t) * (1 - t);
|
---|
| 239 | }
|
---|
| 240 | var x = P3x * QB1(pct) + P2x * QB2(pct) + P1x * QB3(pct);
|
---|
| 241 | var y = P3y * QB1(pct) + P2y * QB2(pct) + P1y * QB3(pct);
|
---|
| 242 | return {
|
---|
| 243 | x: x,
|
---|
| 244 | y: y,
|
---|
| 245 | };
|
---|
| 246 | }
|
---|
| 247 | static getPointOnEllipticalArc(cx, cy, rx, ry, theta, psi) {
|
---|
| 248 | var cosPsi = Math.cos(psi), sinPsi = Math.sin(psi);
|
---|
| 249 | var pt = {
|
---|
| 250 | x: rx * Math.cos(theta),
|
---|
| 251 | y: ry * Math.sin(theta),
|
---|
| 252 | };
|
---|
| 253 | return {
|
---|
| 254 | x: cx + (pt.x * cosPsi - pt.y * sinPsi),
|
---|
| 255 | y: cy + (pt.x * sinPsi + pt.y * cosPsi),
|
---|
| 256 | };
|
---|
| 257 | }
|
---|
| 258 | static parsePathData(data) {
|
---|
| 259 | if (!data) {
|
---|
| 260 | return [];
|
---|
| 261 | }
|
---|
| 262 | var cs = data;
|
---|
| 263 | var cc = [
|
---|
| 264 | 'm',
|
---|
| 265 | 'M',
|
---|
| 266 | 'l',
|
---|
| 267 | 'L',
|
---|
| 268 | 'v',
|
---|
| 269 | 'V',
|
---|
| 270 | 'h',
|
---|
| 271 | 'H',
|
---|
| 272 | 'z',
|
---|
| 273 | 'Z',
|
---|
| 274 | 'c',
|
---|
| 275 | 'C',
|
---|
| 276 | 'q',
|
---|
| 277 | 'Q',
|
---|
| 278 | 't',
|
---|
| 279 | 'T',
|
---|
| 280 | 's',
|
---|
| 281 | 'S',
|
---|
| 282 | 'a',
|
---|
| 283 | 'A',
|
---|
| 284 | ];
|
---|
| 285 | cs = cs.replace(new RegExp(' ', 'g'), ',');
|
---|
| 286 | for (var n = 0; n < cc.length; n++) {
|
---|
| 287 | cs = cs.replace(new RegExp(cc[n], 'g'), '|' + cc[n]);
|
---|
| 288 | }
|
---|
| 289 | var arr = cs.split('|');
|
---|
| 290 | var ca = [];
|
---|
| 291 | var coords = [];
|
---|
| 292 | var cpx = 0;
|
---|
| 293 | var cpy = 0;
|
---|
| 294 | var re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/gi;
|
---|
| 295 | var match;
|
---|
| 296 | for (n = 1; n < arr.length; n++) {
|
---|
| 297 | var str = arr[n];
|
---|
| 298 | var c = str.charAt(0);
|
---|
| 299 | str = str.slice(1);
|
---|
| 300 | coords.length = 0;
|
---|
| 301 | while ((match = re.exec(str))) {
|
---|
| 302 | coords.push(match[0]);
|
---|
| 303 | }
|
---|
| 304 | var p = [];
|
---|
| 305 | for (var j = 0, jlen = coords.length; j < jlen; j++) {
|
---|
| 306 | if (coords[j] === '00') {
|
---|
| 307 | p.push(0, 0);
|
---|
| 308 | continue;
|
---|
| 309 | }
|
---|
| 310 | var parsed = parseFloat(coords[j]);
|
---|
| 311 | if (!isNaN(parsed)) {
|
---|
| 312 | p.push(parsed);
|
---|
| 313 | }
|
---|
| 314 | else {
|
---|
| 315 | p.push(0);
|
---|
| 316 | }
|
---|
| 317 | }
|
---|
| 318 | while (p.length > 0) {
|
---|
| 319 | if (isNaN(p[0])) {
|
---|
| 320 | break;
|
---|
| 321 | }
|
---|
| 322 | var cmd = '';
|
---|
| 323 | var points = [];
|
---|
| 324 | var startX = cpx, startY = cpy;
|
---|
| 325 | var prevCmd, ctlPtx, ctlPty;
|
---|
| 326 | var rx, ry, psi, fa, fs, x1, y1;
|
---|
| 327 | switch (c) {
|
---|
| 328 | case 'l':
|
---|
| 329 | cpx += p.shift();
|
---|
| 330 | cpy += p.shift();
|
---|
| 331 | cmd = 'L';
|
---|
| 332 | points.push(cpx, cpy);
|
---|
| 333 | break;
|
---|
| 334 | case 'L':
|
---|
| 335 | cpx = p.shift();
|
---|
| 336 | cpy = p.shift();
|
---|
| 337 | points.push(cpx, cpy);
|
---|
| 338 | break;
|
---|
| 339 | case 'm':
|
---|
| 340 | var dx = p.shift();
|
---|
| 341 | var dy = p.shift();
|
---|
| 342 | cpx += dx;
|
---|
| 343 | cpy += dy;
|
---|
| 344 | cmd = 'M';
|
---|
| 345 | if (ca.length > 2 && ca[ca.length - 1].command === 'z') {
|
---|
| 346 | for (var idx = ca.length - 2; idx >= 0; idx--) {
|
---|
| 347 | if (ca[idx].command === 'M') {
|
---|
| 348 | cpx = ca[idx].points[0] + dx;
|
---|
| 349 | cpy = ca[idx].points[1] + dy;
|
---|
| 350 | break;
|
---|
| 351 | }
|
---|
| 352 | }
|
---|
| 353 | }
|
---|
| 354 | points.push(cpx, cpy);
|
---|
| 355 | c = 'l';
|
---|
| 356 | break;
|
---|
| 357 | case 'M':
|
---|
| 358 | cpx = p.shift();
|
---|
| 359 | cpy = p.shift();
|
---|
| 360 | cmd = 'M';
|
---|
| 361 | points.push(cpx, cpy);
|
---|
| 362 | c = 'L';
|
---|
| 363 | break;
|
---|
| 364 | case 'h':
|
---|
| 365 | cpx += p.shift();
|
---|
| 366 | cmd = 'L';
|
---|
| 367 | points.push(cpx, cpy);
|
---|
| 368 | break;
|
---|
| 369 | case 'H':
|
---|
| 370 | cpx = p.shift();
|
---|
| 371 | cmd = 'L';
|
---|
| 372 | points.push(cpx, cpy);
|
---|
| 373 | break;
|
---|
| 374 | case 'v':
|
---|
| 375 | cpy += p.shift();
|
---|
| 376 | cmd = 'L';
|
---|
| 377 | points.push(cpx, cpy);
|
---|
| 378 | break;
|
---|
| 379 | case 'V':
|
---|
| 380 | cpy = p.shift();
|
---|
| 381 | cmd = 'L';
|
---|
| 382 | points.push(cpx, cpy);
|
---|
| 383 | break;
|
---|
| 384 | case 'C':
|
---|
| 385 | points.push(p.shift(), p.shift(), p.shift(), p.shift());
|
---|
| 386 | cpx = p.shift();
|
---|
| 387 | cpy = p.shift();
|
---|
| 388 | points.push(cpx, cpy);
|
---|
| 389 | break;
|
---|
| 390 | case 'c':
|
---|
| 391 | points.push(cpx + p.shift(), cpy + p.shift(), cpx + p.shift(), cpy + p.shift());
|
---|
| 392 | cpx += p.shift();
|
---|
| 393 | cpy += p.shift();
|
---|
| 394 | cmd = 'C';
|
---|
| 395 | points.push(cpx, cpy);
|
---|
| 396 | break;
|
---|
| 397 | case 'S':
|
---|
| 398 | ctlPtx = cpx;
|
---|
| 399 | ctlPty = cpy;
|
---|
| 400 | prevCmd = ca[ca.length - 1];
|
---|
| 401 | if (prevCmd.command === 'C') {
|
---|
| 402 | ctlPtx = cpx + (cpx - prevCmd.points[2]);
|
---|
| 403 | ctlPty = cpy + (cpy - prevCmd.points[3]);
|
---|
| 404 | }
|
---|
| 405 | points.push(ctlPtx, ctlPty, p.shift(), p.shift());
|
---|
| 406 | cpx = p.shift();
|
---|
| 407 | cpy = p.shift();
|
---|
| 408 | cmd = 'C';
|
---|
| 409 | points.push(cpx, cpy);
|
---|
| 410 | break;
|
---|
| 411 | case 's':
|
---|
| 412 | ctlPtx = cpx;
|
---|
| 413 | ctlPty = cpy;
|
---|
| 414 | prevCmd = ca[ca.length - 1];
|
---|
| 415 | if (prevCmd.command === 'C') {
|
---|
| 416 | ctlPtx = cpx + (cpx - prevCmd.points[2]);
|
---|
| 417 | ctlPty = cpy + (cpy - prevCmd.points[3]);
|
---|
| 418 | }
|
---|
| 419 | points.push(ctlPtx, ctlPty, cpx + p.shift(), cpy + p.shift());
|
---|
| 420 | cpx += p.shift();
|
---|
| 421 | cpy += p.shift();
|
---|
| 422 | cmd = 'C';
|
---|
| 423 | points.push(cpx, cpy);
|
---|
| 424 | break;
|
---|
| 425 | case 'Q':
|
---|
| 426 | points.push(p.shift(), p.shift());
|
---|
| 427 | cpx = p.shift();
|
---|
| 428 | cpy = p.shift();
|
---|
| 429 | points.push(cpx, cpy);
|
---|
| 430 | break;
|
---|
| 431 | case 'q':
|
---|
| 432 | points.push(cpx + p.shift(), cpy + p.shift());
|
---|
| 433 | cpx += p.shift();
|
---|
| 434 | cpy += p.shift();
|
---|
| 435 | cmd = 'Q';
|
---|
| 436 | points.push(cpx, cpy);
|
---|
| 437 | break;
|
---|
| 438 | case 'T':
|
---|
| 439 | ctlPtx = cpx;
|
---|
| 440 | ctlPty = cpy;
|
---|
| 441 | prevCmd = ca[ca.length - 1];
|
---|
| 442 | if (prevCmd.command === 'Q') {
|
---|
| 443 | ctlPtx = cpx + (cpx - prevCmd.points[0]);
|
---|
| 444 | ctlPty = cpy + (cpy - prevCmd.points[1]);
|
---|
| 445 | }
|
---|
| 446 | cpx = p.shift();
|
---|
| 447 | cpy = p.shift();
|
---|
| 448 | cmd = 'Q';
|
---|
| 449 | points.push(ctlPtx, ctlPty, cpx, cpy);
|
---|
| 450 | break;
|
---|
| 451 | case 't':
|
---|
| 452 | ctlPtx = cpx;
|
---|
| 453 | ctlPty = cpy;
|
---|
| 454 | prevCmd = ca[ca.length - 1];
|
---|
| 455 | if (prevCmd.command === 'Q') {
|
---|
| 456 | ctlPtx = cpx + (cpx - prevCmd.points[0]);
|
---|
| 457 | ctlPty = cpy + (cpy - prevCmd.points[1]);
|
---|
| 458 | }
|
---|
| 459 | cpx += p.shift();
|
---|
| 460 | cpy += p.shift();
|
---|
| 461 | cmd = 'Q';
|
---|
| 462 | points.push(ctlPtx, ctlPty, cpx, cpy);
|
---|
| 463 | break;
|
---|
| 464 | case 'A':
|
---|
| 465 | rx = p.shift();
|
---|
| 466 | ry = p.shift();
|
---|
| 467 | psi = p.shift();
|
---|
| 468 | fa = p.shift();
|
---|
| 469 | fs = p.shift();
|
---|
| 470 | x1 = cpx;
|
---|
| 471 | y1 = cpy;
|
---|
| 472 | cpx = p.shift();
|
---|
| 473 | cpy = p.shift();
|
---|
| 474 | cmd = 'A';
|
---|
| 475 | points = this.convertEndpointToCenterParameterization(x1, y1, cpx, cpy, fa, fs, rx, ry, psi);
|
---|
| 476 | break;
|
---|
| 477 | case 'a':
|
---|
| 478 | rx = p.shift();
|
---|
| 479 | ry = p.shift();
|
---|
| 480 | psi = p.shift();
|
---|
| 481 | fa = p.shift();
|
---|
| 482 | fs = p.shift();
|
---|
| 483 | x1 = cpx;
|
---|
| 484 | y1 = cpy;
|
---|
| 485 | cpx += p.shift();
|
---|
| 486 | cpy += p.shift();
|
---|
| 487 | cmd = 'A';
|
---|
| 488 | points = this.convertEndpointToCenterParameterization(x1, y1, cpx, cpy, fa, fs, rx, ry, psi);
|
---|
| 489 | break;
|
---|
| 490 | }
|
---|
| 491 | ca.push({
|
---|
| 492 | command: cmd || c,
|
---|
| 493 | points: points,
|
---|
| 494 | start: {
|
---|
| 495 | x: startX,
|
---|
| 496 | y: startY,
|
---|
| 497 | },
|
---|
| 498 | pathLength: this.calcLength(startX, startY, cmd || c, points),
|
---|
| 499 | });
|
---|
| 500 | }
|
---|
| 501 | if (c === 'z' || c === 'Z') {
|
---|
| 502 | ca.push({
|
---|
| 503 | command: 'z',
|
---|
| 504 | points: [],
|
---|
| 505 | start: undefined,
|
---|
| 506 | pathLength: 0,
|
---|
| 507 | });
|
---|
| 508 | }
|
---|
| 509 | }
|
---|
| 510 | return ca;
|
---|
| 511 | }
|
---|
| 512 | static calcLength(x, y, cmd, points) {
|
---|
| 513 | var len, p1, p2, t;
|
---|
| 514 | var path = Path;
|
---|
| 515 | switch (cmd) {
|
---|
| 516 | case 'L':
|
---|
| 517 | return path.getLineLength(x, y, points[0], points[1]);
|
---|
| 518 | case 'C':
|
---|
| 519 | return (0, BezierFunctions_1.getCubicArcLength)([x, points[0], points[2], points[4]], [y, points[1], points[3], points[5]], 1);
|
---|
| 520 | case 'Q':
|
---|
| 521 | return (0, BezierFunctions_1.getQuadraticArcLength)([x, points[0], points[2]], [y, points[1], points[3]], 1);
|
---|
| 522 | case 'A':
|
---|
| 523 | len = 0.0;
|
---|
| 524 | var start = points[4];
|
---|
| 525 | var dTheta = points[5];
|
---|
| 526 | var end = points[4] + dTheta;
|
---|
| 527 | var inc = Math.PI / 180.0;
|
---|
| 528 | if (Math.abs(start - end) < inc) {
|
---|
| 529 | inc = Math.abs(start - end);
|
---|
| 530 | }
|
---|
| 531 | p1 = path.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], start, 0);
|
---|
| 532 | if (dTheta < 0) {
|
---|
| 533 | for (t = start - inc; t > end; t -= inc) {
|
---|
| 534 | p2 = path.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], t, 0);
|
---|
| 535 | len += path.getLineLength(p1.x, p1.y, p2.x, p2.y);
|
---|
| 536 | p1 = p2;
|
---|
| 537 | }
|
---|
| 538 | }
|
---|
| 539 | else {
|
---|
| 540 | for (t = start + inc; t < end; t += inc) {
|
---|
| 541 | p2 = path.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], t, 0);
|
---|
| 542 | len += path.getLineLength(p1.x, p1.y, p2.x, p2.y);
|
---|
| 543 | p1 = p2;
|
---|
| 544 | }
|
---|
| 545 | }
|
---|
| 546 | p2 = path.getPointOnEllipticalArc(points[0], points[1], points[2], points[3], end, 0);
|
---|
| 547 | len += path.getLineLength(p1.x, p1.y, p2.x, p2.y);
|
---|
| 548 | return len;
|
---|
| 549 | }
|
---|
| 550 | return 0;
|
---|
| 551 | }
|
---|
| 552 | static convertEndpointToCenterParameterization(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg) {
|
---|
| 553 | var psi = psiDeg * (Math.PI / 180.0);
|
---|
| 554 | var xp = (Math.cos(psi) * (x1 - x2)) / 2.0 + (Math.sin(psi) * (y1 - y2)) / 2.0;
|
---|
| 555 | var yp = (-1 * Math.sin(psi) * (x1 - x2)) / 2.0 +
|
---|
| 556 | (Math.cos(psi) * (y1 - y2)) / 2.0;
|
---|
| 557 | var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);
|
---|
| 558 | if (lambda > 1) {
|
---|
| 559 | rx *= Math.sqrt(lambda);
|
---|
| 560 | ry *= Math.sqrt(lambda);
|
---|
| 561 | }
|
---|
| 562 | var f = Math.sqrt((rx * rx * (ry * ry) - rx * rx * (yp * yp) - ry * ry * (xp * xp)) /
|
---|
| 563 | (rx * rx * (yp * yp) + ry * ry * (xp * xp)));
|
---|
| 564 | if (fa === fs) {
|
---|
| 565 | f *= -1;
|
---|
| 566 | }
|
---|
| 567 | if (isNaN(f)) {
|
---|
| 568 | f = 0;
|
---|
| 569 | }
|
---|
| 570 | var cxp = (f * rx * yp) / ry;
|
---|
| 571 | var cyp = (f * -ry * xp) / rx;
|
---|
| 572 | var cx = (x1 + x2) / 2.0 + Math.cos(psi) * cxp - Math.sin(psi) * cyp;
|
---|
| 573 | var cy = (y1 + y2) / 2.0 + Math.sin(psi) * cxp + Math.cos(psi) * cyp;
|
---|
| 574 | var vMag = function (v) {
|
---|
| 575 | return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
---|
| 576 | };
|
---|
| 577 | var vRatio = function (u, v) {
|
---|
| 578 | return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
|
---|
| 579 | };
|
---|
| 580 | var vAngle = function (u, v) {
|
---|
| 581 | return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v));
|
---|
| 582 | };
|
---|
| 583 | var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]);
|
---|
| 584 | var u = [(xp - cxp) / rx, (yp - cyp) / ry];
|
---|
| 585 | var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry];
|
---|
| 586 | var dTheta = vAngle(u, v);
|
---|
| 587 | if (vRatio(u, v) <= -1) {
|
---|
| 588 | dTheta = Math.PI;
|
---|
| 589 | }
|
---|
| 590 | if (vRatio(u, v) >= 1) {
|
---|
| 591 | dTheta = 0;
|
---|
| 592 | }
|
---|
| 593 | if (fs === 0 && dTheta > 0) {
|
---|
| 594 | dTheta = dTheta - 2 * Math.PI;
|
---|
| 595 | }
|
---|
| 596 | if (fs === 1 && dTheta < 0) {
|
---|
| 597 | dTheta = dTheta + 2 * Math.PI;
|
---|
| 598 | }
|
---|
| 599 | return [cx, cy, rx, ry, theta, dTheta, psi, fs];
|
---|
| 600 | }
|
---|
| 601 | }
|
---|
| 602 | exports.Path = Path;
|
---|
| 603 | Path.prototype.className = 'Path';
|
---|
| 604 | Path.prototype._attrsAffectingSize = ['data'];
|
---|
| 605 | (0, Global_1._registerNode)(Path);
|
---|
| 606 | Factory_1.Factory.addGetterSetter(Path, 'data');
|
---|