#1295 First draft of generic renderer applied to flowcharts.

This commit is contained in:
Knut Sveidqvist
2020-03-08 09:49:41 +01:00
parent 25e2d78311
commit aa32d454c9
21 changed files with 639 additions and 1087 deletions

View File

@@ -0,0 +1,17 @@
/*
* Borrowed with love from from dagrge-d3. Many thanks to cpettitt!
*/
import node from './intersect-node';
import circle from './intersect-circle';
import ellipse from './intersect-ellipse';
import polygon from './intersect-polygon';
import rect from './intersect-rect';
module.exports = {
node,
circle,
ellipse,
polygon,
rect
};

View File

@@ -0,0 +1,7 @@
var intersectEllipse = require("./intersect-ellipse");
module.exports = intersectCircle;
function intersectCircle(node, rx, point) {
return intersectEllipse(node, rx, rx, point);
}

View File

@@ -0,0 +1,25 @@
module.exports = intersectEllipse;
function intersectEllipse(node, rx, ry, point) {
// Formulae from: http://mathworld.wolfram.com/Ellipse-LineIntersection.html
var cx = node.x;
var cy = node.y;
var px = cx - point.x;
var py = cy - point.y;
var det = Math.sqrt(rx * rx * py * py + ry * ry * px * px);
var dx = Math.abs(rx * ry * px / det);
if (point.x < cx) {
dx = -dx;
}
var dy = Math.abs(rx * ry * py / det);
if (point.y < cy) {
dy = -dy;
}
return {x: cx + dx, y: cy + dy};
}

View File

@@ -0,0 +1,70 @@
module.exports = intersectLine;
/*
* Returns the point at which two lines, p and q, intersect or returns
* undefined if they do not intersect.
*/
function intersectLine(p1, p2, q1, q2) {
// Algorithm from J. Avro, (ed.) Graphics Gems, No 2, Morgan Kaufmann, 1994,
// p7 and p473.
var a1, a2, b1, b2, c1, c2;
var r1, r2 , r3, r4;
var denom, offset, num;
var x, y;
// Compute a1, b1, c1, where line joining points 1 and 2 is F(x,y) = a1 x +
// b1 y + c1 = 0.
a1 = p2.y - p1.y;
b1 = p1.x - p2.x;
c1 = (p2.x * p1.y) - (p1.x * p2.y);
// Compute r3 and r4.
r3 = ((a1 * q1.x) + (b1 * q1.y) + c1);
r4 = ((a1 * q2.x) + (b1 * q2.y) + c1);
// Check signs of r3 and r4. If both point 3 and point 4 lie on
// same side of line 1, the line segments do not intersect.
if ((r3 !== 0) && (r4 !== 0) && sameSign(r3, r4)) {
return /*DONT_INTERSECT*/;
}
// Compute a2, b2, c2 where line joining points 3 and 4 is G(x,y) = a2 x + b2 y + c2 = 0
a2 = q2.y - q1.y;
b2 = q1.x - q2.x;
c2 = (q2.x * q1.y) - (q1.x * q2.y);
// Compute r1 and r2
r1 = (a2 * p1.x) + (b2 * p1.y) + c2;
r2 = (a2 * p2.x) + (b2 * p2.y) + c2;
// Check signs of r1 and r2. If both point 1 and point 2 lie
// on same side of second line segment, the line segments do
// not intersect.
if ((r1 !== 0) && (r2 !== 0) && (sameSign(r1, r2))) {
return /*DONT_INTERSECT*/;
}
// Line segments intersect: compute intersection point.
denom = (a1 * b2) - (a2 * b1);
if (denom === 0) {
return /*COLLINEAR*/;
}
offset = Math.abs(denom / 2);
// The denom/2 is to get rounding instead of truncating. It
// is added or subtracted to the numerator, depending upon the
// sign of the numerator.
num = (b1 * c2) - (b2 * c1);
x = (num < 0) ? ((num - offset) / denom) : ((num + offset) / denom);
num = (a2 * c1) - (a1 * c2);
y = (num < 0) ? ((num - offset) / denom) : ((num + offset) / denom);
return { x: x, y: y };
}
function sameSign(r1, r2) {
return r1 * r2 > 0;
}

View File

@@ -0,0 +1,5 @@
module.exports = intersectNode;
function intersectNode(node, point) {
return node.intersect(point);
}

View File

@@ -0,0 +1,57 @@
/* eslint "no-console": off */
var intersectLine = require("./intersect-line");
module.exports = intersectPolygon;
/*
* Returns the point ({x, y}) at which the point argument intersects with the
* node argument assuming that it has the shape specified by polygon.
*/
function intersectPolygon(node, polyPoints, point) {
var x1 = node.x;
var y1 = node.y;
var intersections = [];
var minX = Number.POSITIVE_INFINITY;
var minY = Number.POSITIVE_INFINITY;
polyPoints.forEach(function(entry) {
minX = Math.min(minX, entry.x);
minY = Math.min(minY, entry.y);
});
var left = x1 - node.width / 2 - minX;
var top = y1 - node.height / 2 - minY;
for (var i = 0; i < polyPoints.length; i++) {
var p1 = polyPoints[i];
var p2 = polyPoints[i < polyPoints.length - 1 ? i + 1 : 0];
var intersect = intersectLine(node, point,
{x: left + p1.x, y: top + p1.y}, {x: left + p2.x, y: top + p2.y});
if (intersect) {
intersections.push(intersect);
}
}
if (!intersections.length) {
console.log("NO INTERSECTION FOUND, RETURN NODE CENTER", node);
return node;
}
if (intersections.length > 1) {
// More intersections, find the one nearest to edge end point
intersections.sort(function(p, q) {
var pdx = p.x - point.x;
var pdy = p.y - point.y;
var distp = Math.sqrt(pdx * pdx + pdy * pdy);
var qdx = q.x - point.x;
var qdy = q.y - point.y;
var distq = Math.sqrt(qdx * qdx + qdy * qdy);
return (distp < distq) ? -1 : (distp === distq ? 0 : 1);
});
}
return intersections[0];
}

View File

@@ -0,0 +1,32 @@
const intersectRect = (node, point) => {
var x = node.x;
var y = node.y;
// Rectangle intersection algorithm from:
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
var dx = point.x - x;
var dy = point.y - y;
var w = node.width / 2;
var h = node.height / 2;
var sx, sy;
if (Math.abs(dy) * w > Math.abs(dx) * h) {
// Intersection is top or bottom of rect.
if (dy < 0) {
h = -h;
}
sx = dy === 0 ? 0 : (h * dx) / dy;
sy = h;
} else {
// Intersection is left or right of rect.
if (dx < 0) {
w = -w;
}
sx = w;
sy = dx === 0 ? 0 : (w * dy) / dx;
}
return { x: x + sx, y: y + sy };
};
export default intersectRect;