366 lines
11 KiB
JavaScript
366 lines
11 KiB
JavaScript
'use strict';
|
|
|
|
var Point = require('../../../../maths/point/Point.js');
|
|
var _const = require('../const.js');
|
|
var getOrientationOfPoints = require('../utils/getOrientationOfPoints.js');
|
|
|
|
"use strict";
|
|
function square(x, y, nx, ny, innerWeight, outerWeight, clockwise, verts) {
|
|
const ix = x - nx * innerWeight;
|
|
const iy = y - ny * innerWeight;
|
|
const ox = x + nx * outerWeight;
|
|
const oy = y + ny * outerWeight;
|
|
let exx;
|
|
let eyy;
|
|
if (clockwise) {
|
|
exx = ny;
|
|
eyy = -nx;
|
|
} else {
|
|
exx = -ny;
|
|
eyy = nx;
|
|
}
|
|
const eix = ix + exx;
|
|
const eiy = iy + eyy;
|
|
const eox = ox + exx;
|
|
const eoy = oy + eyy;
|
|
verts.push(eix, eiy);
|
|
verts.push(eox, eoy);
|
|
return 2;
|
|
}
|
|
function round(cx, cy, sx, sy, ex, ey, verts, clockwise) {
|
|
const cx2p0x = sx - cx;
|
|
const cy2p0y = sy - cy;
|
|
let angle0 = Math.atan2(cx2p0x, cy2p0y);
|
|
let angle1 = Math.atan2(ex - cx, ey - cy);
|
|
if (clockwise && angle0 < angle1) {
|
|
angle0 += Math.PI * 2;
|
|
} else if (!clockwise && angle0 > angle1) {
|
|
angle1 += Math.PI * 2;
|
|
}
|
|
let startAngle = angle0;
|
|
const angleDiff = angle1 - angle0;
|
|
const absAngleDiff = Math.abs(angleDiff);
|
|
const radius = Math.sqrt(cx2p0x * cx2p0x + cy2p0y * cy2p0y);
|
|
const segCount = (15 * absAngleDiff * Math.sqrt(radius) / Math.PI >> 0) + 1;
|
|
const angleInc = angleDiff / segCount;
|
|
startAngle += angleInc;
|
|
if (clockwise) {
|
|
verts.push(cx, cy);
|
|
verts.push(sx, sy);
|
|
for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
|
|
verts.push(cx, cy);
|
|
verts.push(
|
|
cx + Math.sin(angle) * radius,
|
|
cy + Math.cos(angle) * radius
|
|
);
|
|
}
|
|
verts.push(cx, cy);
|
|
verts.push(ex, ey);
|
|
} else {
|
|
verts.push(sx, sy);
|
|
verts.push(cx, cy);
|
|
for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
|
|
verts.push(
|
|
cx + Math.sin(angle) * radius,
|
|
cy + Math.cos(angle) * radius
|
|
);
|
|
verts.push(cx, cy);
|
|
}
|
|
verts.push(ex, ey);
|
|
verts.push(cx, cy);
|
|
}
|
|
return segCount * 2;
|
|
}
|
|
function buildLine(points, lineStyle, flipAlignment, closed, vertices, _verticesStride, _verticesOffset, indices, _indicesOffset) {
|
|
const eps = _const.closePointEps;
|
|
if (points.length === 0) {
|
|
return;
|
|
}
|
|
const style = lineStyle;
|
|
let alignment = style.alignment;
|
|
if (lineStyle.alignment !== 0.5) {
|
|
let orientation = getOrientationOfPoints.getOrientationOfPoints(points);
|
|
if (flipAlignment)
|
|
orientation *= -1;
|
|
alignment = (alignment - 0.5) * orientation + 0.5;
|
|
}
|
|
const firstPoint = new Point.Point(points[0], points[1]);
|
|
const lastPoint = new Point.Point(points[points.length - 2], points[points.length - 1]);
|
|
const closedShape = closed;
|
|
const closedPath = Math.abs(firstPoint.x - lastPoint.x) < eps && Math.abs(firstPoint.y - lastPoint.y) < eps;
|
|
if (closedShape) {
|
|
points = points.slice();
|
|
if (closedPath) {
|
|
points.pop();
|
|
points.pop();
|
|
lastPoint.set(points[points.length - 2], points[points.length - 1]);
|
|
}
|
|
const midPointX = (firstPoint.x + lastPoint.x) * 0.5;
|
|
const midPointY = (lastPoint.y + firstPoint.y) * 0.5;
|
|
points.unshift(midPointX, midPointY);
|
|
points.push(midPointX, midPointY);
|
|
}
|
|
const verts = vertices;
|
|
const length = points.length / 2;
|
|
let indexCount = points.length;
|
|
const indexStart = verts.length / 2;
|
|
const width = style.width / 2;
|
|
const widthSquared = width * width;
|
|
const miterLimitSquared = style.miterLimit * style.miterLimit;
|
|
let x0 = points[0];
|
|
let y0 = points[1];
|
|
let x1 = points[2];
|
|
let y1 = points[3];
|
|
let x2 = 0;
|
|
let y2 = 0;
|
|
let perpX = -(y0 - y1);
|
|
let perpY = x0 - x1;
|
|
let perp1x = 0;
|
|
let perp1y = 0;
|
|
let dist = Math.sqrt(perpX * perpX + perpY * perpY);
|
|
perpX /= dist;
|
|
perpY /= dist;
|
|
perpX *= width;
|
|
perpY *= width;
|
|
const ratio = alignment;
|
|
const innerWeight = (1 - ratio) * 2;
|
|
const outerWeight = ratio * 2;
|
|
if (!closedShape) {
|
|
if (style.cap === "round") {
|
|
indexCount += round(
|
|
x0 - perpX * (innerWeight - outerWeight) * 0.5,
|
|
y0 - perpY * (innerWeight - outerWeight) * 0.5,
|
|
x0 - perpX * innerWeight,
|
|
y0 - perpY * innerWeight,
|
|
x0 + perpX * outerWeight,
|
|
y0 + perpY * outerWeight,
|
|
verts,
|
|
true
|
|
) + 2;
|
|
} else if (style.cap === "square") {
|
|
indexCount += square(x0, y0, perpX, perpY, innerWeight, outerWeight, true, verts);
|
|
}
|
|
}
|
|
verts.push(
|
|
x0 - perpX * innerWeight,
|
|
y0 - perpY * innerWeight
|
|
);
|
|
verts.push(
|
|
x0 + perpX * outerWeight,
|
|
y0 + perpY * outerWeight
|
|
);
|
|
for (let i = 1; i < length - 1; ++i) {
|
|
x0 = points[(i - 1) * 2];
|
|
y0 = points[(i - 1) * 2 + 1];
|
|
x1 = points[i * 2];
|
|
y1 = points[i * 2 + 1];
|
|
x2 = points[(i + 1) * 2];
|
|
y2 = points[(i + 1) * 2 + 1];
|
|
perpX = -(y0 - y1);
|
|
perpY = x0 - x1;
|
|
dist = Math.sqrt(perpX * perpX + perpY * perpY);
|
|
perpX /= dist;
|
|
perpY /= dist;
|
|
perpX *= width;
|
|
perpY *= width;
|
|
perp1x = -(y1 - y2);
|
|
perp1y = x1 - x2;
|
|
dist = Math.sqrt(perp1x * perp1x + perp1y * perp1y);
|
|
perp1x /= dist;
|
|
perp1y /= dist;
|
|
perp1x *= width;
|
|
perp1y *= width;
|
|
const dx0 = x1 - x0;
|
|
const dy0 = y0 - y1;
|
|
const dx1 = x1 - x2;
|
|
const dy1 = y2 - y1;
|
|
const dot = dx0 * dx1 + dy0 * dy1;
|
|
const cross = dy0 * dx1 - dy1 * dx0;
|
|
const clockwise = cross < 0;
|
|
if (Math.abs(cross) < 1e-3 * Math.abs(dot)) {
|
|
verts.push(
|
|
x1 - perpX * innerWeight,
|
|
y1 - perpY * innerWeight
|
|
);
|
|
verts.push(
|
|
x1 + perpX * outerWeight,
|
|
y1 + perpY * outerWeight
|
|
);
|
|
if (dot >= 0) {
|
|
if (style.join === "round") {
|
|
indexCount += round(
|
|
x1,
|
|
y1,
|
|
x1 - perpX * innerWeight,
|
|
y1 - perpY * innerWeight,
|
|
x1 - perp1x * innerWeight,
|
|
y1 - perp1y * innerWeight,
|
|
verts,
|
|
false
|
|
) + 4;
|
|
} else {
|
|
indexCount += 2;
|
|
}
|
|
verts.push(
|
|
x1 - perp1x * outerWeight,
|
|
y1 - perp1y * outerWeight
|
|
);
|
|
verts.push(
|
|
x1 + perp1x * innerWeight,
|
|
y1 + perp1y * innerWeight
|
|
);
|
|
}
|
|
continue;
|
|
}
|
|
const c1 = (-perpX + x0) * (-perpY + y1) - (-perpX + x1) * (-perpY + y0);
|
|
const c2 = (-perp1x + x2) * (-perp1y + y1) - (-perp1x + x1) * (-perp1y + y2);
|
|
const px = (dx0 * c2 - dx1 * c1) / cross;
|
|
const py = (dy1 * c1 - dy0 * c2) / cross;
|
|
const pDist = (px - x1) * (px - x1) + (py - y1) * (py - y1);
|
|
const imx = x1 + (px - x1) * innerWeight;
|
|
const imy = y1 + (py - y1) * innerWeight;
|
|
const omx = x1 - (px - x1) * outerWeight;
|
|
const omy = y1 - (py - y1) * outerWeight;
|
|
const smallerInsideSegmentSq = Math.min(dx0 * dx0 + dy0 * dy0, dx1 * dx1 + dy1 * dy1);
|
|
const insideWeight = clockwise ? innerWeight : outerWeight;
|
|
const smallerInsideDiagonalSq = smallerInsideSegmentSq + insideWeight * insideWeight * widthSquared;
|
|
const insideMiterOk = pDist <= smallerInsideDiagonalSq;
|
|
if (insideMiterOk) {
|
|
if (style.join === "bevel" || pDist / widthSquared > miterLimitSquared) {
|
|
if (clockwise) {
|
|
verts.push(imx, imy);
|
|
verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
|
|
verts.push(imx, imy);
|
|
verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight);
|
|
} else {
|
|
verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
|
|
verts.push(omx, omy);
|
|
verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight);
|
|
verts.push(omx, omy);
|
|
}
|
|
indexCount += 2;
|
|
} else if (style.join === "round") {
|
|
if (clockwise) {
|
|
verts.push(imx, imy);
|
|
verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
|
|
indexCount += round(
|
|
x1,
|
|
y1,
|
|
x1 + perpX * outerWeight,
|
|
y1 + perpY * outerWeight,
|
|
x1 + perp1x * outerWeight,
|
|
y1 + perp1y * outerWeight,
|
|
verts,
|
|
true
|
|
) + 4;
|
|
verts.push(imx, imy);
|
|
verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight);
|
|
} else {
|
|
verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
|
|
verts.push(omx, omy);
|
|
indexCount += round(
|
|
x1,
|
|
y1,
|
|
x1 - perpX * innerWeight,
|
|
y1 - perpY * innerWeight,
|
|
x1 - perp1x * innerWeight,
|
|
y1 - perp1y * innerWeight,
|
|
verts,
|
|
false
|
|
) + 4;
|
|
verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight);
|
|
verts.push(omx, omy);
|
|
}
|
|
} else {
|
|
verts.push(imx, imy);
|
|
verts.push(omx, omy);
|
|
}
|
|
} else {
|
|
verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
|
|
verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
|
|
if (style.join === "round") {
|
|
if (clockwise) {
|
|
indexCount += round(
|
|
x1,
|
|
y1,
|
|
x1 + perpX * outerWeight,
|
|
y1 + perpY * outerWeight,
|
|
x1 + perp1x * outerWeight,
|
|
y1 + perp1y * outerWeight,
|
|
verts,
|
|
true
|
|
) + 2;
|
|
} else {
|
|
indexCount += round(
|
|
x1,
|
|
y1,
|
|
x1 - perpX * innerWeight,
|
|
y1 - perpY * innerWeight,
|
|
x1 - perp1x * innerWeight,
|
|
y1 - perp1y * innerWeight,
|
|
verts,
|
|
false
|
|
) + 2;
|
|
}
|
|
} else if (style.join === "miter" && pDist / widthSquared <= miterLimitSquared) {
|
|
if (clockwise) {
|
|
verts.push(omx, omy);
|
|
verts.push(omx, omy);
|
|
} else {
|
|
verts.push(imx, imy);
|
|
verts.push(imx, imy);
|
|
}
|
|
indexCount += 2;
|
|
}
|
|
verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight);
|
|
verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight);
|
|
indexCount += 2;
|
|
}
|
|
}
|
|
x0 = points[(length - 2) * 2];
|
|
y0 = points[(length - 2) * 2 + 1];
|
|
x1 = points[(length - 1) * 2];
|
|
y1 = points[(length - 1) * 2 + 1];
|
|
perpX = -(y0 - y1);
|
|
perpY = x0 - x1;
|
|
dist = Math.sqrt(perpX * perpX + perpY * perpY);
|
|
perpX /= dist;
|
|
perpY /= dist;
|
|
perpX *= width;
|
|
perpY *= width;
|
|
verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
|
|
verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
|
|
if (!closedShape) {
|
|
if (style.cap === "round") {
|
|
indexCount += round(
|
|
x1 - perpX * (innerWeight - outerWeight) * 0.5,
|
|
y1 - perpY * (innerWeight - outerWeight) * 0.5,
|
|
x1 - perpX * innerWeight,
|
|
y1 - perpY * innerWeight,
|
|
x1 + perpX * outerWeight,
|
|
y1 + perpY * outerWeight,
|
|
verts,
|
|
false
|
|
) + 2;
|
|
} else if (style.cap === "square") {
|
|
indexCount += square(x1, y1, perpX, perpY, innerWeight, outerWeight, false, verts);
|
|
}
|
|
}
|
|
const eps2 = _const.curveEps * _const.curveEps;
|
|
for (let i = indexStart; i < indexCount + indexStart - 2; ++i) {
|
|
x0 = verts[i * 2];
|
|
y0 = verts[i * 2 + 1];
|
|
x1 = verts[(i + 1) * 2];
|
|
y1 = verts[(i + 1) * 2 + 1];
|
|
x2 = verts[(i + 2) * 2];
|
|
y2 = verts[(i + 2) * 2 + 1];
|
|
if (Math.abs(x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)) < eps2) {
|
|
continue;
|
|
}
|
|
indices.push(i, i + 1, i + 2);
|
|
}
|
|
}
|
|
|
|
exports.buildLine = buildLine;
|
|
//# sourceMappingURL=buildLine.js.map
|