789 lines
20 KiB
Java
789 lines
20 KiB
Java
![]() |
var Util = require('../../util/index');
|
||
|
|
||
|
var Inside = require('./inside');
|
||
|
|
||
|
var Cubic = require('../math/cubic');
|
||
|
|
||
|
var Quadratic = require('../math/quadratic');
|
||
|
|
||
|
var Ellipse = require('../math/ellipse');
|
||
|
|
||
|
var vec3 = Util.vec3;
|
||
|
var mat3 = Util.mat3;
|
||
|
var ARR_CMD = ['m', 'l', 'c', 'a', 'q', 'h', 'v', 't', 's', 'z'];
|
||
|
|
||
|
function toAbsolute(x, y, curPoint) {
|
||
|
// 获取绝对坐标
|
||
|
return {
|
||
|
x: curPoint.x + x,
|
||
|
y: curPoint.y + y
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function toSymmetry(point, center) {
|
||
|
// 点对称
|
||
|
return {
|
||
|
x: center.x + (center.x - point.x),
|
||
|
y: center.y + (center.y - point.y)
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function vMag(v) {
|
||
|
return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
|
||
|
}
|
||
|
|
||
|
function vRatio(u, v) {
|
||
|
return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
|
||
|
}
|
||
|
|
||
|
function vAngle(u, v) {
|
||
|
return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v));
|
||
|
}
|
||
|
|
||
|
function getArcParams(point1, point2, fa, fs, rx, ry, psiDeg) {
|
||
|
var psi = Util.mod(Util.toRadian(psiDeg), Math.PI * 2);
|
||
|
var x1 = point1.x;
|
||
|
var y1 = point1.y;
|
||
|
var x2 = point2.x;
|
||
|
var y2 = point2.y;
|
||
|
var xp = Math.cos(psi) * (x1 - x2) / 2.0 + Math.sin(psi) * (y1 - y2) / 2.0;
|
||
|
var yp = -1 * Math.sin(psi) * (x1 - x2) / 2.0 + Math.cos(psi) * (y1 - y2) / 2.0;
|
||
|
var lambda = xp * xp / (rx * rx) + yp * yp / (ry * ry);
|
||
|
|
||
|
if (lambda > 1) {
|
||
|
rx *= Math.sqrt(lambda);
|
||
|
ry *= Math.sqrt(lambda);
|
||
|
}
|
||
|
|
||
|
var diff = rx * rx * (yp * yp) + ry * ry * (xp * xp);
|
||
|
var f = Math.sqrt((rx * rx * (ry * ry) - diff) / diff);
|
||
|
|
||
|
if (fa === fs) {
|
||
|
f *= -1;
|
||
|
}
|
||
|
|
||
|
if (isNaN(f)) {
|
||
|
f = 0;
|
||
|
}
|
||
|
|
||
|
var cxp = f * rx * yp / ry;
|
||
|
var cyp = f * -ry * xp / rx;
|
||
|
var cx = (x1 + x2) / 2.0 + Math.cos(psi) * cxp - Math.sin(psi) * cyp;
|
||
|
var cy = (y1 + y2) / 2.0 + Math.sin(psi) * cxp + Math.cos(psi) * cyp;
|
||
|
var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]);
|
||
|
var u = [(xp - cxp) / rx, (yp - cyp) / ry];
|
||
|
var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry];
|
||
|
var dTheta = vAngle(u, v);
|
||
|
|
||
|
if (vRatio(u, v) <= -1) {
|
||
|
dTheta = Math.PI;
|
||
|
}
|
||
|
|
||
|
if (vRatio(u, v) >= 1) {
|
||
|
dTheta = 0;
|
||
|
}
|
||
|
|
||
|
if (fs === 0 && dTheta > 0) {
|
||
|
dTheta = dTheta - 2 * Math.PI;
|
||
|
}
|
||
|
|
||
|
if (fs === 1 && dTheta < 0) {
|
||
|
dTheta = dTheta + 2 * Math.PI;
|
||
|
}
|
||
|
|
||
|
return [point1, cx, cy, rx, ry, theta, dTheta, psi, fs];
|
||
|
}
|
||
|
|
||
|
var PathSegment = function PathSegment(item, preSegment, isLast) {
|
||
|
this.preSegment = preSegment;
|
||
|
this.isLast = isLast;
|
||
|
this.init(item, preSegment);
|
||
|
};
|
||
|
|
||
|
Util.augment(PathSegment, {
|
||
|
init: function init(item, preSegment) {
|
||
|
var command = item[0];
|
||
|
preSegment = preSegment || {
|
||
|
endPoint: {
|
||
|
x: 0,
|
||
|
y: 0
|
||
|
}
|
||
|
};
|
||
|
var relative = ARR_CMD.indexOf(command) >= 0; // /[a-z]/.test(command);
|
||
|
|
||
|
var cmd = relative ? command.toUpperCase() : command;
|
||
|
var p = item;
|
||
|
var point1;
|
||
|
var point2;
|
||
|
var point3;
|
||
|
var point;
|
||
|
var preEndPoint = preSegment.endPoint;
|
||
|
var p1 = p[1];
|
||
|
var p2 = p[2];
|
||
|
|
||
|
switch (cmd) {
|
||
|
default:
|
||
|
break;
|
||
|
|
||
|
case 'M':
|
||
|
if (relative) {
|
||
|
point = toAbsolute(p1, p2, preEndPoint);
|
||
|
} else {
|
||
|
point = {
|
||
|
x: p1,
|
||
|
y: p2
|
||
|
};
|
||
|
}
|
||
|
|
||
|
this.command = 'M';
|
||
|
this.params = [preEndPoint, point];
|
||
|
this.subStart = point;
|
||
|
this.endPoint = point;
|
||
|
break;
|
||
|
|
||
|
case 'L':
|
||
|
if (relative) {
|
||
|
point = toAbsolute(p1, p2, preEndPoint);
|
||
|
} else {
|
||
|
point = {
|
||
|
x: p1,
|
||
|
y: p2
|
||
|
};
|
||
|
}
|
||
|
|
||
|
this.command = 'L';
|
||
|
this.params = [preEndPoint, point];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = point;
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
return [point.x - preEndPoint.x, point.y - preEndPoint.y];
|
||
|
};
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
return [preEndPoint.x - point.x, preEndPoint.y - point.y];
|
||
|
};
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'H':
|
||
|
if (relative) {
|
||
|
point = toAbsolute(p1, 0, preEndPoint);
|
||
|
} else {
|
||
|
point = {
|
||
|
x: p1,
|
||
|
y: preEndPoint.y
|
||
|
};
|
||
|
}
|
||
|
|
||
|
this.command = 'L';
|
||
|
this.params = [preEndPoint, point];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = point;
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
return [point.x - preEndPoint.x, point.y - preEndPoint.y];
|
||
|
};
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
return [preEndPoint.x - point.x, preEndPoint.y - point.y];
|
||
|
};
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'V':
|
||
|
if (relative) {
|
||
|
point = toAbsolute(0, p1, preEndPoint);
|
||
|
} else {
|
||
|
point = {
|
||
|
x: preEndPoint.x,
|
||
|
y: p1
|
||
|
};
|
||
|
}
|
||
|
|
||
|
this.command = 'L';
|
||
|
this.params = [preEndPoint, point];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = point;
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
return [point.x - preEndPoint.x, point.y - preEndPoint.y];
|
||
|
};
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
return [preEndPoint.x - point.x, preEndPoint.y - point.y];
|
||
|
};
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'Q':
|
||
|
if (relative) {
|
||
|
point1 = toAbsolute(p1, p2, preEndPoint);
|
||
|
point2 = toAbsolute(p[3], p[4], preEndPoint);
|
||
|
} else {
|
||
|
point1 = {
|
||
|
x: p1,
|
||
|
y: p2
|
||
|
};
|
||
|
point2 = {
|
||
|
x: p[3],
|
||
|
y: p[4]
|
||
|
};
|
||
|
}
|
||
|
|
||
|
this.command = 'Q';
|
||
|
this.params = [preEndPoint, point1, point2];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = point2;
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
return [point2.x - point1.x, point2.y - point1.y];
|
||
|
};
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
return [preEndPoint.x - point1.x, preEndPoint.y - point1.y];
|
||
|
};
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'T':
|
||
|
if (relative) {
|
||
|
point2 = toAbsolute(p1, p2, preEndPoint);
|
||
|
} else {
|
||
|
point2 = {
|
||
|
x: p1,
|
||
|
y: p2
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (preSegment.command === 'Q') {
|
||
|
point1 = toSymmetry(preSegment.params[1], preEndPoint);
|
||
|
this.command = 'Q';
|
||
|
this.params = [preEndPoint, point1, point2];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = point2;
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
return [point2.x - point1.x, point2.y - point1.y];
|
||
|
};
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
return [preEndPoint.x - point1.x, preEndPoint.y - point1.y];
|
||
|
};
|
||
|
} else {
|
||
|
this.command = 'TL';
|
||
|
this.params = [preEndPoint, point2];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = point2;
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
return [point2.x - preEndPoint.x, point2.y - preEndPoint.y];
|
||
|
};
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
return [preEndPoint.x - point2.x, preEndPoint.y - point2.y];
|
||
|
};
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'C':
|
||
|
if (relative) {
|
||
|
point1 = toAbsolute(p1, p2, preEndPoint);
|
||
|
point2 = toAbsolute(p[3], p[4], preEndPoint);
|
||
|
point3 = toAbsolute(p[5], p[6], preEndPoint);
|
||
|
} else {
|
||
|
point1 = {
|
||
|
x: p1,
|
||
|
y: p2
|
||
|
};
|
||
|
point2 = {
|
||
|
x: p[3],
|
||
|
y: p[4]
|
||
|
};
|
||
|
point3 = {
|
||
|
x: p[5],
|
||
|
y: p[6]
|
||
|
};
|
||
|
}
|
||
|
|
||
|
this.command = 'C';
|
||
|
this.params = [preEndPoint, point1, point2, point3];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = point3;
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
return [point3.x - point2.x, point3.y - point2.y];
|
||
|
};
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
return [preEndPoint.x - point1.x, preEndPoint.y - point1.y];
|
||
|
};
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'S':
|
||
|
if (relative) {
|
||
|
point2 = toAbsolute(p1, p2, preEndPoint);
|
||
|
point3 = toAbsolute(p[3], p[4], preEndPoint);
|
||
|
} else {
|
||
|
point2 = {
|
||
|
x: p1,
|
||
|
y: p2
|
||
|
};
|
||
|
point3 = {
|
||
|
x: p[3],
|
||
|
y: p[4]
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (preSegment.command === 'C') {
|
||
|
point1 = toSymmetry(preSegment.params[2], preEndPoint);
|
||
|
this.command = 'C';
|
||
|
this.params = [preEndPoint, point1, point2, point3];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = point3;
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
return [point3.x - point2.x, point3.y - point2.y];
|
||
|
};
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
return [preEndPoint.x - point1.x, preEndPoint.y - point1.y];
|
||
|
};
|
||
|
} else {
|
||
|
this.command = 'SQ';
|
||
|
this.params = [preEndPoint, point2, point3];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = point3;
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
return [point3.x - point2.x, point3.y - point2.y];
|
||
|
};
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
return [preEndPoint.x - point2.x, preEndPoint.y - point2.y];
|
||
|
};
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'A':
|
||
|
{
|
||
|
var rx = p1;
|
||
|
var ry = p2;
|
||
|
var psi = p[3];
|
||
|
var fa = p[4];
|
||
|
var fs = p[5];
|
||
|
|
||
|
if (relative) {
|
||
|
point = toAbsolute(p[6], p[7], preEndPoint);
|
||
|
} else {
|
||
|
point = {
|
||
|
x: p[6],
|
||
|
y: p[7]
|
||
|
};
|
||
|
}
|
||
|
|
||
|
this.command = 'A';
|
||
|
var params = getArcParams(preEndPoint, point, fa, fs, rx, ry, psi);
|
||
|
this.params = params;
|
||
|
var start = preSegment.subStart;
|
||
|
this.subStart = start;
|
||
|
this.endPoint = point;
|
||
|
var startAngle = params[5] % (Math.PI * 2);
|
||
|
|
||
|
if (Util.isNumberEqual(startAngle, Math.PI * 2)) {
|
||
|
startAngle = 0;
|
||
|
}
|
||
|
|
||
|
var endAngle = params[6] % (Math.PI * 2);
|
||
|
|
||
|
if (Util.isNumberEqual(endAngle, Math.PI * 2)) {
|
||
|
endAngle = 0;
|
||
|
}
|
||
|
|
||
|
var d = 0.001;
|
||
|
|
||
|
this.startTangent = function () {
|
||
|
if (fs === 0) {
|
||
|
d *= -1;
|
||
|
}
|
||
|
|
||
|
var dx = params[3] * Math.cos(startAngle - d) + params[1];
|
||
|
var dy = params[4] * Math.sin(startAngle - d) + params[2];
|
||
|
return [dx - start.x, dy - start.y];
|
||
|
};
|
||
|
|
||
|
this.endTangent = function () {
|
||
|
var endAngle = params[6];
|
||
|
|
||
|
if (endAngle - Math.PI * 2 < 0.0001) {
|
||
|
endAngle = 0;
|
||
|
}
|
||
|
|
||
|
var dx = params[3] * Math.cos(startAngle + endAngle + d) + params[1];
|
||
|
var dy = params[4] * Math.sin(startAngle + endAngle - d) + params[2];
|
||
|
return [preEndPoint.x - dx, preEndPoint.y - dy];
|
||
|
};
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'Z':
|
||
|
{
|
||
|
this.command = 'Z';
|
||
|
this.params = [preEndPoint, preSegment.subStart];
|
||
|
this.subStart = preSegment.subStart;
|
||
|
this.endPoint = preSegment.subStart;
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
isInside: function isInside(x, y, lineWidth) {
|
||
|
var self = this;
|
||
|
var command = self.command;
|
||
|
var params = self.params;
|
||
|
var box = self.box;
|
||
|
|
||
|
if (box) {
|
||
|
if (!Inside.box(box.minX, box.maxX, box.minY, box.maxY, x, y)) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (command) {
|
||
|
default:
|
||
|
break;
|
||
|
|
||
|
case 'M':
|
||
|
return false;
|
||
|
|
||
|
case 'TL':
|
||
|
case 'L':
|
||
|
case 'Z':
|
||
|
return Inside.line(params[0].x, params[0].y, params[1].x, params[1].y, lineWidth, x, y);
|
||
|
|
||
|
case 'SQ':
|
||
|
case 'Q':
|
||
|
return Inside.quadraticline(params[0].x, params[0].y, params[1].x, params[1].y, params[2].x, params[2].y, lineWidth, x, y);
|
||
|
|
||
|
case 'C':
|
||
|
{
|
||
|
return Inside.cubicline(params[0].x, params[0].y, params[1].x, params[1].y, params[2].x, params[2].y, params[3].x, params[3].y, lineWidth, x, y);
|
||
|
}
|
||
|
|
||
|
case 'A':
|
||
|
{
|
||
|
var p = params;
|
||
|
var cx = p[1];
|
||
|
var cy = p[2];
|
||
|
var rx = p[3];
|
||
|
var ry = p[4];
|
||
|
var theta = p[5];
|
||
|
var dTheta = p[6];
|
||
|
var psi = p[7];
|
||
|
var fs = p[8];
|
||
|
var r = rx > ry ? rx : ry;
|
||
|
var scaleX = rx > ry ? 1 : rx / ry;
|
||
|
var scaleY = rx > ry ? ry / rx : 1;
|
||
|
p = [x, y, 1];
|
||
|
var m = [1, 0, 0, 0, 1, 0, 0, 0, 1];
|
||
|
mat3.translate(m, m, [-cx, -cy]);
|
||
|
mat3.rotate(m, m, -psi);
|
||
|
mat3.scale(m, m, [1 / scaleX, 1 / scaleY]);
|
||
|
vec3.transformMat3(p, p, m);
|
||
|
return Inside.arcline(0, 0, r, theta, theta + dTheta, 1 - fs, lineWidth, p[0], p[1]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
},
|
||
|
draw: function draw(context) {
|
||
|
var command = this.command;
|
||
|
var params = this.params;
|
||
|
var point1;
|
||
|
var point2;
|
||
|
var point3;
|
||
|
|
||
|
switch (command) {
|
||
|
default:
|
||
|
break;
|
||
|
|
||
|
case 'M':
|
||
|
context.moveTo(params[1].x, params[1].y);
|
||
|
break;
|
||
|
|
||
|
case 'TL':
|
||
|
case 'L':
|
||
|
context.lineTo(params[1].x, params[1].y);
|
||
|
break;
|
||
|
|
||
|
case 'SQ':
|
||
|
case 'Q':
|
||
|
point1 = params[1];
|
||
|
point2 = params[2];
|
||
|
context.quadraticCurveTo(point1.x, point1.y, point2.x, point2.y);
|
||
|
break;
|
||
|
|
||
|
case 'C':
|
||
|
point1 = params[1];
|
||
|
point2 = params[2];
|
||
|
point3 = params[3];
|
||
|
context.bezierCurveTo(point1.x, point1.y, point2.x, point2.y, point3.x, point3.y);
|
||
|
break;
|
||
|
|
||
|
case 'A':
|
||
|
{
|
||
|
var p = params;
|
||
|
var p1 = p[1];
|
||
|
var p2 = p[2];
|
||
|
var cx = p1;
|
||
|
var cy = p2;
|
||
|
var rx = p[3];
|
||
|
var ry = p[4];
|
||
|
var theta = p[5];
|
||
|
var dTheta = p[6];
|
||
|
var psi = p[7];
|
||
|
var fs = p[8];
|
||
|
var r = rx > ry ? rx : ry;
|
||
|
var scaleX = rx > ry ? 1 : rx / ry;
|
||
|
var scaleY = rx > ry ? ry / rx : 1;
|
||
|
context.translate(cx, cy);
|
||
|
context.rotate(psi);
|
||
|
context.scale(scaleX, scaleY);
|
||
|
context.arc(0, 0, r, theta, theta + dTheta, 1 - fs);
|
||
|
context.scale(1 / scaleX, 1 / scaleY);
|
||
|
context.rotate(-psi);
|
||
|
context.translate(-cx, -cy);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'Z':
|
||
|
context.closePath();
|
||
|
break;
|
||
|
}
|
||
|
},
|
||
|
shortenDraw: function shortenDraw(context, dx, dy) {
|
||
|
var command = this.command;
|
||
|
var params = this.params;
|
||
|
var point1;
|
||
|
var point2;
|
||
|
var point3;
|
||
|
|
||
|
switch (command) {
|
||
|
default:
|
||
|
break;
|
||
|
|
||
|
case 'M':
|
||
|
context.moveTo(params[1].x - dx, params[1].y - dy);
|
||
|
break;
|
||
|
|
||
|
case 'TL':
|
||
|
case 'L':
|
||
|
context.lineTo(params[1].x - dx, params[1].y - dy);
|
||
|
break;
|
||
|
|
||
|
case 'SQ':
|
||
|
case 'Q':
|
||
|
point1 = params[1];
|
||
|
point2 = params[2];
|
||
|
context.quadraticCurveTo(point1.x, point1.y, point2.x - dx, point2.y - dy);
|
||
|
break;
|
||
|
|
||
|
case 'C':
|
||
|
point1 = params[1];
|
||
|
point2 = params[2];
|
||
|
point3 = params[3];
|
||
|
context.bezierCurveTo(point1.x, point1.y, point2.x, point2.y, point3.x - dx, point3.y - dy);
|
||
|
break;
|
||
|
|
||
|
case 'A':
|
||
|
{
|
||
|
var p = params;
|
||
|
var p1 = p[1];
|
||
|
var p2 = p[2];
|
||
|
var cx = p1;
|
||
|
var cy = p2;
|
||
|
var rx = p[3];
|
||
|
var ry = p[4];
|
||
|
var theta = p[5];
|
||
|
var dTheta = p[6];
|
||
|
var psi = p[7];
|
||
|
var fs = p[8];
|
||
|
var r = rx > ry ? rx : ry;
|
||
|
var scaleX = rx > ry ? 1 : rx / ry;
|
||
|
var scaleY = rx > ry ? ry / rx : 1;
|
||
|
context.translate(cx, cy);
|
||
|
context.rotate(psi);
|
||
|
context.scale(scaleX, scaleY);
|
||
|
context.arc(0, 0, r, theta, theta + dTheta, 1 - fs);
|
||
|
context.scale(1 / scaleX, 1 / scaleY);
|
||
|
context.rotate(-psi);
|
||
|
context.translate(-cx, -cy);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case 'Z':
|
||
|
context.closePath();
|
||
|
break;
|
||
|
}
|
||
|
},
|
||
|
getBBox: function getBBox(lineWidth) {
|
||
|
var halfWidth = lineWidth / 2;
|
||
|
var params = this.params;
|
||
|
var yDims;
|
||
|
var xDims;
|
||
|
var i;
|
||
|
var l;
|
||
|
|
||
|
switch (this.command) {
|
||
|
default:
|
||
|
case 'M':
|
||
|
case 'Z':
|
||
|
break;
|
||
|
|
||
|
case 'TL':
|
||
|
case 'L':
|
||
|
this.box = {
|
||
|
minX: Math.min(params[0].x, params[1].x) - halfWidth,
|
||
|
maxX: Math.max(params[0].x, params[1].x) + halfWidth,
|
||
|
minY: Math.min(params[0].y, params[1].y) - halfWidth,
|
||
|
maxY: Math.max(params[0].y, params[1].y) + halfWidth
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case 'SQ':
|
||
|
case 'Q':
|
||
|
xDims = Quadratic.extrema(params[0].x, params[1].x, params[2].x);
|
||
|
|
||
|
for (i = 0, l = xDims.length; i < l; i++) {
|
||
|
xDims[i] = Quadratic.at(params[0].x, params[1].x, params[2].x, xDims[i]);
|
||
|
}
|
||
|
|
||
|
xDims.push(params[0].x, params[2].x);
|
||
|
yDims = Quadratic.extrema(params[0].y, params[1].y, params[2].y);
|
||
|
|
||
|
for (i = 0, l = yDims.length; i < l; i++) {
|
||
|
yDims[i] = Quadratic.at(params[0].y, params[1].y, params[2].y, yDims);
|
||
|
}
|
||
|
|
||
|
yDims.push(params[0].y, params[2].y);
|
||
|
this.box = {
|
||
|
minX: Math.min.apply(Math, xDims) - halfWidth,
|
||
|
maxX: Math.max.apply(Math, xDims) + halfWidth,
|
||
|
minY: Math.min.apply(Math, yDims) - halfWidth,
|
||
|
maxY: Math.max.apply(Math, yDims) + halfWidth
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case 'C':
|
||
|
xDims = Cubic.extrema(params[0].x, params[1].x, params[2].x, params[3].x);
|
||
|
|
||
|
for (i = 0, l = xDims.length; i < l; i++) {
|
||
|
xDims[i] = Cubic.at(params[0].x, params[1].x, params[2].x, params[3].x, xDims[i]);
|
||
|
}
|
||
|
|
||
|
yDims = Cubic.extrema(params[0].y, params[1].y, params[2].y, params[3].y);
|
||
|
|
||
|
for (i = 0, l = yDims.length; i < l; i++) {
|
||
|
yDims[i] = Cubic.at(params[0].y, params[1].y, params[2].y, params[3].y, yDims[i]);
|
||
|
}
|
||
|
|
||
|
xDims.push(params[0].x, params[3].x);
|
||
|
yDims.push(params[0].y, params[3].y);
|
||
|
this.box = {
|
||
|
minX: Math.min.apply(Math, xDims) - halfWidth,
|
||
|
maxX: Math.max.apply(Math, xDims) + halfWidth,
|
||
|
minY: Math.min.apply(Math, yDims) - halfWidth,
|
||
|
maxY: Math.max.apply(Math, yDims) + halfWidth
|
||
|
};
|
||
|
break;
|
||
|
|
||
|
case 'A':
|
||
|
{
|
||
|
// todo 待优化
|
||
|
var p = params;
|
||
|
var cx = p[1];
|
||
|
var cy = p[2];
|
||
|
var rx = p[3];
|
||
|
var ry = p[4];
|
||
|
var theta = p[5];
|
||
|
var dTheta = p[6];
|
||
|
var psi = p[7];
|
||
|
var fs = p[8];
|
||
|
var start = theta;
|
||
|
var end = theta + dTheta;
|
||
|
var xDim = Ellipse.xExtrema(psi, rx, ry);
|
||
|
var minX = Infinity;
|
||
|
var maxX = -Infinity;
|
||
|
var xs = [start, end];
|
||
|
|
||
|
for (i = -Math.PI * 2; i <= Math.PI * 2; i += Math.PI) {
|
||
|
var xAngle = xDim + i;
|
||
|
|
||
|
if (fs === 1) {
|
||
|
if (start < xAngle && xAngle < end) {
|
||
|
xs.push(xAngle);
|
||
|
}
|
||
|
} else {
|
||
|
if (end < xAngle && xAngle < start) {
|
||
|
xs.push(xAngle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 0, l = xs.length; i < l; i++) {
|
||
|
var x = Ellipse.xAt(psi, rx, ry, cx, xs[i]);
|
||
|
|
||
|
if (x < minX) {
|
||
|
minX = x;
|
||
|
}
|
||
|
|
||
|
if (x > maxX) {
|
||
|
maxX = x;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var yDim = Ellipse.yExtrema(psi, rx, ry);
|
||
|
var minY = Infinity;
|
||
|
var maxY = -Infinity;
|
||
|
var ys = [start, end];
|
||
|
|
||
|
for (i = -Math.PI * 2; i <= Math.PI * 2; i += Math.PI) {
|
||
|
var yAngle = yDim + i;
|
||
|
|
||
|
if (fs === 1) {
|
||
|
if (start < yAngle && yAngle < end) {
|
||
|
ys.push(yAngle);
|
||
|
}
|
||
|
} else {
|
||
|
if (end < yAngle && yAngle < start) {
|
||
|
ys.push(yAngle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 0, l = ys.length; i < l; i++) {
|
||
|
var y = Ellipse.yAt(psi, rx, ry, cy, ys[i]);
|
||
|
|
||
|
if (y < minY) {
|
||
|
minY = y;
|
||
|
}
|
||
|
|
||
|
if (y > maxY) {
|
||
|
maxY = y;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.box = {
|
||
|
minX: minX - halfWidth,
|
||
|
maxX: maxX + halfWidth,
|
||
|
minY: minY - halfWidth,
|
||
|
maxY: maxY + halfWidth
|
||
|
};
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
module.exports = PathSegment;
|