@logicflow/extension
Version:
LogicFlow Extensions
641 lines (640 loc) • 20.6 kB
JavaScript
"use strict";
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ManhattanLayout = exports.getOrient = exports.PriorityQueue = void 0;
var NodeBase = /** @class */ (function () {
function NodeBase(x, y) {
this.x = x;
this.y = y;
this.G = 0;
this.H = 0;
this.isProcessed = false;
this.connection = null;
this.from = null;
}
Object.defineProperty(NodeBase.prototype, "F", {
get: function () {
return this.G + this.H;
},
enumerable: false,
configurable: true
});
NodeBase.prototype.setProcessed = function () {
this.isProcessed = true;
};
NodeBase.prototype.setConnection = function (connection) {
this.connection = connection;
};
NodeBase.prototype.setFrom = function (from) {
this.from = from;
};
NodeBase.prototype.setG = function (g) {
this.G = g;
};
NodeBase.prototype.setH = function (h) {
this.H = h;
};
NodeBase.prototype.getManhattanDistanceTo = function (point) {
var _a = this, x1 = _a.x, y1 = _a.y;
var x2 = point.x, y2 = point.y;
return Math.abs(x1 - x2) + Math.abs(y1 - y2);
};
return NodeBase;
}());
var PriorityQueue = /** @class */ (function () {
function PriorityQueue() {
this.heap = [];
}
PriorityQueue.prototype.enqueue = function (node, priority) {
this.heap.push({
node: node,
priority: priority,
});
this.bubbleUp(this.heap.length - 1);
};
PriorityQueue.prototype.dequeue = function () {
var min = this.heap[0];
var end = this.heap.pop();
if (this.heap.length > 0) {
this.heap[0] = end;
this.sinkDown(0);
}
return min;
};
PriorityQueue.prototype.bubbleUp = function (index) {
var node = this.heap[index];
while (index > 0) {
var parentIndex = Math.floor((index - 1) / 2);
var parent_1 = this.heap[parentIndex];
if (node.priority >= parent_1.priority)
break;
this.heap[parentIndex] = node;
this.heap[index] = parent_1;
index = parentIndex;
}
};
PriorityQueue.prototype.sinkDown = function (index) {
var leftChildIndex = 2 * index + 1;
var rightChildIndex = 2 * index + 2;
var smallestChildIndex = index;
var length = this.heap.length;
if (leftChildIndex < length &&
this.heap[leftChildIndex].priority <
this.heap[smallestChildIndex].priority) {
smallestChildIndex = leftChildIndex;
}
if (rightChildIndex < length &&
this.heap[rightChildIndex].priority <
this.heap[smallestChildIndex].priority) {
smallestChildIndex = rightChildIndex;
}
if (smallestChildIndex !== index) {
var swapNode = this.heap[smallestChildIndex];
this.heap[smallestChildIndex] = this.heap[index];
this.heap[index] = swapNode;
this.sinkDown(smallestChildIndex);
}
};
PriorityQueue.prototype.isEmpty = function () {
return this.heap.length === 0;
};
return PriorityQueue;
}());
exports.PriorityQueue = PriorityQueue;
function expandBBox(bbox, offset) {
var minX = bbox.minX, minY = bbox.minY, maxX = bbox.maxX, maxY = bbox.maxY;
return {
minX: minX - offset,
minY: minY - offset,
maxX: maxX + offset,
maxY: maxY + offset,
};
}
function getPointsFromBBoxBorder(bbox) {
var minX = bbox.minX, minY = bbox.minY, maxX = bbox.maxX, maxY = bbox.maxY;
return [
{
x: minX,
y: minY,
},
{
x: minX + (maxX - minX) / 2,
y: minY,
},
{
x: maxX,
y: minY,
},
{
x: maxX,
y: minY + (maxY - minY) / 2,
},
{
x: maxX,
y: maxY,
},
{
x: minX + (maxX - minX) / 2,
y: maxY,
},
{
x: minX,
y: maxY,
},
{
x: minX,
y: minY + (maxY - minY) / 2,
},
];
}
function getHull(points) {
var xs = points.map(function (item) { return item.x; });
var ys = points.map(function (item) { return item.y; });
return {
minX: Math.min.apply(Math, __spreadArray([], __read(xs), false)),
minY: Math.min.apply(Math, __spreadArray([], __read(ys), false)),
maxX: Math.max.apply(Math, __spreadArray([], __read(xs), false)),
maxY: Math.max.apply(Math, __spreadArray([], __read(ys), false)),
};
}
function isPointInsideTheBoxes(point, bboxes) {
var e_1, _a;
var flag = false;
try {
for (var bboxes_1 = __values(bboxes), bboxes_1_1 = bboxes_1.next(); !bboxes_1_1.done; bboxes_1_1 = bboxes_1.next()) {
var bbox = bboxes_1_1.value;
if (isBBoxContainThePoint(bbox, point)) {
flag = true;
break;
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (bboxes_1_1 && !bboxes_1_1.done && (_a = bboxes_1.return)) _a.call(bboxes_1);
}
finally { if (e_1) throw e_1.error; }
}
return flag;
}
function isBBoxContainThePoint(bbox, p) {
var x = p.x, y = p.y;
var minX = bbox.minX, minY = bbox.minY, maxX = bbox.maxX, maxY = bbox.maxY;
// ignore the point on the border
return x > minX && x < maxX && y > minY && y < maxY;
}
function isSegmentsIntersected(seg1, seg2) {
var _a = __read(seg1, 2), p0 = _a[0], p1 = _a[1];
var _b = __read(seg2, 2), p2 = _b[0], p3 = _b[1];
var s1x = p1.x - p0.x;
var s1y = p1.y - p0.y;
var s2x = p3.x - p2.x;
var s2y = p3.y - p2.y;
var s = (-s1y * (p0.x - p2.x) + s1x * (p0.y - p2.y)) / (-s2x * s1y + s1x * s2y);
var t = (s2x * (p0.y - p2.y) - s2y * (p0.x - p2.x)) / (-s2x * s1y + s1x * s2y);
return s >= 0 && s <= 1 && t >= 0 && t <= 1;
}
function getVerticesFromBBox(bbox) {
var minX = bbox.minX, minY = bbox.minY, maxX = bbox.maxX, maxY = bbox.maxY;
return [
{
x: minX,
y: minY,
},
{
x: maxX,
y: minY,
},
{
x: maxX,
y: maxY,
},
{
x: minX,
y: maxY,
},
];
}
function isSegmentCrossingBBox(line, bbox) {
var _a = __read(line, 2), p1 = _a[0], p2 = _a[1];
var minX = bbox.minX, minY = bbox.minY, maxX = bbox.maxX, maxY = bbox.maxY;
var width = Math.abs(maxX - minX);
var height = Math.abs(maxY - minY);
if (width === 0 && height === 0) {
return false;
}
var _b = __read(getVerticesFromBBox(bbox), 4), pa = _b[0], pb = _b[1], pc = _b[2], pd = _b[3];
var count = 0;
if (isSegmentsIntersected([p1, p2], [pa, pb])) {
count++;
}
if (isSegmentsIntersected([p1, p2], [pa, pd])) {
count++;
}
if (isSegmentsIntersected([p1, p2], [pb, pc])) {
count++;
}
if (isSegmentsIntersected([p1, p2], [pc, pd])) {
count++;
}
return count !== 0;
}
function aStarFindPathByGrid(startNode, endNode, step, bboxes, outside) {
var toSearch = [startNode];
var searchSet = new Set();
var _loop_1 = function () {
var e_2, _a, e_3, _b;
var current = toSearch[0];
try {
for (var toSearch_1 = (e_2 = void 0, __values(toSearch)), toSearch_1_1 = toSearch_1.next(); !toSearch_1_1.done; toSearch_1_1 = toSearch_1.next()) {
var item = toSearch_1_1.value;
if (item.F < current.F || (item.F === current.F && item.H < current.H)) {
current = item;
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (toSearch_1_1 && !toSearch_1_1.done && (_a = toSearch_1.return)) _a.call(toSearch_1);
}
finally { if (e_2) throw e_2.error; }
}
if ("".concat(current.x, "/").concat(current.y) === "".concat(endNode.x, "/").concat(endNode.y)) {
var res = [
{
x: current.x,
y: current.y,
},
];
while (current.connection) {
var connection = current.connection;
res.push({
x: connection.x,
y: connection.y,
});
current = current.connection;
}
return { value: res.reverse() };
}
var val = "".concat(current.x, "/").concat(current.y);
!searchSet.has(val) && searchSet.add(val);
toSearch = toSearch.filter(function (item) { return "".concat(current.x, "/").concat(current.y) !== "".concat(item.x, "/").concat(item.y); });
var neighborsRes = findNeighborsByGridStep(current, step, bboxes, outside).filter(function (item) {
var flag = !isPointInsideTheBoxes(item, bboxes);
return flag;
});
var tmpRes = [];
neighborsRes.forEach(function (item) {
var key = "".concat(item.x, "/").concat(item.y);
if (!searchSet.has(key)) {
tmpRes.push(item);
tmpRes.push(item);
}
});
try {
for (var tmpRes_1 = (e_3 = void 0, __values(tmpRes)), tmpRes_1_1 = tmpRes_1.next(); !tmpRes_1_1.done; tmpRes_1_1 = tmpRes_1.next()) {
var neighbor = tmpRes_1_1.value;
if (neighbor.isProcessed)
continue;
var inSearch = toSearch.includes(current);
var costToNeighbor = current.G + current.getManhattanDistanceTo(neighbor);
if (!inSearch || costToNeighbor < neighbor.G) {
neighbor.setG(costToNeighbor);
neighbor.setConnection(current);
current.setFrom(neighbor);
if (!inSearch) {
neighbor.setH(neighbor.getManhattanDistanceTo(endNode));
toSearch.push(neighbor);
}
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (tmpRes_1_1 && !tmpRes_1_1.done && (_b = tmpRes_1.return)) _b.call(tmpRes_1);
}
finally { if (e_3) throw e_3.error; }
}
};
while (toSearch.length) {
var state_1 = _loop_1();
if (typeof state_1 === "object")
return state_1.value;
}
return null;
}
function findNeighborsByGridStep(cur, step, bboxes, outside) {
var neighbors = [];
var x = cur.x, y = cur.y;
var minX = outside.minX, minY = outside.minY, maxX = outside.maxX, maxY = outside.maxY;
var x1 = x - step;
var x2 = x + step;
var y1 = y - step;
var y2 = y + step;
// eslint-disable-next-line no-shadow
function isValid(cur, neighbor, bboxes) {
var e_4, _a;
var flag = !isPointInsideTheBoxes(neighbor, bboxes) &&
!isPointInsideTheBoxes(cur, bboxes);
if (!flag)
return false;
try {
for (var bboxes_2 = __values(bboxes), bboxes_2_1 = bboxes_2.next(); !bboxes_2_1.done; bboxes_2_1 = bboxes_2.next()) {
var bbox = bboxes_2_1.value;
if (isSegmentCrossingBBox([
{
x: cur.x,
y: cur.y,
},
{
x: neighbor.x,
y: neighbor.y,
},
], bbox)) {
flag = false;
break;
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (bboxes_2_1 && !bboxes_2_1.done && (_a = bboxes_2.return)) _a.call(bboxes_2);
}
finally { if (e_4) throw e_4.error; }
}
return flag;
}
if (x1 >= minX) {
isValid(cur, {
x: x1,
y: y,
}, bboxes) && neighbors.push(new NodeBase(x1, y));
}
if (x2 <= maxX) {
isValid(cur, {
x: x2,
y: y,
}, bboxes) && neighbors.push(new NodeBase(x2, y));
}
if (y1 >= minY) {
isValid(cur, {
x: x,
y: y1,
}, bboxes) && neighbors.push(new NodeBase(x, y1));
}
if (y2 <= maxY) {
isValid(cur, {
x: x,
y: y2,
}, bboxes) && neighbors.push(new NodeBase(x, y2));
}
return neighbors;
}
function getAnchorWithOffset(_a, node, offset) {
var bbox = _a.bbox;
var minX = bbox.minX, minY = bbox.minY, maxX = bbox.maxX, maxY = bbox.maxY;
var x = node.x, y = node.y;
if (x === minX) {
return {
x: x - offset,
y: y,
};
}
if (x === maxX) {
return {
x: x + offset,
y: y,
};
}
if (y === minY) {
return {
x: x,
y: y - offset,
};
}
if (y === maxY) {
return {
x: x,
y: y + offset,
};
}
}
function perpendicularDistance(point, lineStart, lineEnd) {
var x1 = lineStart.x, y1 = lineStart.y;
var x2 = lineEnd.x, y2 = lineEnd.y;
var x = point.x, y = point.y;
if (x1 === x2) {
// 线段是垂直的
return Math.abs(x - x1);
}
if (y1 === y2) {
// 线段是水平的
return Math.abs(y - y1);
}
// 计算点到线段垂直点的坐标
var px = x1 +
((x2 - x1) * ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1))) /
(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
var py = y1 +
((y2 - y1) * ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1))) /
(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
// 计算曼哈顿距离
return Math.abs(x - px) + Math.abs(y - py);
}
function perpendicularToStraight(line) {
// Step 1: Convert perpendicular segments to straight lines
var straightLine = [line[0]];
for (var i = 0; i < line.length - 2; i++) {
var point1 = line[i];
var point2 = line[i + 1];
var point3 = line[i + 2];
if (isVertical(point1, point2, point3) ||
isHorizontal(point1, point2, point3)) {
// Remove point2 to make it a straight line
continue;
}
straightLine.push(point2);
}
straightLine.push(line[line.length - 1]);
// Step 2: Douglas-Peucker algorithm to remove redundant points
// return straightLine;
var epsilon = 1.0; // Adjust epsilon based on your requirements
return douglasPeucker(straightLine, epsilon);
}
function isVertical(p1, p2, p3) {
return p1.x === p2.x && p2.x === p3.x;
}
function isHorizontal(p1, p2, p3) {
return p1.y === p2.y && p2.y === p3.y;
}
function douglasPeucker(points, epsilon) {
var dmax = 0;
var index = 0;
for (var i = 1; i < points.length - 1; i++) {
var d = perpendicularDistance(points[i], points[0], points[points.length - 1]);
if (d > dmax) {
index = i;
dmax = d;
}
}
if (dmax > epsilon) {
var left = douglasPeucker(points.slice(0, index + 1), epsilon);
var right = douglasPeucker(points.slice(index), epsilon);
return left.slice(0, left.length - 1).concat(right);
}
return [points[0], points[points.length - 1]];
}
// 每三个点如果其横坐标或者纵坐标都相同,则取其二
function getSimplePath(path) {
// if (path.length < 5) return path;
path = circleDetection(path);
var res = [];
for (var i = 0; i < path.length;) {
var point1 = path[i];
var point2 = path[i + 1];
var point3 = path[i + 2];
if (!point3) {
res.push(point1);
i++;
continue;
}
if ((point1.x === point2.x && point2.x === point3.x) ||
(point1.y === point2.y && point2.y === point3.y)) {
res.push(point1);
res.push(point3);
i += 3;
}
else {
res.push(point1);
i++;
}
}
return res;
}
// 回环检测 & 处理
function circleDetection(path) {
if (path.length < 6)
return path;
var res = [];
for (var i = 0; i < path.length;) {
var point1 = path[i];
var point2 = path[i + 1];
var point4 = path[i + 3];
var point5 = path[i + 4];
if (!point5) {
res.push(point1);
i++;
continue;
}
if (isSegmentsIntersected([point1, point2], [point4, point5])) {
var x = 0;
var y = 0;
if (point1.x === point2.x) {
x = point1.x;
y = point4.y;
}
else {
x = point4.x;
y = point1.y;
}
res.push({
x: x,
y: y,
});
res.push(point5);
i += 4;
continue;
}
res.push(point1);
i++;
}
return res;
}
function getOrient(start, end) {
var x1 = start.x, y1 = start.y;
var x2 = end.x, y2 = end.y;
var prefix = '';
var suffix = '';
if (x1 >= x2) {
prefix = 'left';
}
else {
prefix = 'right';
}
if (y1 >= y2) {
suffix = 'top';
}
else {
suffix = 'bottom';
}
return "".concat(prefix, ":").concat(suffix);
}
exports.getOrient = getOrient;
function ManhattanLayout(startAnchor, endAnchor, startNode, endNode,
// obstacles,
offset) {
// get expanded bbox
var startBBox = startNode.bbox;
var endBBox = endNode.bbox;
var startExpandBBox = expandBBox(startNode.bbox, offset);
var endExpandBBox = expandBBox(endNode.bbox, offset);
// get points from bbox border
var points1 = getPointsFromBBoxBorder(startExpandBBox);
var points2 = getPointsFromBBoxBorder(endExpandBBox);
// is bbox overlap
// const overlap = isBBoxOverlap(startBBox, endBBox);
var outsideBBox = getHull(__spreadArray(__spreadArray([], __read(points1), false), __read(points2), false));
var sNode = getAnchorWithOffset(startNode, startAnchor, offset);
var eNode = getAnchorWithOffset(endNode, endAnchor, offset);
var sNodeBase = new NodeBase(sNode.x, sNode.y);
var eNodeBase = new NodeBase(eNode.x, eNode.y);
var path = aStarFindPathByGrid(eNodeBase, sNodeBase, 10,
// obstacles,
[startBBox, endBBox],
// [startExpandBBox, endExpandBBox],
outsideBBox);
if (path) {
var simplifiedPath = perpendicularToStraight(path);
return getSimplePath(__spreadArray(__spreadArray([endAnchor], __read(simplifiedPath), false), [startAnchor], false).reverse());
}
}
exports.ManhattanLayout = ManhattanLayout;