287 lines
8.1 KiB
JavaScript
287 lines
8.1 KiB
JavaScript
import { JOINT_TYPE } from '../core/const.mjs';
|
|
import { Point, utils } from '@pixi/core';
|
|
|
|
const tempArr = [];
|
|
function fixOrientation(points, hole = false) {
|
|
const m = points.length;
|
|
if (m < 6) {
|
|
return;
|
|
}
|
|
let area = 0;
|
|
for (let i = 0, x1 = points[m - 2], y1 = points[m - 1]; i < m; i += 2) {
|
|
const x2 = points[i];
|
|
const y2 = points[i + 1];
|
|
area += (x2 - x1) * (y2 + y1);
|
|
x1 = x2;
|
|
y1 = y2;
|
|
}
|
|
if (!hole && area > 0 || hole && area <= 0) {
|
|
const n = m / 2;
|
|
for (let i = n + n % 2; i < m; i += 2) {
|
|
const i1 = m - i - 2;
|
|
const i2 = m - i - 1;
|
|
const i3 = i;
|
|
const i4 = i + 1;
|
|
[points[i1], points[i3]] = [points[i3], points[i1]];
|
|
[points[i2], points[i4]] = [points[i4], points[i2]];
|
|
}
|
|
}
|
|
}
|
|
class PolyBuilder {
|
|
path(graphicsData, buildData) {
|
|
const shape = graphicsData.shape;
|
|
const points = graphicsData.points = shape.points.slice();
|
|
const eps = buildData.closePointEps;
|
|
const eps2 = eps * eps;
|
|
if (points.length === 0) {
|
|
return;
|
|
}
|
|
const firstPoint = new Point(points[0], points[1]);
|
|
const lastPoint = new Point(points[points.length - 2], points[points.length - 1]);
|
|
const closedShape = graphicsData.closeStroke = shape.closeStroke;
|
|
let len = points.length;
|
|
let newLen = 2;
|
|
for (let i = 2; i < len; i += 2) {
|
|
const x1 = points[i - 2];
|
|
const y1 = points[i - 1];
|
|
const x2 = points[i];
|
|
const y2 = points[i + 1];
|
|
let flag = true;
|
|
if (Math.abs(x1 - x2) < eps && Math.abs(y1 - y2) < eps) {
|
|
flag = false;
|
|
}
|
|
if (flag) {
|
|
points[newLen] = points[i];
|
|
points[newLen + 1] = points[i + 1];
|
|
newLen += 2;
|
|
}
|
|
}
|
|
points.length = len = newLen;
|
|
newLen = 2;
|
|
for (let i = 2; i + 2 < len; i += 2) {
|
|
let x1 = points[i - 2];
|
|
let y1 = points[i - 1];
|
|
const x2 = points[i];
|
|
const y2 = points[i + 1];
|
|
let x3 = points[i + 2];
|
|
let y3 = points[i + 3];
|
|
x1 -= x2;
|
|
y1 -= y2;
|
|
x3 -= x2;
|
|
y3 -= y2;
|
|
let flag = true;
|
|
if (Math.abs(x3 * y1 - y3 * x1) < eps2) {
|
|
if (x1 * x3 + y1 * y3 < -eps2) {
|
|
flag = false;
|
|
}
|
|
}
|
|
if (flag) {
|
|
points[newLen] = points[i];
|
|
points[newLen + 1] = points[i + 1];
|
|
newLen += 2;
|
|
}
|
|
}
|
|
points[newLen] = points[len - 2];
|
|
points[newLen + 1] = points[len - 1];
|
|
newLen += 2;
|
|
points.length = len = newLen;
|
|
if (len <= 2) {
|
|
return;
|
|
}
|
|
if (closedShape) {
|
|
const closedPath = Math.abs(firstPoint.x - lastPoint.x) < eps && Math.abs(firstPoint.y - lastPoint.y) < eps;
|
|
if (closedPath) {
|
|
points.pop();
|
|
points.pop();
|
|
}
|
|
}
|
|
}
|
|
line(graphicsData, buildData) {
|
|
const { closeStroke, points } = graphicsData;
|
|
const len = points.length;
|
|
if (len <= 2) {
|
|
return;
|
|
}
|
|
const { verts, joints } = buildData;
|
|
const joint = graphicsData.jointType();
|
|
const cap = graphicsData.capType();
|
|
let prevCap = 0;
|
|
let prevX;
|
|
let prevY;
|
|
if (closeStroke) {
|
|
prevX = points[len - 2];
|
|
prevY = points[len - 1];
|
|
joints.push(JOINT_TYPE.NONE);
|
|
} else {
|
|
prevX = points[2];
|
|
prevY = points[3];
|
|
if (cap === JOINT_TYPE.CAP_ROUND) {
|
|
verts.push(points[0], points[1]);
|
|
joints.push(JOINT_TYPE.NONE);
|
|
joints.push(JOINT_TYPE.CAP_ROUND);
|
|
prevCap = 0;
|
|
} else {
|
|
prevCap = cap;
|
|
joints.push(JOINT_TYPE.NONE);
|
|
}
|
|
}
|
|
verts.push(prevX, prevY);
|
|
for (let i = 0; i < len; i += 2) {
|
|
const x1 = points[i];
|
|
const y1 = points[i + 1];
|
|
let endJoint = joint;
|
|
if (i + 2 >= len) {
|
|
if (!closeStroke) {
|
|
endJoint = JOINT_TYPE.NONE;
|
|
}
|
|
} else if (i + 4 >= len) {
|
|
if (!closeStroke) {
|
|
if (cap === JOINT_TYPE.CAP_ROUND) {
|
|
endJoint = JOINT_TYPE.JOINT_CAP_ROUND;
|
|
}
|
|
if (cap === JOINT_TYPE.CAP_BUTT) {
|
|
endJoint = JOINT_TYPE.JOINT_CAP_BUTT;
|
|
}
|
|
if (cap === JOINT_TYPE.CAP_SQUARE) {
|
|
endJoint = JOINT_TYPE.JOINT_CAP_SQUARE;
|
|
}
|
|
}
|
|
}
|
|
endJoint += prevCap;
|
|
prevCap = 0;
|
|
verts.push(x1, y1);
|
|
joints.push(endJoint);
|
|
prevX = x1;
|
|
prevY = y1;
|
|
}
|
|
if (closeStroke) {
|
|
verts.push(points[0], points[1]);
|
|
joints.push(JOINT_TYPE.NONE);
|
|
verts.push(points[2], points[3]);
|
|
joints.push(JOINT_TYPE.NONE);
|
|
} else {
|
|
verts.push(points[len - 4], points[len - 3]);
|
|
joints.push(JOINT_TYPE.NONE);
|
|
}
|
|
}
|
|
fill(graphicsData, buildData) {
|
|
let points = graphicsData.points;
|
|
const holes = graphicsData.holes;
|
|
const eps = buildData.closePointEps;
|
|
const { verts, joints } = buildData;
|
|
if (points.length < 6) {
|
|
return;
|
|
}
|
|
const holeArray = [];
|
|
let len = points.length;
|
|
fixOrientation(points, false);
|
|
for (let i = 0; i < holes.length; i++) {
|
|
const hole = holes[i];
|
|
fixOrientation(hole.points, true);
|
|
holeArray.push(points.length / 2);
|
|
points = points.concat(hole.points);
|
|
}
|
|
const pn = tempArr;
|
|
if (pn.length < points.length) {
|
|
pn.length = points.length;
|
|
}
|
|
let start = 0;
|
|
for (let i = 0; i <= holeArray.length; i++) {
|
|
let finish = len / 2;
|
|
if (i > 0) {
|
|
if (i < holeArray.length) {
|
|
finish = holeArray[i];
|
|
} else {
|
|
finish = points.length >> 1;
|
|
}
|
|
}
|
|
pn[start * 2] = finish - 1;
|
|
pn[(finish - 1) * 2 + 1] = start;
|
|
for (let j = start; j + 1 < finish; j++) {
|
|
pn[j * 2 + 1] = j + 1;
|
|
pn[j * 2 + 2] = j;
|
|
}
|
|
start = finish;
|
|
}
|
|
graphicsData.triangles = utils.earcut(points, holeArray, 2);
|
|
if (!graphicsData.triangles) {
|
|
return;
|
|
}
|
|
if (!graphicsData.fillAA) {
|
|
for (let i = 0; i < points.length; i += 2) {
|
|
verts.push(points[i], points[i + 1]);
|
|
joints.push(JOINT_TYPE.FILL);
|
|
}
|
|
return;
|
|
}
|
|
const { triangles } = graphicsData;
|
|
len = points.length;
|
|
for (let i = 0; i < triangles.length; i += 3) {
|
|
let flag = 0;
|
|
for (let j = 0; j < 3; j++) {
|
|
const ind1 = triangles[i + j];
|
|
const ind2 = triangles[i + (j + 1) % 3];
|
|
if (pn[ind1 * 2] === ind2 || pn[ind1 * 2 + 1] === ind2) {
|
|
flag |= 1 << j;
|
|
}
|
|
}
|
|
joints.push(JOINT_TYPE.FILL_EXPAND + flag);
|
|
joints.push(JOINT_TYPE.NONE);
|
|
joints.push(JOINT_TYPE.NONE);
|
|
joints.push(JOINT_TYPE.NONE);
|
|
joints.push(JOINT_TYPE.NONE);
|
|
joints.push(JOINT_TYPE.NONE);
|
|
}
|
|
for (let ind = 0; ind < len / 2; ind++) {
|
|
const prev = pn[ind * 2];
|
|
const next = pn[ind * 2 + 1];
|
|
let nx1 = points[next * 2 + 1] - points[ind * 2 + 1];
|
|
let ny1 = -(points[next * 2] - points[ind * 2]);
|
|
let nx2 = points[ind * 2 + 1] - points[prev * 2 + 1];
|
|
let ny2 = -(points[ind * 2] - points[prev * 2]);
|
|
const D1 = Math.sqrt(nx1 * nx1 + ny1 * ny1);
|
|
nx1 /= D1;
|
|
ny1 /= D1;
|
|
const D2 = Math.sqrt(nx2 * nx2 + ny2 * ny2);
|
|
nx2 /= D2;
|
|
ny2 /= D2;
|
|
let bx = nx1 + nx2;
|
|
let by = ny1 + ny2;
|
|
const D = bx * nx1 + by * ny1;
|
|
if (Math.abs(D) < eps) {
|
|
bx = nx1;
|
|
by = ny1;
|
|
} else {
|
|
bx /= D;
|
|
by /= D;
|
|
}
|
|
pn[ind * 2] = bx;
|
|
pn[ind * 2 + 1] = by;
|
|
}
|
|
for (let i = 0; i < triangles.length; i += 3) {
|
|
const prev = triangles[i];
|
|
const ind = triangles[i + 1];
|
|
const next = triangles[i + 2];
|
|
const nx1 = points[next * 2 + 1] - points[ind * 2 + 1];
|
|
const ny1 = -(points[next * 2] - points[ind * 2]);
|
|
const nx2 = points[ind * 2 + 1] - points[prev * 2 + 1];
|
|
const ny2 = -(points[ind * 2] - points[prev * 2]);
|
|
let j1 = 1;
|
|
if (nx1 * ny2 - nx2 * ny1 > 0) {
|
|
j1 = 2;
|
|
}
|
|
for (let j = 0; j < 3; j++) {
|
|
const ind2 = triangles[i + j * j1 % 3];
|
|
verts.push(points[ind2 * 2], points[ind2 * 2 + 1]);
|
|
}
|
|
for (let j = 0; j < 3; j++) {
|
|
const ind2 = triangles[i + j * j1 % 3];
|
|
verts.push(pn[ind2 * 2], pn[ind2 * 2 + 1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export { PolyBuilder };
|
|
//# sourceMappingURL=PolyBuilder.mjs.map
|