@antv/g2plot
Version:
G2 Plot, a market of plots built with the Grammar of Graphics'
286 lines • 8.87 kB
JavaScript
import * as matrixUtil from '@antv/matrix-util';
import * as _ from '@antv/util';
function magnitude(v) {
var sum = 0;
_.each(v, function (value) {
sum += value * value;
});
return Math.sqrt(sum);
}
function dotProduct2D(va, vb) {
return va.x * vb.y + va.y * vb.x;
}
function angleTo(va, vb) {
var magA = magnitude(va);
var magB = magnitude(vb);
var dot = dotProduct2D(va, vb);
var angle = Math.acos(dot / magA / magB);
return angle;
}
function crossProduct2D(va, vb) {
var magA = magnitude(va);
var magB = magnitude(vb);
var dot = dotProduct2D(va, vb);
var angle = Math.acos(dot / magA / magB);
return magA * magB * Math.sin(angle);
}
function crossProduct3D(va, vb) {
var ax = va.x, ay = va.y, az = va.z;
var bx = vb.x, by = vb.y, bz = vb.z;
var x = ay * bz - az * by;
var y = az * bx - ax * bz;
var z = ax * by - ay * bx;
return { x: x, y: y, z: z };
}
function sub2D(va, vb) {
return { x: va.x - vb.x, y: va.y - vb.y };
}
function applyMatrix(point, matrix, tag) {
if (tag === void 0) { tag = 1; }
var vector = [point.x, point.y, tag];
matrixUtil.vec3.transformMat3(vector, vector, matrix);
return {
x: vector[0],
y: vector[1],
};
}
function isBetween(value, min, max) {
return value >= min && value <= max;
}
var tolerance = 0.001;
function getLineIntersect(p0, p1, p2, p3) {
var E = {
x: p2.x - p0.x,
y: p2.y - p0.y,
};
var D0 = {
x: p1.x - p0.x,
y: p1.y - p0.y,
};
var D1 = {
x: p3.x - p2.x,
y: p3.y - p2.y,
};
var kross = D0.x * D1.y - D0.y * D1.x;
var sqrKross = kross * kross;
var sqrLen0 = D0.x * D0.x + D0.y * D0.y;
var sqrLen1 = D1.x * D1.x + D1.y * D1.y;
var point = null;
if (sqrKross > tolerance * sqrLen0 * sqrLen1) {
var s = (E.x * D1.y - E.y * D1.x) / kross;
var t = (E.x * D0.y - E.y * D0.x) / kross;
if (isBetween(s, 0, 1) && isBetween(t, 0, 1)) {
point = {
x: p0.x + s * D0.x,
y: p0.y + s * D0.y,
};
}
}
return point;
}
function isPointInPolygon(p, polygon) {
/** 射线法 */
var inside = false;
for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
var xi = polygon[i].x;
var yi = polygon[i].y;
var xj = polygon[j].x;
var yj = polygon[j].y;
var intersect = yi > p.y !== yj > p.y && p.x <= ((xj - xi) * (p.y - yi)) / (yj - yi) + xi;
if (intersect) {
inside = !inside;
}
}
return inside;
}
function sqr(v) {
return v * v;
}
function dist2(a, b) {
return Math.sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}
function distBetweenPoints(a, b) {
return Math.sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}
function distBetweenPointLine(p, p1, p2) {
var l2 = dist2(p1, p2);
if (l2 === 0) {
return dist2(p, p1);
}
var t = ((p.x - p1.x) * (p2.x - p1.x) + (p.y - p1.y) * (p2.y - p1.y)) / l2;
t = Math.max(0, Math.min(1, t));
var distSquare = dist2(p, { x: p1.x + t * (p2.x - p1.x), y: p1.y + t * (p2.y - p1.y) });
return Math.sqrt(distSquare);
}
// todo:待优化 https://blog.csdn.net/WilliamSun0122/article/details/77994526
function minDistBetweenPointPolygon(p, polygon) {
var min = Infinity;
/** vertice to vertice */
_.each(polygon, function (v) {
var dist = Math.sqrt(dist2(v, p));
if (min > dist) {
min = dist;
}
});
/** vertice to edge */
for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
var xi = polygon[i].x;
var yi = polygon[i].y;
var xj = polygon[j].x;
var yj = polygon[j].y;
var dist = distBetweenPointLine(p, { x: xi, y: yi }, { x: xj, y: yj });
if (min > dist) {
min = dist;
}
}
return min;
}
function isPolygonIntersection(polyA, polyB) {
for (var _i = 0, polyA_1 = polyA; _i < polyA_1.length; _i++) {
var p = polyA_1[_i];
var inside = isPointInPolygon(p, polyB);
if (inside) {
return true;
}
}
return false;
}
function minDistBetweenConvexPolygon(polyA, polyB) {
if (isPolygonIntersection(polyA, polyB)) {
return 0;
}
var minA = Infinity;
var minB = Infinity;
_.each(polyA, function (v) {
var localMin = minDistBetweenPointPolygon(v, polyB);
if (minA > localMin) {
minA = localMin;
}
});
_.each(polyB, function (v) {
var localMin = minDistBetweenPointPolygon(v, polyA);
if (minB > localMin) {
minB = localMin;
}
});
return Math.min(minA, minB);
}
function bboxOnRotate(shape) {
var bbox = shape.getBBox();
var x = bbox.minX;
var y = bbox.minY;
/*
* step1: 获得旋转后的shape包围盒
* 将包围盒对齐到原点,apply旋转矩阵
* 移回原来的位置
*/
var bboxWidth = bbox.tr.x - bbox.tl.x;
var bboxHeight = bbox.bl.y - bbox.tl.y;
// const matrix = shape.getTotalMatrix();
var matrix = shape.attr('matrix');
var ulMatrix = [matrix[0], matrix[1], 0, matrix[3], matrix[4], 0, 0, 0, 1];
var top_left = applyMatrix({ x: 0, y: 0 }, ulMatrix);
top_left.x += x;
top_left.y += y;
var top_right = applyMatrix({ x: bboxWidth, y: 0 }, ulMatrix);
top_right.x += x;
top_right.y += y;
var bottom_left = applyMatrix({ x: 0, y: bboxHeight }, ulMatrix);
bottom_left.x += x;
bottom_left.y += y;
var bottom_right = applyMatrix({ x: bboxWidth, y: bboxHeight }, ulMatrix);
bottom_right.x += x;
bottom_right.y += y;
/** step2:根据旋转后的画布位置重新计算包围盒,以免图形进行旋转后上下颠倒 */
var points = [top_left, top_right, bottom_left, bottom_right];
points.sort(function (a, b) {
return a.y - b.y;
});
var minY = points[0].y;
var maxY = points[points.length - 1].y;
var tops = [points[0], points[1]];
var bottoms = [points[2], points[3]];
var topLeft = tops[0].x < tops[1].x ? tops[0] : tops[1];
var topRight = tops[0].x < tops[1].x ? tops[1] : tops[0];
var bottomLeft = bottoms[0].x < bottoms[1].x ? bottoms[0] : bottoms[1];
var bottomRight = bottoms[0].x < bottoms[1].x ? bottoms[1] : bottoms[0];
points.sort(function (a, b) {
return a.x - b.x;
});
var minX = points[0].x;
var maxX = points[points.length - 1].x;
var node = {
width: maxX - minX,
height: maxY - minY,
left: minX,
right: maxX,
top: minY,
bottom: maxY,
topLeft: topLeft,
topRight: topRight,
bottomLeft: bottomLeft,
bottomRight: bottomRight,
centerX: minX + (maxX - minX) / 2,
centerY: minY + (maxY - minY) / 2,
};
return node;
}
/**
* 线简化算法
*/
var THRESHOLD = 2;
function lineSimplification(points) {
if (points.length < 5) {
return points;
}
return DouglasPeucker(points, THRESHOLD);
}
// https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm
function DouglasPeucker(points, threshold) {
var result;
var max = -Infinity;
var index = 0;
var endIndex = points.length - 1;
for (var i = 1; i < endIndex; i++) {
var point = points[i];
var line = { start: points[0], end: points[endIndex] };
var dist = distBetweenPointLine(point, line.start, line.end);
if (dist > max) {
max = dist;
index = i;
}
}
if (max > threshold) {
var list1 = DouglasPeucker(points.slice(0, index + 1), threshold);
var list2 = DouglasPeucker(points.slice(index, points.length), threshold);
result = list1.concat(list2);
}
else {
result = [points[0], points[points.length - 1]];
}
return result;
}
/** 统计的以后迁出去,暂时先放这里 */
function getMedian(array) {
var list = _.clone(array);
list.sort(function (a, b) {
return a - b;
});
var half = Math.floor(list.length / 2);
if (list.length % 2) {
return list[half];
}
return (list[half - 1] + list[half]) / 2.0;
}
function getMean(array) {
var sum = 0;
_.each(array, function (num) {
sum += num;
});
return sum / array.length;
}
function sturges(values) {
return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
}
export { applyMatrix, isBetween, getLineIntersect, isPointInPolygon, distBetweenPoints, distBetweenPointLine, isPolygonIntersection, minDistBetweenConvexPolygon, bboxOnRotate, dotProduct2D, crossProduct2D, crossProduct3D, sub2D, angleTo, lineSimplification, getMedian, getMean, sturges, dist2, };
//# sourceMappingURL=math.js.map