Files
railwaysystem/RuoYi-Vue/ruoyi-ui/node_modules1/@antv/g6-element/lib/edges/polyline-util.js
T

625 lines
20 KiB
JavaScript
Raw Normal View History

2026-09-10 15:40:10 +08:00
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.simplifyPolyline = exports.removeRedundantPoint = exports.removeFrom = exports.reconstructPath = exports.pathFinder = exports.mergeBBox = exports.isSegmentsIntersected = exports.isSegmentCrossingBBox = exports.isPointOutsideBBox = exports.isHorizontalPort = exports.isBending = exports.isBBoxesOverlapping = exports.heuristicCostEstimate = exports.getSimplePolyline = exports.getPolylinePoints = exports.getPointsFromBBox = exports.getPathWithBorderRadiusByPolyline = exports.getNeighborPoints = exports.getExpandedBBoxPoint = exports.getExpandedBBox = exports.getBorderRadiusPoints = exports.getBBoxYCrossPoints = exports.getBBoxXCrossPoints = exports.getBBoxFromPoints = exports.getBBoxFromPoint = exports.getBBoxCrossPointsByPoint = exports.filterConnectPoints = exports.distance = exports._costByPoints = exports.SortedArray = void 0;
var getBBoxFromPoint = exports.getBBoxFromPoint = function getBBoxFromPoint(point) {
var x = point.x,
y = point.y;
return {
x: x,
y: y,
centerX: x,
centerY: y,
minX: x,
minY: y,
maxX: x,
maxY: y,
height: 0,
width: 0
};
};
var getBBoxFromPoints = exports.getBBoxFromPoints = function getBBoxFromPoints(points) {
if (points === void 0) {
points = [];
}
var xs = [];
var ys = [];
points.forEach(function (p) {
xs.push(p.x);
ys.push(p.y);
});
var minX = Math.min.apply(Math, xs);
var maxX = Math.max.apply(Math, xs);
var minY = Math.min.apply(Math, ys);
var maxY = Math.max.apply(Math, ys);
return {
centerX: (minX + maxX) / 2,
centerY: (minY + maxY) / 2,
maxX: maxX,
maxY: maxY,
minX: minX,
minY: minY,
height: maxY - minY,
width: maxX - minX
};
};
var isBBoxesOverlapping = exports.isBBoxesOverlapping = function isBBoxesOverlapping(b1, b2) {
return Math.abs(b1.centerX - b2.centerX) * 2 < b1.width + b2.width && Math.abs(b1.centerY - b2.centerY) * 2 < b1.height + b2.height;
};
var filterConnectPoints = exports.filterConnectPoints = function filterConnectPoints(points) {
// pre-process: remove duplicated points
var result = [];
var map = {};
var pointsLength = points.length;
for (var i = pointsLength - 1; i >= 0; i--) {
var p = points[i];
p.id = "".concat(p.x, "|||").concat(p.y);
if (!map[p.id]) {
map[p.id] = p;
result.push(p);
}
}
return result;
};
var simplifyPolyline = exports.simplifyPolyline = function simplifyPolyline(points) {
return filterConnectPoints(points);
};
var getSimplePolyline = exports.getSimplePolyline = function getSimplePolyline(sPoint, tPoint) {
return [sPoint, {
x: sPoint.x,
y: tPoint.y
}, tPoint];
};
var getExpandedBBox = exports.getExpandedBBox = function getExpandedBBox(bbox, offset) {
if (bbox.width || bbox.height) {
return {
centerX: bbox.centerX,
centerY: bbox.centerY,
minX: bbox.minX - offset,
minY: bbox.minY - offset,
maxX: bbox.maxX + offset,
maxY: bbox.maxY + offset,
height: bbox.height + 2 * offset,
width: bbox.width + 2 * offset
};
}
// when it is a point
return bbox;
};
var isHorizontalPort = exports.isHorizontalPort = function isHorizontalPort(port, bbox) {
var dx = Math.abs(port.x - bbox.centerX);
var dy = Math.abs(port.y - bbox.centerY);
if (dx === 0 && dy === 0) return 0;
return dx / bbox.width > dy / bbox.height;
};
var getExpandedBBoxPoint = exports.getExpandedBBoxPoint = function getExpandedBBoxPoint(bbox,
// 将原来节点 bbox 扩展了 offset 后的 bbox,且被 gridSize 格式化
point,
// 被 gridSize 格式化后的位置(anchorPoint)
anotherPoint) {
var isHorizontal = isHorizontalPort(point, bbox);
if (isHorizontal === 0) {
// 说明锚点是节点中心,linkCenter: true。需要根据两个节点的相对关系决定方向
var x = bbox.centerX;
var y = bbox.centerY;
if (anotherPoint.y < point.y) {
// 另一端在左上/右上方时,总是从上方走
y = bbox.minY;
} else if (anotherPoint.x > point.x) {
// 另一端在右下方,往右边走
x = bbox.maxX;
} else if (anotherPoint.x < point.x) {
// 另一端在左下方,往左边走
x = bbox.minX;
} else if (anotherPoint.x === point.x) {
// 另一段在正下方,往下走
y = bbox.maxY;
}
return {
x: x,
y: y
};
}
if (isHorizontal) {
return {
x: point.x > bbox.centerX ? bbox.maxX : bbox.minX,
y: point.y
};
}
return {
x: point.x,
y: point.y > bbox.centerY ? bbox.maxY : bbox.minY
};
};
/**
*
* @param b1
* @param b2
*/
var mergeBBox = exports.mergeBBox = function mergeBBox(b1, b2) {
var minX = Math.min(b1.minX, b2.minX);
var minY = Math.min(b1.minY, b2.minY);
var maxX = Math.max(b1.maxX, b2.maxX);
var maxY = Math.max(b1.maxY, b2.maxY);
return {
centerX: (minX + maxX) / 2,
centerY: (minY + maxY) / 2,
minX: minX,
minY: minY,
maxX: maxX,
maxY: maxY,
height: maxY - minY,
width: maxX - minX
};
};
var getPointsFromBBox = exports.getPointsFromBBox = function getPointsFromBBox(bbox) {
// anticlockwise
return [{
x: bbox.minX,
y: bbox.minY
}, {
x: bbox.maxX,
y: bbox.minY
}, {
x: bbox.maxX,
y: bbox.maxY
}, {
x: bbox.minX,
y: bbox.maxY
}];
};
var isPointOutsideBBox = exports.isPointOutsideBBox = function isPointOutsideBBox(point, bbox) {
var x = point.x,
y = point.y;
return x < bbox.minX || x > bbox.maxX || y < bbox.minY || y > bbox.maxY;
};
var getBBoxXCrossPoints = exports.getBBoxXCrossPoints = function getBBoxXCrossPoints(bbox, x) {
if (x < bbox.minX || x > bbox.maxX) {
return [];
}
return [{
x: x,
y: bbox.minY
}, {
x: x,
y: bbox.maxY
}];
};
var getBBoxYCrossPoints = exports.getBBoxYCrossPoints = function getBBoxYCrossPoints(bbox, y) {
if (y < bbox.minY || y > bbox.maxY) {
return [];
}
return [{
x: bbox.minX,
y: y
}, {
x: bbox.maxX,
y: y
}];
};
var getBBoxCrossPointsByPoint = exports.getBBoxCrossPointsByPoint = function getBBoxCrossPointsByPoint(bbox, point) {
return getBBoxXCrossPoints(bbox, point.x).concat(getBBoxYCrossPoints(bbox, point.y));
};
/**
* 曼哈顿距离
*/
var distance = exports.distance = function distance(p1, p2) {
return Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y);
};
/**
* 如果 points 中的一个节点 x 与 p 相等,则消耗 -2。y 同
* 即优先选择和 points 在同一水平线 / 垂直线上的点
*/
// eslint-disable-next-line @typescript-eslint/naming-convention
var _costByPoints = exports._costByPoints = function _costByPoints(p, points) {
var offset = -2;
var result = 0;
points.forEach(function (point) {
if (point) {
if (p.x === point.x) {
result += offset;
}
if (p.y === point.y) {
result += offset;
}
}
});
return result;
};
/**
* ps 经过 p 到 pt 的距离,减去其他路过节点造成的消耗
*/
var heuristicCostEstimate = exports.heuristicCostEstimate = function heuristicCostEstimate(p, ps, pt, source, target) {
return distance(p, ps) + distance(p, pt) + _costByPoints(p, [ps, pt, source, target]);
};
var _reconstructPath = exports.reconstructPath = function reconstructPath(pathPoints, pointById, cameFrom, currentId, iterator) {
if (iterator === void 0) {
iterator = 0;
}
pathPoints.unshift(pointById[currentId]);
if (cameFrom[currentId] && cameFrom[currentId] !== currentId && iterator <= 100) {
_reconstructPath(pathPoints, pointById, cameFrom, cameFrom[currentId], iterator + 1);
}
};
/**
* 从 arr 中删去 item
*/
var removeFrom = exports.removeFrom = function removeFrom(arr, item) {
var index = arr.indexOf(item);
if (index > -1) {
arr.splice(index, 1);
}
};
var isSegmentsIntersected = exports.isSegmentsIntersected = function isSegmentsIntersected(p0, p1, p2, p3) {
var v1x = p2.x - p0.x;
var v1y = p2.y - p0.y;
var v2x = p3.x - p0.x;
var v2y = p3.y - p0.y;
var v3x = p2.x - p1.x;
var v3y = p2.y - p1.y;
var v4x = p3.x - p1.x;
var v4y = p3.y - p1.y;
var pd1 = v1x * v2y - v1y * v2x;
var pd2 = v3x * v4y - v3y * v4x;
var pd3 = v1x * v3y - v1y * v3x;
var pd4 = v2x * v4y - v2y * v4x;
return pd1 * pd2 <= 0 && pd3 * pd4 <= 0;
};
var isSegmentCrossingBBox = exports.isSegmentCrossingBBox = function isSegmentCrossingBBox(p1, p2, bbox) {
if (bbox.width || bbox.height) {
var _a = getPointsFromBBox(bbox),
pa = _a[0],
pb = _a[1],
pc = _a[2],
pd = _a[3];
return isSegmentsIntersected(p1, p2, pa, pb) || isSegmentsIntersected(p1, p2, pa, pd) || isSegmentsIntersected(p1, p2, pb, pc) || isSegmentsIntersected(p1, p2, pc, pd);
}
return false;
};
/**
* 在 points 中找到满足 x 或 y 和 point 的 x 或 y 相等,且与 point 连线不经过 bbox1 与 bbox2 的点
*/
var getNeighborPoints = exports.getNeighborPoints = function getNeighborPoints(points, point, bbox1, bbox2) {
var neighbors = [];
points.forEach(function (p) {
if (p === point) return;
if (p.x === point.x || p.y === point.y) {
if (isSegmentCrossingBBox(p, point, bbox1) || isSegmentCrossingBBox(p, point, bbox2)) return;
neighbors.push(p);
}
});
return filterConnectPoints(neighbors);
};
/**
* sorted array ascendly
* add new item to proper index when calling add
*/
var SortedArray = exports.SortedArray = /** @class */function () {
function SortedArray() {
this.arr = [];
this.map = {};
this.arr = [];
this.map = {};
}
SortedArray.prototype._innerAdd = function (item, length) {
var idxRange = [0, length - 1];
while (idxRange[1] - idxRange[0] > 1) {
var midIdx = Math.floor((idxRange[0] + idxRange[1]) / 2);
if (this.arr[midIdx].value > item.value) {
idxRange[1] = midIdx;
} else if (this.arr[midIdx].value < item.value) {
idxRange[0] = midIdx;
} else {
this.arr.splice(midIdx, 0, item);
this.map[item.id] = true;
return;
}
}
this.arr.splice(idxRange[1], 0, item);
this.map[item.id] = true;
};
SortedArray.prototype.add = function (item) {
// 已经存在,先移除
delete this.map[item.id];
var length = this.arr.length;
if (!length) {
this.arr.push(item);
this.map[item.id] = true;
return;
}
// 比最后一个大,加入尾部
if (this.arr[length - 1].value < item.value) {
this.arr.push(item);
this.map[item.id] = true;
return;
}
this._innerAdd(item, length);
};
// only remove from the map to avoid cost
// clear the invalid (not in the map) item when calling minId(true)
SortedArray.prototype.remove = function (id) {
if (!this.map[id]) return;
delete this.map[id];
};
SortedArray.prototype._clearAndGetMinId = function () {
var res;
for (var i = this.arr.length - 1; i >= 0; i--) {
if (this.map[this.arr[i].id]) res = this.arr[i].id;else this.arr.splice(i, 1);
}
return res;
};
SortedArray.prototype._findFirstId = function () {
while (this.arr.length) {
var first = this.arr.shift();
if (this.map[first.id]) return first.id;
}
};
SortedArray.prototype.minId = function (clear) {
if (clear) {
return this._clearAndGetMinId();
} else {
return this._findFirstId();
}
};
return SortedArray;
}();
var pathFinder = exports.pathFinder = function pathFinder(points, start, goal, sBBox, tBBox, os, ot) {
var _a;
// A-Star Algorithm
var closedSet = [];
var openSet = (_a = {}, _a[start.id] = start, _a);
var cameFrom = {};
var gScore = {}; // all default values are Infinity
var fScore = {}; // all default values are Infinity
gScore[start.id] = 0;
fScore[start.id] = heuristicCostEstimate(start, goal, start);
var sortedOpenSet = new SortedArray();
sortedOpenSet.add({
id: start.id,
value: fScore[start.id]
});
var pointById = {};
points.forEach(function (p) {
pointById[p.id] = p;
});
var current;
while (Object.keys(openSet).length) {
var minId = sortedOpenSet.minId(false);
if (minId) {
current = openSet[minId];
} else {
break;
}
// 若 openSet 中 fScore 最小的点就是终点
if (current === goal) {
// ending condition
var pathPoints = [];
_reconstructPath(pathPoints, pointById, cameFrom, goal.id);
return pathPoints;
}
delete openSet[current.id];
sortedOpenSet.remove(current.id);
closedSet.push(current);
var neighborPoints = getNeighborPoints(points, current, sBBox, tBBox);
var iterateNeighbors = function iterateNeighbors(items) {
items.forEach(function (neighbor) {
if (closedSet.indexOf(neighbor) !== -1) {
return;
}
var neighborId = neighbor.id;
if (!openSet[neighborId]) {
openSet[neighborId] = neighbor;
}
var tentativeGScore = fScore[current.id] + distance(current, neighbor); // + distance(neighbor, goal);
if (gScore[neighborId] && tentativeGScore >= gScore[neighborId]) {
sortedOpenSet.add({
id: neighborId,
value: fScore[neighborId]
});
return;
}
cameFrom[neighborId] = current.id;
gScore[neighborId] = tentativeGScore;
fScore[neighborId] = gScore[neighborId] + heuristicCostEstimate(neighbor, goal, start, os, ot);
sortedOpenSet.add({
id: neighborId,
value: fScore[neighborId]
});
});
};
iterateNeighbors(neighborPoints);
}
// throw new Error('Cannot find path');
return [start, goal];
};
var isBending = exports.isBending = function isBending(p0, p1, p2) {
return !(p0.x === p1.x && p1.x === p2.x || p0.y === p1.y && p1.y === p2.y);
};
var getBorderRadiusPoints = exports.getBorderRadiusPoints = function getBorderRadiusPoints(p0, p1, p2, r) {
var d0 = distance(p0, p1);
var d1 = distance(p2, p1);
if (d0 < r) {
r = d0;
}
if (d1 < r) {
r = d1;
}
var ps = {
x: p1.x - r / d0 * (p1.x - p0.x),
y: p1.y - r / d0 * (p1.y - p0.y)
};
var pt = {
x: p1.x - r / d1 * (p1.x - p2.x),
y: p1.y - r / d1 * (p1.y - p2.y)
};
return [ps, pt];
};
var getPathWithBorderRadiusByPolyline = exports.getPathWithBorderRadiusByPolyline = function getPathWithBorderRadiusByPolyline(points, borderRadius) {
var pathSegments = [];
var startPoint = points[0];
pathSegments.push("M".concat(startPoint.x, " ").concat(startPoint.y));
points.forEach(function (p, i) {
var p1 = points[i + 1];
var p2 = points[i + 2];
if (p1 && p2) {
if (isBending(p, p1, p2)) {
var _a = getBorderRadiusPoints(p, p1, p2, borderRadius),
ps = _a[0],
pt = _a[1];
pathSegments.push("L".concat(ps.x, " ").concat(ps.y));
pathSegments.push("Q".concat(p1.x, " ").concat(p1.y, " ").concat(pt.x, " ").concat(pt.y));
pathSegments.push("L".concat(pt.x, " ").concat(pt.y));
} else {
pathSegments.push("L".concat(p1.x, " ").concat(p1.y));
}
} else if (p1) {
pathSegments.push("L".concat(p1.x, " ").concat(p1.y));
}
});
return pathSegments.join('');
};
var getPolylinePoints = exports.getPolylinePoints = function getPolylinePoints(start, end, sNode, tNode, offset) {
var sBBox, tBBox;
if (!sNode || !sNode.getType()) {
sBBox = getBBoxFromPoint(start);
} else if (sNode.getType() === 'combo') {
var sKeyShapeBBox = sNode.getKeyShape().getBBox();
if (sKeyShapeBBox) {
var _a = sNode.getModel(),
sx = _a.x,
sy = _a.y;
sBBox = {
x: sx,
y: sy,
width: sKeyShapeBBox.width,
height: sKeyShapeBBox.height,
minX: sKeyShapeBBox.minX + sx,
maxX: sKeyShapeBBox.maxX + sx,
minY: sKeyShapeBBox.minY + sy,
maxY: sKeyShapeBBox.maxY + sy
};
sBBox.centerX = (sBBox.minX + sBBox.maxX) / 2;
sBBox.centerY = (sBBox.minY + sBBox.maxY) / 2;
} else {
sBBox = getBBoxFromPoint(start);
}
} else {
sBBox = sNode && sNode.getBBox();
}
if (!tNode || !tNode.getType()) {
tBBox = getBBoxFromPoint(end);
} else if (tNode.getType() === 'combo') {
var tKeyShapeBBox = tNode.getKeyShape().getBBox();
if (tKeyShapeBBox) {
var _b = tNode.getModel(),
tx = _b.x,
ty = _b.y;
tBBox = {
x: tx,
y: ty,
width: tKeyShapeBBox.width,
height: tKeyShapeBBox.height,
minX: tKeyShapeBBox.minX + tx,
maxX: tKeyShapeBBox.maxX + tx,
minY: tKeyShapeBBox.minY + ty,
maxY: tKeyShapeBBox.maxY + ty
};
tBBox.centerX = (tBBox.minX + tBBox.maxX) / 2;
tBBox.centerY = (tBBox.minY + tBBox.maxY) / 2;
} else {
tBBox = getBBoxFromPoint(end);
}
} else {
tBBox = tNode && tNode.getBBox();
}
// if (isBBoxesOverlapping(sBBox, tBBox)) {
// // source and target nodes are overlapping
// return simplifyPolyline(getSimplePolyline(start, end));
// }
var sxBBox = getExpandedBBox(sBBox, offset);
var txBBox = getExpandedBBox(tBBox, offset);
// if (isBBoxesOverlapping(sxBBox, txBBox)) {
// // the expanded bounding boxes of source and target nodes are overlapping
// return simplifyPolyline(getSimplePolyline(start, end));
// }
var sPoint = getExpandedBBoxPoint(sxBBox, start, end);
var tPoint = getExpandedBBoxPoint(txBBox, end, start);
var lineBBox = getBBoxFromPoints([sPoint, tPoint]);
var sMixBBox = mergeBBox(sxBBox, lineBBox);
var tMixBBox = mergeBBox(txBBox, lineBBox);
var connectPoints = [];
connectPoints = connectPoints.concat(getPointsFromBBox(sMixBBox)).concat(getPointsFromBBox(tMixBBox));
var centerPoint = {
x: (start.x + end.x) / 2,
y: (start.y + end.y) / 2
};
[lineBBox, sMixBBox, tMixBBox].forEach(function (bbox) {
connectPoints = connectPoints.concat(getBBoxCrossPointsByPoint(bbox, centerPoint).filter(function (p) {
return isPointOutsideBBox(p, sxBBox) && isPointOutsideBBox(p, txBBox);
}));
});
[{
x: sPoint.x,
y: tPoint.y
}, {
x: tPoint.x,
y: sPoint.y
}].forEach(function (p) {
// impossible!!
if (isPointOutsideBBox(p, sxBBox) && isPointOutsideBBox(p, txBBox) // &&
// isPointInsideBBox(p, sMixBBox) && isPointInsideBBox(p, tMixBBox)
) {
connectPoints.push(p);
}
});
connectPoints.unshift(sPoint);
connectPoints.push(tPoint);
// filter out dulplicated points in connectPoints
connectPoints = filterConnectPoints(connectPoints); // , sxBBox, txBBox, outerBBox
var pathPoints = pathFinder(connectPoints, sPoint, tPoint, sBBox, tBBox, start, end);
pathPoints.unshift(start);
pathPoints.push(end);
return simplifyPolyline(pathPoints);
};
/**
* 去除连续同 x 不同 y 的中间点;去除连续同 y 不同 x 的中间点
* @param points 坐标集合 { x: number, y: number, id: string }[]
* @returns
*/
var removeRedundantPoint = exports.removeRedundantPoint = function removeRedundantPoint(points) {
if (!(points === null || points === void 0 ? void 0 : points.length)) return points;
var beginPoint = points[points.length - 1];
var current = {
x: beginPoint.x,
y: beginPoint.y
};
var continueSameX = [beginPoint];
var continueSameY = [beginPoint];
for (var i = points.length - 2; i >= 0; i--) {
var point = points[i];
if (point.x === current.x) {
continueSameX.push(point);
} else {
continueSameX = [point];
current.x = point.x;
}
if (point.y === current.y) {
continueSameY.push(point);
} else {
continueSameY = [point];
current.y = point.y;
}
if (continueSameX.length > 2) {
var removeIdx = points.indexOf(continueSameX[1]);
if (removeIdx > -1) points.splice(removeIdx, 1);
continue;
}
if (continueSameY.length > 2) {
var removeIdx = points.indexOf(continueSameY[1]);
if (removeIdx > -1) points.splice(removeIdx, 1);
}
}
return points;
};