@antv/g-math
Advanced tools
Comparing version 1.7.49 to 1.8.0-alpha.1
@@ -1,49 +0,9 @@ | ||
import type { Point, BBox } from './types'; | ||
declare const _default: { | ||
/** | ||
* 计算包围盒 | ||
* @param {number} cx 圆心 x | ||
* @param {number} cy 圆心 y | ||
* @param {number} rx x 轴方向的半径 | ||
* @param {number} ry y 轴方向的半径 | ||
* @param {number} xRotation 旋转角度 | ||
* @param {number} startAngle 起始角度 | ||
* @param {number} endAngle 结束角度 | ||
* @return {object} 包围盒对象 | ||
*/ | ||
box(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number): BBox; | ||
/** | ||
* 获取圆弧的长度,计算圆弧长度时不考虑旋转角度, | ||
* 仅跟 rx, ry, startAngle, endAngle 相关 | ||
* @param {number} cx 圆心 x | ||
* @param {number} cy 圆心 y | ||
* @param {number} rx x 轴方向的半径 | ||
* @param {number} ry y 轴方向的半径 | ||
* @param {number} xRotation 旋转角度 | ||
* @param {number} startAngle 起始角度 | ||
* @param {number} endAngle 结束角度 | ||
*/ | ||
length(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number): void; | ||
/** | ||
* 获取指定点到圆弧的最近距离的点 | ||
* @param {number} cx 圆心 x | ||
* @param {number} cy 圆心 y | ||
* @param {number} rx x 轴方向的半径 | ||
* @param {number} ry y 轴方向的半径 | ||
* @param {number} xRotation 旋转角度 | ||
* @param {number} startAngle 起始角度 | ||
* @param {number} endAngle 结束角度 | ||
* @param {number} x0 指定点的 x | ||
* @param {number} y0 指定点的 y | ||
* @return {object} 到指定点最近距离的点 | ||
*/ | ||
nearestPoint(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number, x0: number, y0: number): { | ||
x: number; | ||
y: number; | ||
}; | ||
pointDistance(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number, x0: number, y0: number): number; | ||
pointAt(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number, t: number): Point; | ||
tangentAngle(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number, t: number): number; | ||
import type { BBox, Point } from './types'; | ||
export declare function box(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number): BBox; | ||
export declare function nearestPoint(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number, x0: number, y0: number): { | ||
x: number; | ||
y: number; | ||
}; | ||
export default _default; | ||
//# sourceMappingURL=arc.d.ts.map | ||
export declare function pointDistance(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number, x0: number, y0: number): number; | ||
export declare function pointAt(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number, t: number): Point; | ||
export declare function tangentAngle(cx: number, cy: number, rx: number, ry: number, xRotation: number, startAngle: number, endAngle: number, t: number): number; |
@@ -12,2 +12,1 @@ import type { Point } from './types'; | ||
export declare function snapLength(xArr: number[], yArr: number[]): number; | ||
//# sourceMappingURL=bezier.d.ts.map |
import type { Point } from './types'; | ||
declare function cubicAt(p0: number, p1: number, p2: number, p3: number, t: number): number; | ||
declare function extrema(p0: number, p1: number, p2: number, p3: number): any[]; | ||
declare const _default: { | ||
extrema: typeof extrema; | ||
box(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): import("./types").BBox; | ||
length(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): number; | ||
nearestPoint(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, x0: number, y0: number, length?: number): Point; | ||
pointDistance(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, x0: number, y0: number, length?: number): number; | ||
interpolationAt: typeof cubicAt; | ||
pointAt(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, t: number): Point; | ||
divide(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, t: number): [number, number, number, number, number, number, number, number][]; | ||
tangentAngle(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, t: number): number; | ||
}; | ||
export default _default; | ||
//# sourceMappingURL=cubic.d.ts.map | ||
export declare function box(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): import("./types").BBox; | ||
export declare function length(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): number; | ||
export declare function nearestPoint(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, x0: number, y0: number, length?: number): Point; | ||
export declare function pointDistance(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, x0: number, y0: number, length?: number): number; | ||
export declare function pointAt(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, t: number): Point; | ||
export declare function divide(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, t: number): [number, number, number, number, number, number, number, number][]; | ||
export declare function tangentAngle(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number, t: number): number; |
@@ -1,74 +0,10 @@ | ||
/** | ||
* @fileoverview 椭圆的一些计算, | ||
* - 周长计算参考:https://www.mathsisfun.com/geometry/ellipse-perimeter.html | ||
* - 距离计算参考:https://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/ | ||
* @author dxq613@gmail.com | ||
*/ | ||
import type { Point, BBox } from './types'; | ||
declare const _default: { | ||
/** | ||
* 包围盒计算 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @return {object} 包围盒 | ||
*/ | ||
box(x: number, y: number, rx: number, ry: number): BBox; | ||
/** | ||
* 计算周长,使用近似法 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @return {number} 椭圆周长 | ||
*/ | ||
length(x: number, y: number, rx: number, ry: number): number; | ||
/** | ||
* 距离椭圆最近的点 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} x0 指定的点 x | ||
* @param {number} y0 指定的点 y | ||
* @return {object} 椭圆上距离指定点最近的点 | ||
*/ | ||
nearestPoint(x: number, y: number, rx: number, ry: number, x0: number, y0: number): { | ||
x: number; | ||
y: number; | ||
}; | ||
/** | ||
* 点到椭圆最近的距离 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} x0 指定的点 x | ||
* @param {number} y0 指定的点 y | ||
* @return {number} 点到椭圆的距离 | ||
*/ | ||
pointDistance(x: number, y: number, rx: number, ry: number, x0: number, y0: number): number; | ||
/** | ||
* 根据比例获取点 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} t 指定比例,x轴方向为 0 | ||
* @return {object} 点 | ||
*/ | ||
pointAt(x: number, y: number, rx: number, ry: number, t: number): Point; | ||
/** | ||
* 根据比例计算切线角度 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} t 指定比例 0 - 1 之间,x轴方向为 0。在 0-1 范围之外是循环还是返回 null,还需要调整 | ||
* @return {number} 角度,在 0 - 2PI 之间 | ||
*/ | ||
tangentAngle(x: number, y: number, rx: number, ry: number, t: number): number; | ||
import type { BBox, Point } from './types'; | ||
export declare function box(x: number, y: number, rx: number, ry: number): BBox; | ||
export declare function length(x: number, y: number, rx: number, ry: number): number; | ||
export declare function nearestPoint(x: number, y: number, rx: number, ry: number, x0: number, y0: number): { | ||
x: number; | ||
y: number; | ||
}; | ||
export default _default; | ||
//# sourceMappingURL=ellipse.d.ts.map | ||
export declare function pointDistance(x: number, y: number, rx: number, ry: number, x0: number, y0: number): number; | ||
export declare function pointAt(x: number, y: number, rx: number, ry: number, t: number): Point; | ||
export declare function tangentAngle(x: number, y: number, rx: number, ry: number, t: number): number; |
@@ -1,9 +0,8 @@ | ||
import Quad from './quadratic'; | ||
import Cubic from './cubic'; | ||
import Arc from './arc'; | ||
import Line from './line'; | ||
import Polygon from './polygon'; | ||
import Polyline from './polyline'; | ||
import * as Util from './util'; | ||
export { Quad, Cubic, Arc, Line, Polygon, Polyline, Util }; | ||
//# sourceMappingURL=index.d.ts.map | ||
import { box as arcBox, nearestPoint as arcNearestPoint, tangentAngle as arcTangentAngle } from './arc'; | ||
import { box as cubicBox, length as cubicLength, nearestPoint as cubicNearestPoint, pointAt as cubicPointAt, pointDistance as cubicPointDistance, tangentAngle as cubicTangentAngle } from './cubic'; | ||
import { box as lineBox, length as lineLength, pointAt as linePointAt, pointDistance as linePointDistance, pointToLine as linePointToLine, tangentAngle as lineTangentAngle } from './line'; | ||
import { box as polygonBox, length as polygonLength, pointAt as polygonPointAt, pointDistance as polygonPointDistance, tangentAngle as polygonTangentAngle } from './polygon'; | ||
import { box as polylineBox, length as polylineLength, pointAt as polylinePointAt, pointDistance as polylinePointDistance, tangentAngle as polylineTangentAngle } from './polyline'; | ||
import { box as quadBox, length as quadLength, nearestPoint as quadNearestPoint, pointDistance as quadPointDistance } from './quadratic'; | ||
import { distance } from './util'; | ||
export { distance, quadBox, quadLength, quadPointDistance, quadNearestPoint, cubicBox, cubicLength, cubicNearestPoint, cubicPointDistance, cubicPointAt, cubicTangentAngle, polygonBox, polygonLength, polygonPointDistance, polygonPointAt, polygonTangentAngle, polylineBox, polylineLength, polylinePointDistance, polylinePointAt, polylineTangentAngle, lineBox, lineLength, linePointDistance, linePointAt, linePointToLine, lineTangentAngle, arcBox, arcTangentAngle, arcNearestPoint, }; |
@@ -0,473 +1,33 @@ | ||
import { __spreadArray, __read } from 'tslib'; | ||
import { vec2 } from 'gl-matrix'; | ||
/** | ||
* 两点之间的距离 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {number} 距离 | ||
*/ | ||
function distance(x1, y1, x2, y2) { | ||
var dx = x1 - x2; | ||
var dy = y1 - y2; | ||
return Math.sqrt(dx * dx + dy * dy); | ||
var dx = x1 - x2; | ||
var dy = y1 - y2; | ||
return Math.sqrt(dx * dx + dy * dy); | ||
} | ||
function isNumberEqual(v1, v2) { | ||
return Math.abs(v1 - v2) < 0.001; | ||
return Math.abs(v1 - v2) < 0.001; | ||
} | ||
function getBBoxByArray(xArr, yArr) { | ||
var minX = Math.min.apply(Math, xArr); | ||
var minY = Math.min.apply(Math, yArr); | ||
var maxX = Math.max.apply(Math, xArr); | ||
var maxY = Math.max.apply(Math, yArr); | ||
return { | ||
x: minX, | ||
y: minY, | ||
width: maxX - minX, | ||
height: maxY - minY | ||
}; | ||
} | ||
function getBBoxRange(x1, y1, x2, y2) { | ||
return { | ||
minX: Math.min(x1, x2), | ||
maxX: Math.max(x1, x2), | ||
minY: Math.min(y1, y2), | ||
maxY: Math.max(y1, y2) | ||
}; | ||
} | ||
function piMod(angle) { | ||
return (angle + Math.PI * 2) % (Math.PI * 2); | ||
} | ||
var util = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
distance: distance, | ||
isNumberEqual: isNumberEqual, | ||
getBBoxByArray: getBBoxByArray, | ||
getBBoxRange: getBBoxRange, | ||
piMod: piMod | ||
}); | ||
var line = { | ||
/** | ||
* 计算线段的包围盒 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {object} 包围盒对象 | ||
*/ | ||
box: function box(x1, y1, x2, y2) { | ||
return getBBoxByArray([x1, x2], [y1, y2]); | ||
}, | ||
/** | ||
* 线段的长度 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {number} 距离 | ||
*/ | ||
length: function length(x1, y1, x2, y2) { | ||
return distance(x1, y1, x2, y2); | ||
}, | ||
/** | ||
* 根据比例获取点 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @param {number} t 指定比例 | ||
* @return {object} 包含 x, y 的点 | ||
*/ | ||
pointAt: function pointAt(x1, y1, x2, y2, t) { | ||
var minX = Math.min.apply(Math, __spreadArray([], __read(xArr), false)); | ||
var minY = Math.min.apply(Math, __spreadArray([], __read(yArr), false)); | ||
var maxX = Math.max.apply(Math, __spreadArray([], __read(xArr), false)); | ||
var maxY = Math.max.apply(Math, __spreadArray([], __read(yArr), false)); | ||
return { | ||
x: (1 - t) * x1 + t * x2, | ||
y: (1 - t) * y1 + t * y2 | ||
x: minX, | ||
y: minY, | ||
width: maxX - minX, | ||
height: maxY - minY, | ||
}; | ||
}, | ||
/** | ||
* 点到线段的距离 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @param {number} x 测试点 x | ||
* @param {number} y 测试点 y | ||
* @return {number} 距离 | ||
*/ | ||
pointDistance: function pointDistance(x1, y1, x2, y2, x, y) { | ||
// 投影距离 x1, y1 的向量,假设 p, p1, p2 三个点,投影点为 a | ||
// p1a = p1p.p1p2/|p1p2| * (p1p 的单位向量) | ||
var cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1); | ||
if (cross < 0) { | ||
return distance(x1, y1, x, y); | ||
} | ||
var lengthSquare = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); | ||
if (cross > lengthSquare) { | ||
return distance(x2, y2, x, y); | ||
} | ||
return this.pointToLine(x1, y1, x2, y2, x, y); | ||
}, | ||
/** | ||
* 点到直线的距离,而不是点到线段的距离 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @param {number} x 测试点 x | ||
* @param {number} y 测试点 y | ||
* @return {number} 距离 | ||
*/ | ||
pointToLine: function pointToLine(x1, y1, x2, y2, x, y) { | ||
var d = [x2 - x1, y2 - y1]; | ||
// 如果端点相等,则判定点到点的距离 | ||
if (vec2.exactEquals(d, [0, 0])) { | ||
return Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)); | ||
} | ||
var u = [-d[1], d[0]]; | ||
vec2.normalize(u, u); | ||
var a = [x - x1, y - y1]; | ||
return Math.abs(vec2.dot(a, u)); | ||
}, | ||
/** | ||
* 线段的角度 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {number} 导数 | ||
*/ | ||
tangentAngle: function tangentAngle(x1, y1, x2, y2) { | ||
return Math.atan2(y2 - y1, x2 - x1); | ||
} | ||
}; | ||
var EPSILON = 0.0001; | ||
/** | ||
* 使用牛顿切割法求最近的点 | ||
* @param {number[]} xArr 点的 x 数组 | ||
* @param {number[]} yArr 点的 y 数组 | ||
* @param {number} x 指定的点 x | ||
* @param {number} y 指定的点 y | ||
* @param {Function} tCallback 差值函数 | ||
*/ | ||
function nearestPoint(xArr, yArr, x, y, tCallback, length) { | ||
var t = -1; | ||
var d = Infinity; | ||
var v0 = [x, y]; | ||
var segNum = 20; | ||
if (length && length > 200) { | ||
segNum = length / 10; | ||
} | ||
var increaseRate = 1 / segNum; | ||
var interval = increaseRate / 10; | ||
for (var i = 0; i <= segNum; i++) { | ||
var _t = i * increaseRate; | ||
var v1 = [tCallback.apply(void 0, xArr.concat([_t])), tCallback.apply(void 0, yArr.concat([_t]))]; | ||
var d1 = distance(v0[0], v0[1], v1[0], v1[1]); | ||
if (d1 < d) { | ||
t = _t; | ||
d = d1; | ||
} | ||
} | ||
// 提前终止 | ||
if (t === 0) { | ||
return { | ||
x: xArr[0], | ||
y: yArr[0] | ||
}; | ||
} | ||
if (t === 1) { | ||
var count = xArr.length; | ||
return { | ||
x: xArr[count - 1], | ||
y: yArr[count - 1] | ||
}; | ||
} | ||
d = Infinity; | ||
for (var _i = 0; _i < 32; _i++) { | ||
if (interval < EPSILON) { | ||
break; | ||
} | ||
var prev = t - interval; | ||
var next = t + interval; | ||
var _v = [tCallback.apply(void 0, xArr.concat([prev])), tCallback.apply(void 0, yArr.concat([prev]))]; | ||
var _d = distance(v0[0], v0[1], _v[0], _v[1]); | ||
if (prev >= 0 && _d < d) { | ||
t = prev; | ||
d = _d; | ||
} else { | ||
var v2 = [tCallback.apply(void 0, xArr.concat([next])), tCallback.apply(void 0, yArr.concat([next]))]; | ||
var d2 = distance(v0[0], v0[1], v2[0], v2[1]); | ||
if (next <= 1 && d2 < d) { | ||
t = next; | ||
d = d2; | ||
} else { | ||
interval *= 0.5; | ||
} | ||
} | ||
} | ||
return { | ||
x: tCallback.apply(void 0, xArr.concat([t])), | ||
y: tCallback.apply(void 0, yArr.concat([t])) | ||
}; | ||
} | ||
// 近似求解 https://community.khronos.org/t/3d-cubic-bezier-segment-length/62363/2 | ||
function snapLength(xArr, yArr) { | ||
var totalLength = 0; | ||
var count = xArr.length; | ||
for (var i = 0; i < count; i++) { | ||
var x = xArr[i]; | ||
var y = yArr[i]; | ||
var nextX = xArr[(i + 1) % count]; | ||
var nextY = yArr[(i + 1) % count]; | ||
totalLength += distance(x, y, nextX, nextY); | ||
} | ||
return totalLength / 2; | ||
function piMod(angle) { | ||
return (angle + Math.PI * 2) % (Math.PI * 2); | ||
} | ||
// 差值公式 | ||
function quadraticAt(p0, p1, p2, t) { | ||
var onet = 1 - t; | ||
return onet * onet * p0 + 2 * t * onet * p1 + t * t * p2; | ||
} | ||
// 求极值 | ||
function extrema(p0, p1, p2) { | ||
var a = p0 + p2 - 2 * p1; | ||
if (isNumberEqual(a, 0)) { | ||
return [0.5]; | ||
} | ||
var rst = (p0 - p1) / a; | ||
if (rst <= 1 && rst >= 0) { | ||
return [rst]; | ||
} | ||
return []; | ||
} | ||
function derivativeAt(p0, p1, p2, t) { | ||
return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1); | ||
} | ||
// 分割贝塞尔曲线 | ||
function divideQuadratic(x1, y1, x2, y2, x3, y3, t) { | ||
// 划分点 | ||
var xt = quadraticAt(x1, x2, x3, t); | ||
var yt = quadraticAt(y1, y2, y3, t); | ||
// 分割的第一条曲线的控制点 | ||
var controlPoint1 = line.pointAt(x1, y1, x2, y2, t); | ||
// 分割的第二条曲线的控制点 | ||
var controlPoint2 = line.pointAt(x2, y2, x3, y3, t); | ||
return [[x1, y1, controlPoint1.x, controlPoint1.y, xt, yt], [xt, yt, controlPoint2.x, controlPoint2.y, x3, y3]]; | ||
} | ||
// 使用迭代法取贝塞尔曲线的长度 | ||
function quadraticLength(x1, y1, x2, y2, x3, y3, iterationCount) { | ||
if (iterationCount === 0) { | ||
return (distance(x1, y1, x2, y2) + distance(x2, y2, x3, y3) + distance(x1, y1, x3, y3)) / 2; | ||
} | ||
var quadratics = divideQuadratic(x1, y1, x2, y2, x3, y3, 0.5); | ||
var left = quadratics[0]; | ||
var right = quadratics[1]; | ||
left.push(iterationCount - 1); | ||
right.push(iterationCount - 1); | ||
return quadraticLength.apply(void 0, left) + quadraticLength.apply(void 0, right); | ||
} | ||
var quadratic = { | ||
box: function box(x1, y1, x2, y2, x3, y3) { | ||
var xExtrema = extrema(x1, x2, x3)[0]; | ||
var yExtrema = extrema(y1, y2, y3)[0]; | ||
// 控制点不加入 box 的计算 | ||
var xArr = [x1, x3]; | ||
var yArr = [y1, y3]; | ||
if (xExtrema !== undefined) { | ||
xArr.push(quadraticAt(x1, x2, x3, xExtrema)); | ||
} | ||
if (yExtrema !== undefined) { | ||
yArr.push(quadraticAt(y1, y2, y3, yExtrema)); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
}, | ||
length: function length(x1, y1, x2, y2, x3, y3) { | ||
return quadraticLength(x1, y1, x2, y2, x3, y3, 3); | ||
}, | ||
nearestPoint: function nearestPoint$1(x1, y1, x2, y2, x3, y3, x0, y0) { | ||
return nearestPoint([x1, x2, x3], [y1, y2, y3], x0, y0, quadraticAt); | ||
}, | ||
pointDistance: function pointDistance(x1, y1, x2, y2, x3, y3, x0, y0) { | ||
var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x0, y0); | ||
return distance(point.x, point.y, x0, y0); | ||
}, | ||
interpolationAt: quadraticAt, | ||
pointAt: function pointAt(x1, y1, x2, y2, x3, y3, t) { | ||
return { | ||
x: quadraticAt(x1, x2, x3, t), | ||
y: quadraticAt(y1, y2, y3, t) | ||
}; | ||
}, | ||
divide: function divide(x1, y1, x2, y2, x3, y3, t) { | ||
return divideQuadratic(x1, y1, x2, y2, x3, y3, t); | ||
}, | ||
tangentAngle: function tangentAngle(x1, y1, x2, y2, x3, y3, t) { | ||
var dx = derivativeAt(x1, x2, x3, t); | ||
var dy = derivativeAt(y1, y2, y3, t); | ||
var angle = Math.atan2(dy, dx); | ||
return piMod(angle); | ||
} | ||
}; | ||
function cubicAt(p0, p1, p2, p3, t) { | ||
var onet = 1 - t; // t * t * t 的性能大概是 Math.pow(t, 3) 的三倍 | ||
return onet * onet * onet * p0 + 3 * p1 * t * onet * onet + 3 * p2 * t * t * onet + p3 * t * t * t; | ||
} | ||
function derivativeAt$1(p0, p1, p2, p3, t) { | ||
var onet = 1 - t; | ||
return 3 * (onet * onet * (p1 - p0) + 2 * onet * t * (p2 - p1) + t * t * (p3 - p2)); | ||
} | ||
function extrema$1(p0, p1, p2, p3) { | ||
var a = -3 * p0 + 9 * p1 - 9 * p2 + 3 * p3; | ||
var b = 6 * p0 - 12 * p1 + 6 * p2; | ||
var c = 3 * p1 - 3 * p0; | ||
var extremas = []; | ||
var t1; | ||
var t2; | ||
var discSqrt; | ||
if (isNumberEqual(a, 0)) { | ||
if (!isNumberEqual(b, 0)) { | ||
t1 = -c / b; | ||
if (t1 >= 0 && t1 <= 1) { | ||
extremas.push(t1); | ||
} | ||
} | ||
} else { | ||
var disc = b * b - 4 * a * c; | ||
if (isNumberEqual(disc, 0)) { | ||
extremas.push(-b / (2 * a)); | ||
} else if (disc > 0) { | ||
discSqrt = Math.sqrt(disc); | ||
t1 = (-b + discSqrt) / (2 * a); | ||
t2 = (-b - discSqrt) / (2 * a); | ||
if (t1 >= 0 && t1 <= 1) { | ||
extremas.push(t1); | ||
} | ||
if (t2 >= 0 && t2 <= 1) { | ||
extremas.push(t2); | ||
} | ||
} | ||
} | ||
return extremas; | ||
} | ||
// 分割贝塞尔曲线 | ||
function divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
// 划分点 | ||
var xt = cubicAt(x1, x2, x3, x4, t); | ||
var yt = cubicAt(y1, y2, y3, y4, t); | ||
// 计算两点之间的差值点 | ||
var c1 = line.pointAt(x1, y1, x2, y2, t); | ||
var c2 = line.pointAt(x2, y2, x3, y3, t); | ||
var c3 = line.pointAt(x3, y3, x4, y4, t); | ||
var c12 = line.pointAt(c1.x, c1.y, c2.x, c2.y, t); | ||
var c23 = line.pointAt(c2.x, c2.y, c3.x, c3.y, t); | ||
return [[x1, y1, c1.x, c1.y, c12.x, c12.y, xt, yt], [xt, yt, c23.x, c23.y, c3.x, c3.y, x4, y4]]; | ||
} | ||
// 使用迭代法取贝塞尔曲线的长度,二阶和三阶分开写,更清晰和便于调试 | ||
function cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, iterationCount) { | ||
if (iterationCount === 0) { | ||
return snapLength([x1, x2, x3, x4], [y1, y2, y3, y4]); | ||
} | ||
var cubics = divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0.5); | ||
var left = [].concat(cubics[0], [iterationCount - 1]); | ||
var right = [].concat(cubics[1], [iterationCount - 1]); | ||
return cubicLength.apply(void 0, left) + cubicLength.apply(void 0, right); | ||
} | ||
var cubic = { | ||
extrema: extrema$1, | ||
box: function box(x1, y1, x2, y2, x3, y3, x4, y4) { | ||
var xArr = [x1, x4]; | ||
var yArr = [y1, y4]; | ||
var xExtrema = extrema$1(x1, x2, x3, x4); | ||
var yExtrema = extrema$1(y1, y2, y3, y4); | ||
for (var i = 0; i < xExtrema.length; i++) { | ||
xArr.push(cubicAt(x1, x2, x3, x4, xExtrema[i])); | ||
} | ||
for (var _i = 0; _i < yExtrema.length; _i++) { | ||
yArr.push(cubicAt(y1, y2, y3, y4, yExtrema[_i])); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
}, | ||
length: function length(x1, y1, x2, y2, x3, y3, x4, y4) { | ||
// 迭代三次,划分成 8 段求长度 | ||
return cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, 3); | ||
}, | ||
nearestPoint: function nearestPoint$1(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { | ||
return nearestPoint([x1, x2, x3, x4], [y1, y2, y3, y4], x0, y0, cubicAt, length); | ||
}, | ||
pointDistance: function pointDistance(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { | ||
var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length); | ||
return distance(point.x, point.y, x0, y0); | ||
}, | ||
interpolationAt: cubicAt, | ||
pointAt: function pointAt(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
return { | ||
x: cubicAt(x1, x2, x3, x4, t), | ||
y: cubicAt(y1, y2, y3, y4, t) | ||
}; | ||
}, | ||
divide: function divide(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
return divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t); | ||
}, | ||
tangentAngle: function tangentAngle(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
var dx = derivativeAt$1(x1, x2, x3, x4, t); | ||
var dy = derivativeAt$1(y1, y2, y3, y4, t); | ||
return piMod(Math.atan2(dy, dx)); | ||
} | ||
}; | ||
/** | ||
* @fileoverview 椭圆的一些计算, | ||
* - 周长计算参考:https://www.mathsisfun.com/geometry/ellipse-perimeter.html | ||
* - 距离计算参考:https://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/ | ||
* @author dxq613@gmail.com | ||
*/ | ||
function copysign(v1, v2) { | ||
var absv = Math.abs(v1); | ||
return v2 > 0 ? absv : absv * -1; | ||
var absv = Math.abs(v1); | ||
return v2 > 0 ? absv : absv * -1; | ||
} | ||
var ellipse = { | ||
/** | ||
* 包围盒计算 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @return {object} 包围盒 | ||
*/ | ||
box: function box(x, y, rx, ry) { | ||
return { | ||
x: x - rx, | ||
y: y - ry, | ||
width: rx * 2, | ||
height: ry * 2 | ||
}; | ||
}, | ||
/** | ||
* 计算周长,使用近似法 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @return {number} 椭圆周长 | ||
*/ | ||
length: function length(x, y, rx, ry) { | ||
return Math.PI * (3 * (rx + ry) - Math.sqrt((3 * rx + ry) * (rx + 3 * ry))); | ||
}, | ||
/** | ||
* 距离椭圆最近的点 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} x0 指定的点 x | ||
* @param {number} y0 指定的点 y | ||
* @return {object} 椭圆上距离指定点最近的点 | ||
*/ | ||
nearestPoint: function nearestPoint(x, y, rx, ry, x0, y0) { | ||
function nearestPoint$4(x, y, rx, ry, x0, y0) { | ||
var a = rx; | ||
@@ -477,6 +37,6 @@ var b = ry; | ||
if (a === 0 || b === 0) { | ||
return { | ||
x: x, | ||
y: y | ||
}; | ||
return { | ||
x: x, | ||
y: y, | ||
}; | ||
} | ||
@@ -496,131 +56,74 @@ // 转换成 0, 0 为中心的椭圆计算 | ||
for (var i = 0; i < 4; i++) { | ||
nearestX = a * Math.cos(t); | ||
nearestY = b * Math.sin(t); | ||
var ex = (squareA - squareB) * Math.pow(Math.cos(t), 3) / a; | ||
var ey = (squareB - squareA) * Math.pow(Math.sin(t), 3) / b; | ||
var rx1 = nearestX - ex; | ||
var ry1 = nearestY - ey; | ||
var qx = px - ex; | ||
var qy = py - ey; | ||
var r = Math.hypot(ry1, rx1); | ||
var q = Math.hypot(qy, qx); | ||
var delta_c = r * Math.asin((rx1 * qy - ry1 * qx) / (r * q)); | ||
var delta_t = delta_c / Math.sqrt(squareA + squareB - nearestX * nearestX - nearestY * nearestY); | ||
t += delta_t; | ||
t = Math.min(Math.PI / 2, Math.max(0, t)); | ||
nearestX = a * Math.cos(t); | ||
nearestY = b * Math.sin(t); | ||
var ex = ((squareA - squareB) * Math.pow(Math.cos(t), 3)) / a; | ||
var ey = ((squareB - squareA) * Math.pow(Math.sin(t), 3)) / b; | ||
var rx1 = nearestX - ex; | ||
var ry1 = nearestY - ey; | ||
var qx = px - ex; | ||
var qy = py - ey; | ||
var r = Math.hypot(ry1, rx1); | ||
var q = Math.hypot(qy, qx); | ||
var delta_c = r * Math.asin((rx1 * qy - ry1 * qx) / (r * q)); | ||
var delta_t = delta_c / | ||
Math.sqrt(squareA + squareB - nearestX * nearestX - nearestY * nearestY); | ||
t += delta_t; | ||
t = Math.min(Math.PI / 2, Math.max(0, t)); | ||
} | ||
return { | ||
x: x + copysign(nearestX, relativeX), | ||
y: y + copysign(nearestY, relativeY) | ||
x: x + copysign(nearestX, relativeX), | ||
y: y + copysign(nearestY, relativeY), | ||
}; | ||
}, | ||
/** | ||
* 点到椭圆最近的距离 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} x0 指定的点 x | ||
* @param {number} y0 指定的点 y | ||
* @return {number} 点到椭圆的距离 | ||
*/ | ||
pointDistance: function pointDistance(x, y, rx, ry, x0, y0) { | ||
var nearestPoint = this.nearestPoint(x, y, rx, ry, x0, y0); | ||
return distance(nearestPoint.x, nearestPoint.y, x0, y0); | ||
}, | ||
/** | ||
* 根据比例获取点 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} t 指定比例,x轴方向为 0 | ||
* @return {object} 点 | ||
*/ | ||
pointAt: function pointAt(x, y, rx, ry, t) { | ||
var angle = 2 * Math.PI * t; // 按照角度进行计算,而不按照周长计算 | ||
return { | ||
x: x + rx * Math.cos(angle), | ||
y: y + ry * Math.sin(angle) | ||
}; | ||
}, | ||
/** | ||
* 根据比例计算切线角度 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} t 指定比例 0 - 1 之间,x轴方向为 0。在 0-1 范围之外是循环还是返回 null,还需要调整 | ||
* @return {number} 角度,在 0 - 2PI 之间 | ||
*/ | ||
tangentAngle: function tangentAngle(x, y, rx, ry, t) { | ||
var angle = 2 * Math.PI * t; // 按照角度进行计算,而不按照周长计算 | ||
// 直接使用 x,y 的导数计算, x' = -rx * sin(t); y' = ry * cos(t); | ||
var tangentAngle = Math.atan2(ry * Math.cos(angle), -rx * Math.sin(angle)); | ||
// 也可以使用指定点的切线方程计算,成本有些高 | ||
// const point = this.pointAt(0, 0, rx, ry, t); // 椭圆的切线同椭圆的中心不相关 | ||
// let tangentAngle = -1 * Math.atan((ry * ry * point.x) / (rx * rx * point.y)); | ||
// if (angle >= 0 && angle <= Math.PI) { | ||
// tangentAngle += Math.PI; | ||
// } | ||
return piMod(tangentAngle); | ||
} | ||
}; | ||
} | ||
// 偏导数 x | ||
function derivativeXAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle) { | ||
return -1 * rx * Math.cos(xRotation) * Math.sin(angle) - ry * Math.sin(xRotation) * Math.cos(angle); | ||
return (-1 * rx * Math.cos(xRotation) * Math.sin(angle) - | ||
ry * Math.sin(xRotation) * Math.cos(angle)); | ||
} | ||
// 偏导数 y | ||
function derivativeYAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle) { | ||
return -1 * rx * Math.sin(xRotation) * Math.sin(angle) + ry * Math.cos(xRotation) * Math.cos(angle); | ||
return (-1 * rx * Math.sin(xRotation) * Math.sin(angle) + | ||
ry * Math.cos(xRotation) * Math.cos(angle)); | ||
} | ||
// x 的极值 | ||
function xExtrema(rx, ry, xRotation) { | ||
return Math.atan(-ry / rx * Math.tan(xRotation)); | ||
return Math.atan((-ry / rx) * Math.tan(xRotation)); | ||
} | ||
// y 的极值 | ||
function yExtrema(rx, ry, xRotation) { | ||
return Math.atan(ry / (rx * Math.tan(xRotation))); | ||
return Math.atan(ry / (rx * Math.tan(xRotation))); | ||
} | ||
// 根据角度求 x 坐标 | ||
function xAt(cx, cy, rx, ry, xRotation, angle) { | ||
return rx * Math.cos(xRotation) * Math.cos(angle) - ry * Math.sin(xRotation) * Math.sin(angle) + cx; | ||
return (rx * Math.cos(xRotation) * Math.cos(angle) - | ||
ry * Math.sin(xRotation) * Math.sin(angle) + | ||
cx); | ||
} | ||
// 根据角度求 y 坐标 | ||
function yAt(cx, cy, rx, ry, xRotation, angle) { | ||
return rx * Math.sin(xRotation) * Math.cos(angle) + ry * Math.cos(xRotation) * Math.sin(angle) + cy; | ||
return (rx * Math.sin(xRotation) * Math.cos(angle) + | ||
ry * Math.cos(xRotation) * Math.sin(angle) + | ||
cy); | ||
} | ||
// 获取点在椭圆上的角度 | ||
function getAngle(rx, ry, x0, y0) { | ||
var angle = Math.atan2(y0 * rx, x0 * ry); | ||
// 转换到 0 - 2PI 内 | ||
return (angle + Math.PI * 2) % (Math.PI * 2); | ||
var angle = Math.atan2(y0 * rx, x0 * ry); | ||
// 转换到 0 - 2PI 内 | ||
return (angle + Math.PI * 2) % (Math.PI * 2); | ||
} | ||
// 根据角度获取,x,y | ||
function getPoint(rx, ry, angle) { | ||
return { | ||
x: rx * Math.cos(angle), | ||
y: ry * Math.sin(angle) | ||
}; | ||
return { | ||
x: rx * Math.cos(angle), | ||
y: ry * Math.sin(angle), | ||
}; | ||
} | ||
// 旋转 | ||
function rotate(x, y, angle) { | ||
var cos = Math.cos(angle); | ||
var sin = Math.sin(angle); | ||
return [x * cos - y * sin, x * sin + y * cos]; | ||
var cos = Math.cos(angle); | ||
var sin = Math.sin(angle); | ||
return [x * cos - y * sin, x * sin + y * cos]; | ||
} | ||
var arc = { | ||
/** | ||
* 计算包围盒 | ||
* @param {number} cx 圆心 x | ||
* @param {number} cy 圆心 y | ||
* @param {number} rx x 轴方向的半径 | ||
* @param {number} ry y 轴方向的半径 | ||
* @param {number} xRotation 旋转角度 | ||
* @param {number} startAngle 起始角度 | ||
* @param {number} endAngle 结束角度 | ||
* @return {object} 包围盒对象 | ||
*/ | ||
box: function box(cx, cy, rx, ry, xRotation, startAngle, endAngle) { | ||
function box$5(cx, cy, rx, ry, xRotation, startAngle, endAngle) { | ||
var xDim = xExtrema(rx, ry, xRotation); | ||
@@ -631,21 +134,22 @@ var minX = Infinity; | ||
for (var i = -Math.PI * 2; i <= Math.PI * 2; i += Math.PI) { | ||
var xAngle = xDim + i; | ||
if (startAngle < endAngle) { | ||
if (startAngle < xAngle && xAngle < endAngle) { | ||
xs.push(xAngle); | ||
var xAngle = xDim + i; | ||
if (startAngle < endAngle) { | ||
if (startAngle < xAngle && xAngle < endAngle) { | ||
xs.push(xAngle); | ||
} | ||
} | ||
} else { | ||
if (endAngle < xAngle && xAngle < startAngle) { | ||
xs.push(xAngle); | ||
else { | ||
if (endAngle < xAngle && xAngle < startAngle) { | ||
xs.push(xAngle); | ||
} | ||
} | ||
} | ||
} | ||
for (var _i = 0; _i < xs.length; _i++) { | ||
var x = xAt(cx, cy, rx, ry, xRotation, xs[_i]); | ||
if (x < minX) { | ||
minX = x; | ||
} | ||
if (x > maxX) { | ||
maxX = x; | ||
} | ||
for (var i = 0; i < xs.length; i++) { | ||
var x = xAt(cx, cy, rx, ry, xRotation, xs[i]); | ||
if (x < minX) { | ||
minX = x; | ||
} | ||
if (x > maxX) { | ||
maxX = x; | ||
} | ||
} | ||
@@ -656,62 +160,37 @@ var yDim = yExtrema(rx, ry, xRotation); | ||
var ys = [startAngle, endAngle]; | ||
for (var _i2 = -Math.PI * 2; _i2 <= Math.PI * 2; _i2 += Math.PI) { | ||
var yAngle = yDim + _i2; | ||
if (startAngle < endAngle) { | ||
if (startAngle < yAngle && yAngle < endAngle) { | ||
ys.push(yAngle); | ||
for (var i = -Math.PI * 2; i <= Math.PI * 2; i += Math.PI) { | ||
var yAngle = yDim + i; | ||
if (startAngle < endAngle) { | ||
if (startAngle < yAngle && yAngle < endAngle) { | ||
ys.push(yAngle); | ||
} | ||
} | ||
} else { | ||
if (endAngle < yAngle && yAngle < startAngle) { | ||
ys.push(yAngle); | ||
else { | ||
if (endAngle < yAngle && yAngle < startAngle) { | ||
ys.push(yAngle); | ||
} | ||
} | ||
} | ||
} | ||
for (var _i3 = 0; _i3 < ys.length; _i3++) { | ||
var y = yAt(cx, cy, rx, ry, xRotation, ys[_i3]); | ||
if (y < minY) { | ||
minY = y; | ||
} | ||
if (y > maxY) { | ||
maxY = y; | ||
} | ||
for (var i = 0; i < ys.length; i++) { | ||
var y = yAt(cx, cy, rx, ry, xRotation, ys[i]); | ||
if (y < minY) { | ||
minY = y; | ||
} | ||
if (y > maxY) { | ||
maxY = y; | ||
} | ||
} | ||
return { | ||
x: minX, | ||
y: minY, | ||
width: maxX - minX, | ||
height: maxY - minY | ||
x: minX, | ||
y: minY, | ||
width: maxX - minX, | ||
height: maxY - minY, | ||
}; | ||
}, | ||
/** | ||
* 获取圆弧的长度,计算圆弧长度时不考虑旋转角度, | ||
* 仅跟 rx, ry, startAngle, endAngle 相关 | ||
* @param {number} cx 圆心 x | ||
* @param {number} cy 圆心 y | ||
* @param {number} rx x 轴方向的半径 | ||
* @param {number} ry y 轴方向的半径 | ||
* @param {number} xRotation 旋转角度 | ||
* @param {number} startAngle 起始角度 | ||
* @param {number} endAngle 结束角度 | ||
*/ | ||
length: function length(cx, cy, rx, ry, xRotation, startAngle, endAngle) {}, | ||
/** | ||
* 获取指定点到圆弧的最近距离的点 | ||
* @param {number} cx 圆心 x | ||
* @param {number} cy 圆心 y | ||
* @param {number} rx x 轴方向的半径 | ||
* @param {number} ry y 轴方向的半径 | ||
* @param {number} xRotation 旋转角度 | ||
* @param {number} startAngle 起始角度 | ||
* @param {number} endAngle 结束角度 | ||
* @param {number} x0 指定点的 x | ||
* @param {number} y0 指定点的 y | ||
* @return {object} 到指定点最近距离的点 | ||
*/ | ||
nearestPoint: function nearestPoint(cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0) { | ||
} | ||
function nearestPoint$3(cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0) { | ||
// 将最近距离问题转换成到椭圆中心 0,0 没有旋转的椭圆问题 | ||
var relativeVector = rotate(x0 - cx, y0 - cy, -xRotation); | ||
var x1 = relativeVector[0], | ||
y1 = relativeVector[1]; | ||
var _a = __read(relativeVector, 2), x1 = _a[0], y1 = _a[1]; | ||
// 计算点到椭圆的最近的点 | ||
var relativePoint = ellipse.nearestPoint(0, 0, rx, ry, x1, y1); | ||
var relativePoint = nearestPoint$4(0, 0, rx, ry, x1, y1); | ||
// 获取点在椭圆上的角度 | ||
@@ -721,66 +200,295 @@ var angle = getAngle(rx, ry, relativePoint.x, relativePoint.y); | ||
if (angle < startAngle) { | ||
// 小于起始圆弧 | ||
relativePoint = getPoint(rx, ry, startAngle); | ||
} else if (angle > endAngle) { | ||
// 大于结束圆弧 | ||
relativePoint = getPoint(rx, ry, endAngle); | ||
// 小于起始圆弧 | ||
relativePoint = getPoint(rx, ry, startAngle); | ||
} | ||
else if (angle > endAngle) { | ||
// 大于结束圆弧 | ||
relativePoint = getPoint(rx, ry, endAngle); | ||
} | ||
// 旋转到 xRotation 的角度 | ||
var vector = rotate(relativePoint.x, relativePoint.y, xRotation); | ||
return { | ||
x: vector[0] + cx, | ||
y: vector[1] + cy | ||
x: vector[0] + cx, | ||
y: vector[1] + cy, | ||
}; | ||
}, | ||
pointDistance: function pointDistance(cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0) { | ||
var nearestPoint = this.nearestPoint(cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0); | ||
return distance(nearestPoint.x, nearestPoint.y, x0, y0); | ||
}, | ||
pointAt: function pointAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, t) { | ||
} | ||
function tangentAngle$4(cx, cy, rx, ry, xRotation, startAngle, endAngle, t) { | ||
var angle = (endAngle - startAngle) * t + startAngle; | ||
return { | ||
x: xAt(cx, cy, rx, ry, xRotation, angle), | ||
y: yAt(cx, cy, rx, ry, xRotation, angle) | ||
}; | ||
}, | ||
tangentAngle: function tangentAngle(cx, cy, rx, ry, xRotation, startAngle, endAngle, t) { | ||
var angle = (endAngle - startAngle) * t + startAngle; | ||
var dx = derivativeXAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle); | ||
var dy = derivativeYAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle); | ||
return piMod(Math.atan2(dy, dx)); | ||
} | ||
}; | ||
} | ||
function analyzePoints(points) { | ||
// 计算每段的长度和总的长度 | ||
var totalLength = 0; | ||
var segments = []; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var from = points[i]; | ||
var to = points[i + 1]; | ||
var length = distance(from[0], from[1], to[0], to[1]); | ||
var seg = { | ||
from: from, | ||
to: to, | ||
length: length | ||
var EPSILON = 0.0001; | ||
/** | ||
* 使用牛顿切割法求最近的点 | ||
* @param {number[]} xArr 点的 x 数组 | ||
* @param {number[]} yArr 点的 y 数组 | ||
* @param {number} x 指定的点 x | ||
* @param {number} y 指定的点 y | ||
* @param {Function} tCallback 差值函数 | ||
*/ | ||
function nearestPoint$2(xArr, yArr, x, y, tCallback, length) { | ||
var t = -1; | ||
var d = Infinity; | ||
var v0 = [x, y]; | ||
var segNum = 20; | ||
if (length && length > 200) { | ||
segNum = length / 10; | ||
} | ||
var increaseRate = 1 / segNum; | ||
var interval = increaseRate / 10; | ||
for (var i = 0; i <= segNum; i++) { | ||
var _t = i * increaseRate; | ||
var v1 = [ | ||
tCallback.apply(void 0, __spreadArray([], __read(xArr.concat([_t])), false)), | ||
tCallback.apply(void 0, __spreadArray([], __read(yArr.concat([_t])), false)), | ||
]; | ||
var d1 = distance(v0[0], v0[1], v1[0], v1[1]); | ||
if (d1 < d) { | ||
t = _t; | ||
d = d1; | ||
} | ||
} | ||
// 提前终止 | ||
if (t === 0) { | ||
return { | ||
x: xArr[0], | ||
y: yArr[0], | ||
}; | ||
} | ||
if (t === 1) { | ||
var count = xArr.length; | ||
return { | ||
x: xArr[count - 1], | ||
y: yArr[count - 1], | ||
}; | ||
} | ||
d = Infinity; | ||
for (var i = 0; i < 32; i++) { | ||
if (interval < EPSILON) { | ||
break; | ||
} | ||
var prev = t - interval; | ||
var next = t + interval; | ||
var v1 = [ | ||
tCallback.apply(void 0, __spreadArray([], __read(xArr.concat([prev])), false)), | ||
tCallback.apply(void 0, __spreadArray([], __read(yArr.concat([prev])), false)), | ||
]; | ||
var d1 = distance(v0[0], v0[1], v1[0], v1[1]); | ||
if (prev >= 0 && d1 < d) { | ||
t = prev; | ||
d = d1; | ||
} | ||
else { | ||
var v2 = [ | ||
tCallback.apply(void 0, __spreadArray([], __read(xArr.concat([next])), false)), | ||
tCallback.apply(void 0, __spreadArray([], __read(yArr.concat([next])), false)), | ||
]; | ||
var d2 = distance(v0[0], v0[1], v2[0], v2[1]); | ||
if (next <= 1 && d2 < d) { | ||
t = next; | ||
d = d2; | ||
} | ||
else { | ||
interval *= 0.5; | ||
} | ||
} | ||
} | ||
return { | ||
x: tCallback.apply(void 0, __spreadArray([], __read(xArr.concat([t])), false)), | ||
y: tCallback.apply(void 0, __spreadArray([], __read(yArr.concat([t])), false)), | ||
}; | ||
segments.push(seg); | ||
totalLength += length; | ||
} | ||
return { | ||
segments: segments, | ||
totalLength: totalLength | ||
}; | ||
} | ||
// 近似求解 https://community.khronos.org/t/3d-cubic-bezier-segment-length/62363/2 | ||
function snapLength(xArr, yArr) { | ||
var totalLength = 0; | ||
var count = xArr.length; | ||
for (var i = 0; i < count; i++) { | ||
var x = xArr[i]; | ||
var y = yArr[i]; | ||
var nextX = xArr[(i + 1) % count]; | ||
var nextY = yArr[(i + 1) % count]; | ||
totalLength += distance(x, y, nextX, nextY); | ||
} | ||
return totalLength / 2; | ||
} | ||
function box$4(x1, y1, x2, y2) { | ||
return getBBoxByArray([x1, x2], [y1, y2]); | ||
} | ||
function length$4(x1, y1, x2, y2) { | ||
return distance(x1, y1, x2, y2); | ||
} | ||
function pointAt$3(x1, y1, x2, y2, t) { | ||
return { | ||
x: (1 - t) * x1 + t * x2, | ||
y: (1 - t) * y1 + t * y2, | ||
}; | ||
} | ||
function pointDistance$4(x1, y1, x2, y2, x, y) { | ||
// 投影距离 x1, y1 的向量,假设 p, p1, p2 三个点,投影点为 a | ||
// p1a = p1p.p1p2/|p1p2| * (p1p 的单位向量) | ||
var cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1); | ||
if (cross < 0) { | ||
return distance(x1, y1, x, y); | ||
} | ||
var lengthSquare = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); | ||
if (cross > lengthSquare) { | ||
return distance(x2, y2, x, y); | ||
} | ||
return this.pointToLine(x1, y1, x2, y2, x, y); | ||
} | ||
function pointToLine(x1, y1, x2, y2, x, y) { | ||
var d = [x2 - x1, y2 - y1]; | ||
// 如果端点相等,则判定点到点的距离 | ||
if (vec2.exactEquals(d, [0, 0])) { | ||
return Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)); | ||
} | ||
var u = [-d[1], d[0]]; | ||
vec2.normalize(u, u); | ||
var a = [x - x1, y - y1]; | ||
return Math.abs(vec2.dot(a, u)); | ||
} | ||
function tangentAngle$3(x1, y1, x2, y2) { | ||
return Math.atan2(y2 - y1, x2 - x1); | ||
} | ||
function cubicAt(p0, p1, p2, p3, t) { | ||
var onet = 1 - t; // t * t * t 的性能大概是 Math.pow(t, 3) 的三倍 | ||
return (onet * onet * onet * p0 + | ||
3 * p1 * t * onet * onet + | ||
3 * p2 * t * t * onet + | ||
p3 * t * t * t); | ||
} | ||
function derivativeAt(p0, p1, p2, p3, t) { | ||
var onet = 1 - t; | ||
return (3 * (onet * onet * (p1 - p0) + 2 * onet * t * (p2 - p1) + t * t * (p3 - p2))); | ||
} | ||
function extrema$1(p0, p1, p2, p3) { | ||
var a = -3 * p0 + 9 * p1 - 9 * p2 + 3 * p3; | ||
var b = 6 * p0 - 12 * p1 + 6 * p2; | ||
var c = 3 * p1 - 3 * p0; | ||
var extremas = []; | ||
var t1; | ||
var t2; | ||
var discSqrt; | ||
if (isNumberEqual(a, 0)) { | ||
if (!isNumberEqual(b, 0)) { | ||
t1 = -c / b; | ||
if (t1 >= 0 && t1 <= 1) { | ||
extremas.push(t1); | ||
} | ||
} | ||
} | ||
else { | ||
var disc = b * b - 4 * a * c; | ||
if (isNumberEqual(disc, 0)) { | ||
extremas.push(-b / (2 * a)); | ||
} | ||
else if (disc > 0) { | ||
discSqrt = Math.sqrt(disc); | ||
t1 = (-b + discSqrt) / (2 * a); | ||
t2 = (-b - discSqrt) / (2 * a); | ||
if (t1 >= 0 && t1 <= 1) { | ||
extremas.push(t1); | ||
} | ||
if (t2 >= 0 && t2 <= 1) { | ||
extremas.push(t2); | ||
} | ||
} | ||
} | ||
return extremas; | ||
} | ||
// 分割贝塞尔曲线 | ||
function divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
// 划分点 | ||
var xt = cubicAt(x1, x2, x3, x4, t); | ||
var yt = cubicAt(y1, y2, y3, y4, t); | ||
// 计算两点之间的差值点 | ||
var c1 = pointAt$3(x1, y1, x2, y2, t); | ||
var c2 = pointAt$3(x2, y2, x3, y3, t); | ||
var c3 = pointAt$3(x3, y3, x4, y4, t); | ||
var c12 = pointAt$3(c1.x, c1.y, c2.x, c2.y, t); | ||
var c23 = pointAt$3(c2.x, c2.y, c3.x, c3.y, t); | ||
return [ | ||
[x1, y1, c1.x, c1.y, c12.x, c12.y, xt, yt], | ||
[xt, yt, c23.x, c23.y, c3.x, c3.y, x4, y4], | ||
]; | ||
} | ||
// 使用迭代法取贝塞尔曲线的长度,二阶和三阶分开写,更清晰和便于调试 | ||
function cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, iterationCount) { | ||
if (iterationCount === 0) { | ||
return snapLength([x1, x2, x3, x4], [y1, y2, y3, y4]); | ||
} | ||
var cubics = divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0.5); | ||
var left = __spreadArray(__spreadArray([], __read(cubics[0]), false), [iterationCount - 1], false); | ||
var right = __spreadArray(__spreadArray([], __read(cubics[1]), false), [iterationCount - 1], false); | ||
return cubicLength.apply(void 0, __spreadArray([], __read(left), false)) + cubicLength.apply(void 0, __spreadArray([], __read(right), false)); | ||
} | ||
function box$3(x1, y1, x2, y2, x3, y3, x4, y4) { | ||
var xArr = [x1, x4]; | ||
var yArr = [y1, y4]; | ||
var xExtrema = extrema$1(x1, x2, x3, x4); | ||
var yExtrema = extrema$1(y1, y2, y3, y4); | ||
for (var i = 0; i < xExtrema.length; i++) { | ||
xArr.push(cubicAt(x1, x2, x3, x4, xExtrema[i])); | ||
} | ||
for (var i = 0; i < yExtrema.length; i++) { | ||
yArr.push(cubicAt(y1, y2, y3, y4, yExtrema[i])); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
} | ||
function length$3(x1, y1, x2, y2, x3, y3, x4, y4) { | ||
// 迭代三次,划分成 8 段求长度 | ||
return cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, 3); | ||
} | ||
function nearestPoint$1(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { | ||
return nearestPoint$2([x1, x2, x3, x4], [y1, y2, y3, y4], x0, y0, cubicAt, length); | ||
} | ||
function pointDistance$3(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { | ||
var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length); | ||
return distance(point.x, point.y, x0, y0); | ||
} | ||
function pointAt$2(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
return { | ||
x: cubicAt(x1, x2, x3, x4, t), | ||
y: cubicAt(y1, y2, y3, y4, t), | ||
}; | ||
} | ||
function tangentAngle$2(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
var dx = derivativeAt(x1, x2, x3, x4, t); | ||
var dy = derivativeAt(y1, y2, y3, y4, t); | ||
return piMod(Math.atan2(dy, dx)); | ||
} | ||
function analyzePoints(points) { | ||
// 计算每段的长度和总的长度 | ||
var totalLength = 0; | ||
var segments = []; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var from = points[i]; | ||
var to = points[i + 1]; | ||
var length_1 = distance(from[0], from[1], to[0], to[1]); | ||
var seg = { | ||
from: from, | ||
to: to, | ||
length: length_1, | ||
}; | ||
segments.push(seg); | ||
totalLength += length_1; | ||
} | ||
return { segments: segments, totalLength: totalLength }; | ||
} | ||
function lengthOfSegment(points) { | ||
if (points.length < 2) { | ||
return 0; | ||
} | ||
var totalLength = 0; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var from = points[i]; | ||
var to = points[i + 1]; | ||
totalLength += distance(from[0], from[1], to[0], to[1]); | ||
} | ||
return totalLength; | ||
if (points.length < 2) { | ||
return 0; | ||
} | ||
var totalLength = 0; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var from = points[i]; | ||
var to = points[i + 1]; | ||
totalLength += distance(from[0], from[1], to[0], to[1]); | ||
} | ||
return totalLength; | ||
} | ||
@@ -794,32 +502,29 @@ /** | ||
function pointAtSegments(points, t) { | ||
// 边界判断 | ||
if (t > 1 || t < 0 || points.length < 2) { | ||
return null; | ||
} | ||
var _analyzePoints = analyzePoints(points), | ||
segments = _analyzePoints.segments, | ||
totalLength = _analyzePoints.totalLength; | ||
// 多个点有可能重合 | ||
if (totalLength === 0) { | ||
return { | ||
x: points[0][0], | ||
y: points[0][1] | ||
}; | ||
} | ||
// 计算比例 | ||
var startRatio = 0; | ||
var point = null; | ||
for (var i = 0; i < segments.length; i++) { | ||
var seg = segments[i]; | ||
var from = seg.from, | ||
to = seg.to; | ||
var currentRatio = seg.length / totalLength; | ||
if (t >= startRatio && t <= startRatio + currentRatio) { | ||
var localRatio = (t - startRatio) / currentRatio; | ||
point = line.pointAt(from[0], from[1], to[0], to[1], localRatio); | ||
break; | ||
// 边界判断 | ||
if (t > 1 || t < 0 || points.length < 2) { | ||
return null; | ||
} | ||
startRatio += currentRatio; | ||
} | ||
return point; | ||
var _a = analyzePoints(points), segments = _a.segments, totalLength = _a.totalLength; | ||
// 多个点有可能重合 | ||
if (totalLength === 0) { | ||
return { | ||
x: points[0][0], | ||
y: points[0][1], | ||
}; | ||
} | ||
// 计算比例 | ||
var startRatio = 0; | ||
var point = null; | ||
for (var i = 0; i < segments.length; i++) { | ||
var seg = segments[i]; | ||
var from = seg.from, to = seg.to; | ||
var currentRatio = seg.length / totalLength; | ||
if (t >= startRatio && t <= startRatio + currentRatio) { | ||
var localRatio = (t - startRatio) / currentRatio; | ||
point = pointAt$3(from[0], from[1], to[0], to[1], localRatio); | ||
break; | ||
} | ||
startRatio += currentRatio; | ||
} | ||
return point; | ||
} | ||
@@ -832,146 +537,153 @@ /** | ||
function angleAtSegments(points, t) { | ||
// 边界判断 | ||
if (t > 1 || t < 0 || points.length < 2) { | ||
return 0; | ||
} | ||
var _analyzePoints2 = analyzePoints(points), | ||
segments = _analyzePoints2.segments, | ||
totalLength = _analyzePoints2.totalLength; | ||
// 计算比例 | ||
var startRatio = 0; | ||
var angle = 0; | ||
for (var i = 0; i < segments.length; i++) { | ||
var seg = segments[i]; | ||
var from = seg.from, | ||
to = seg.to; | ||
var currentRatio = seg.length / totalLength; | ||
if (t >= startRatio && t <= startRatio + currentRatio) { | ||
angle = Math.atan2(to[1] - from[1], to[0] - from[0]); | ||
break; | ||
// 边界判断 | ||
if (t > 1 || t < 0 || points.length < 2) { | ||
return 0; | ||
} | ||
startRatio += currentRatio; | ||
} | ||
return angle; | ||
var _a = analyzePoints(points), segments = _a.segments, totalLength = _a.totalLength; | ||
// 计算比例 | ||
var startRatio = 0; | ||
var angle = 0; | ||
for (var i = 0; i < segments.length; i++) { | ||
var seg = segments[i]; | ||
var from = seg.from, to = seg.to; | ||
var currentRatio = seg.length / totalLength; | ||
if (t >= startRatio && t <= startRatio + currentRatio) { | ||
angle = Math.atan2(to[1] - from[1], to[0] - from[0]); | ||
break; | ||
} | ||
startRatio += currentRatio; | ||
} | ||
return angle; | ||
} | ||
function distanceAtSegment(points, x, y) { | ||
var minDistance = Infinity; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var point = points[i]; | ||
var nextPoint = points[i + 1]; | ||
var _distance = line.pointDistance(point[0], point[1], nextPoint[0], nextPoint[1], x, y); | ||
if (_distance < minDistance) { | ||
minDistance = _distance; | ||
var minDistance = Infinity; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var point = points[i]; | ||
var nextPoint = points[i + 1]; | ||
var distance_1 = pointDistance$4(point[0], point[1], nextPoint[0], nextPoint[1], x, y); | ||
if (distance_1 < minDistance) { | ||
minDistance = distance_1; | ||
} | ||
} | ||
} | ||
return minDistance; | ||
return minDistance; | ||
} | ||
var polyline = { | ||
/** | ||
* 计算多折线的包围盒 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 包围盒 | ||
*/ | ||
box: function box(points) { | ||
function box$2(points) { | ||
var xArr = []; | ||
var yArr = []; | ||
for (var i = 0; i < points.length; i++) { | ||
var point = points[i]; | ||
xArr.push(point[0]); | ||
yArr.push(point[1]); | ||
var point = points[i]; | ||
xArr.push(point[0]); | ||
yArr.push(point[1]); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
}, | ||
/** | ||
* 计算多折线的长度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 多条边的长度 | ||
*/ | ||
length: function length(points) { | ||
} | ||
function length$2(points) { | ||
return lengthOfSegment(points); | ||
}, | ||
/** | ||
* 根据比例获取多折线的点 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多折线的长度上的比例 | ||
* @return {object} 根据比例值计算出来的点 | ||
*/ | ||
pointAt: function pointAt(points, t) { | ||
} | ||
function pointAt$1(points, t) { | ||
return pointAtSegments(points, t); | ||
}, | ||
/** | ||
* 指定点到多折线的距离 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} x 指定点的 x | ||
* @param {number} y 指定点的 y | ||
* @return {number} 点到多折线的距离 | ||
*/ | ||
pointDistance: function pointDistance(points, x, y) { | ||
} | ||
function pointDistance$2(points, x, y) { | ||
return distanceAtSegment(points, x, y); | ||
}, | ||
/** | ||
* 根据比例获取多折线的切线角度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多折线的长度上的比例 | ||
* @return {object} 根据比例值计算出来的角度 | ||
*/ | ||
tangentAngle: function tangentAngle(points, t) { | ||
} | ||
function tangentAngle$1(points, t) { | ||
return angleAtSegments(points, t); | ||
} | ||
}; | ||
} | ||
function getAllPoints(points) { | ||
var tmp = points.slice(0); | ||
if (points.length) { | ||
tmp.push(points[0]); | ||
} | ||
return tmp; | ||
var tmp = points.slice(0); | ||
if (points.length) { | ||
tmp.push(points[0]); | ||
} | ||
return tmp; | ||
} | ||
var polygon = { | ||
/** | ||
* 计算多边形的包围盒 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 包围盒 | ||
*/ | ||
box: function box(points) { | ||
return polyline.box(points); | ||
}, | ||
/** | ||
* 计算多边形的长度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 多边形边的长度 | ||
*/ | ||
length: function length(points) { | ||
function box$1(points) { | ||
return box$2(points); | ||
} | ||
function length$1(points) { | ||
return lengthOfSegment(getAllPoints(points)); | ||
}, | ||
/** | ||
* 根据比例获取多边形的点 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多边形的长度上的比例 | ||
* @return {object} 根据比例值计算出来的点 | ||
*/ | ||
pointAt: function pointAt(points, t) { | ||
} | ||
function pointAt(points, t) { | ||
return pointAtSegments(getAllPoints(points), t); | ||
}, | ||
/** | ||
* 指定点到多边形的距离 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} x 指定点的 x | ||
* @param {number} y 指定点的 y | ||
* @return {number} 点到多边形的距离 | ||
*/ | ||
pointDistance: function pointDistance(points, x, y) { | ||
} | ||
function pointDistance$1(points, x, y) { | ||
return distanceAtSegment(getAllPoints(points), x, y); | ||
}, | ||
/** | ||
* 根据比例获取多边形的切线角度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多边形的长度上的比例 | ||
* @return {object} 根据比例值计算出来的角度 | ||
*/ | ||
tangentAngle: function tangentAngle(points, t) { | ||
} | ||
function tangentAngle(points, t) { | ||
return angleAtSegments(getAllPoints(points), t); | ||
} | ||
}; | ||
} | ||
export { arc as Arc, cubic as Cubic, line as Line, polygon as Polygon, polyline as Polyline, quadratic as Quad, util as Util }; | ||
// 差值公式 | ||
function quadraticAt(p0, p1, p2, t) { | ||
var onet = 1 - t; | ||
return onet * onet * p0 + 2 * t * onet * p1 + t * t * p2; | ||
} | ||
// 求极值 | ||
function extrema(p0, p1, p2) { | ||
var a = p0 + p2 - 2 * p1; | ||
if (isNumberEqual(a, 0)) { | ||
return [0.5]; | ||
} | ||
var rst = (p0 - p1) / a; | ||
if (rst <= 1 && rst >= 0) { | ||
return [rst]; | ||
} | ||
return []; | ||
} | ||
// 分割贝塞尔曲线 | ||
function divideQuadratic(x1, y1, x2, y2, x3, y3, t) { | ||
// 划分点 | ||
var xt = quadraticAt(x1, x2, x3, t); | ||
var yt = quadraticAt(y1, y2, y3, t); | ||
// 分割的第一条曲线的控制点 | ||
var controlPoint1 = pointAt$3(x1, y1, x2, y2, t); | ||
// 分割的第二条曲线的控制点 | ||
var controlPoint2 = pointAt$3(x2, y2, x3, y3, t); | ||
return [ | ||
[x1, y1, controlPoint1.x, controlPoint1.y, xt, yt], | ||
[xt, yt, controlPoint2.x, controlPoint2.y, x3, y3], | ||
]; | ||
} | ||
// 使用迭代法取贝塞尔曲线的长度 | ||
function quadraticLength(x1, y1, x2, y2, x3, y3, iterationCount) { | ||
if (iterationCount === 0) { | ||
return ((distance(x1, y1, x2, y2) + | ||
distance(x2, y2, x3, y3) + | ||
distance(x1, y1, x3, y3)) / | ||
2); | ||
} | ||
var quadratics = divideQuadratic(x1, y1, x2, y2, x3, y3, 0.5); | ||
var left = quadratics[0]; | ||
var right = quadratics[1]; | ||
left.push(iterationCount - 1); | ||
right.push(iterationCount - 1); | ||
return quadraticLength.apply(void 0, __spreadArray([], __read(left), false)) + quadraticLength.apply(void 0, __spreadArray([], __read(right), false)); | ||
} | ||
function box(x1, y1, x2, y2, x3, y3) { | ||
var xExtrema = extrema(x1, x2, x3)[0]; | ||
var yExtrema = extrema(y1, y2, y3)[0]; | ||
// 控制点不加入 box 的计算 | ||
var xArr = [x1, x3]; | ||
var yArr = [y1, y3]; | ||
if (xExtrema !== undefined) { | ||
xArr.push(quadraticAt(x1, x2, x3, xExtrema)); | ||
} | ||
if (yExtrema !== undefined) { | ||
yArr.push(quadraticAt(y1, y2, y3, yExtrema)); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
} | ||
function length(x1, y1, x2, y2, x3, y3) { | ||
return quadraticLength(x1, y1, x2, y2, x3, y3, 3); | ||
} | ||
function nearestPoint(x1, y1, x2, y2, x3, y3, x0, y0) { | ||
return nearestPoint$2([x1, x2, x3], [y1, y2, y3], x0, y0, quadraticAt); | ||
} | ||
function pointDistance(x1, y1, x2, y2, x3, y3, x0, y0) { | ||
var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x0, y0); | ||
return distance(point.x, point.y, x0, y0); | ||
} | ||
export { box$5 as arcBox, nearestPoint$3 as arcNearestPoint, tangentAngle$4 as arcTangentAngle, box$3 as cubicBox, length$3 as cubicLength, nearestPoint$1 as cubicNearestPoint, pointAt$2 as cubicPointAt, pointDistance$3 as cubicPointDistance, tangentAngle$2 as cubicTangentAngle, distance, box$4 as lineBox, length$4 as lineLength, pointAt$3 as linePointAt, pointDistance$4 as linePointDistance, pointToLine as linePointToLine, tangentAngle$3 as lineTangentAngle, box$1 as polygonBox, length$1 as polygonLength, pointAt as polygonPointAt, pointDistance$1 as polygonPointDistance, tangentAngle as polygonTangentAngle, box$2 as polylineBox, length$2 as polylineLength, pointAt$1 as polylinePointAt, pointDistance$2 as polylinePointDistance, tangentAngle$1 as polylineTangentAngle, box as quadBox, length as quadLength, nearestPoint as quadNearestPoint, pointDistance as quadPointDistance }; | ||
//# sourceMappingURL=index.esm.js.map |
1407
dist/index.js
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
var tslib = require('tslib'); | ||
var glMatrix = require('gl-matrix'); | ||
/** | ||
* 两点之间的距离 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {number} 距离 | ||
*/ | ||
function distance(x1, y1, x2, y2) { | ||
var dx = x1 - x2; | ||
var dy = y1 - y2; | ||
return Math.sqrt(dx * dx + dy * dy); | ||
var dx = x1 - x2; | ||
var dy = y1 - y2; | ||
return Math.sqrt(dx * dx + dy * dy); | ||
} | ||
function isNumberEqual(v1, v2) { | ||
return Math.abs(v1 - v2) < 0.001; | ||
return Math.abs(v1 - v2) < 0.001; | ||
} | ||
function getBBoxByArray(xArr, yArr) { | ||
var minX = Math.min.apply(Math, xArr); | ||
var minY = Math.min.apply(Math, yArr); | ||
var maxX = Math.max.apply(Math, xArr); | ||
var maxY = Math.max.apply(Math, yArr); | ||
return { | ||
x: minX, | ||
y: minY, | ||
width: maxX - minX, | ||
height: maxY - minY | ||
}; | ||
} | ||
function getBBoxRange(x1, y1, x2, y2) { | ||
return { | ||
minX: Math.min(x1, x2), | ||
maxX: Math.max(x1, x2), | ||
minY: Math.min(y1, y2), | ||
maxY: Math.max(y1, y2) | ||
}; | ||
} | ||
function piMod(angle) { | ||
return (angle + Math.PI * 2) % (Math.PI * 2); | ||
} | ||
var util = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
distance: distance, | ||
isNumberEqual: isNumberEqual, | ||
getBBoxByArray: getBBoxByArray, | ||
getBBoxRange: getBBoxRange, | ||
piMod: piMod | ||
}); | ||
var line = { | ||
/** | ||
* 计算线段的包围盒 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {object} 包围盒对象 | ||
*/ | ||
box: function box(x1, y1, x2, y2) { | ||
return getBBoxByArray([x1, x2], [y1, y2]); | ||
}, | ||
/** | ||
* 线段的长度 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {number} 距离 | ||
*/ | ||
length: function length(x1, y1, x2, y2) { | ||
return distance(x1, y1, x2, y2); | ||
}, | ||
/** | ||
* 根据比例获取点 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @param {number} t 指定比例 | ||
* @return {object} 包含 x, y 的点 | ||
*/ | ||
pointAt: function pointAt(x1, y1, x2, y2, t) { | ||
var minX = Math.min.apply(Math, tslib.__spreadArray([], tslib.__read(xArr), false)); | ||
var minY = Math.min.apply(Math, tslib.__spreadArray([], tslib.__read(yArr), false)); | ||
var maxX = Math.max.apply(Math, tslib.__spreadArray([], tslib.__read(xArr), false)); | ||
var maxY = Math.max.apply(Math, tslib.__spreadArray([], tslib.__read(yArr), false)); | ||
return { | ||
x: (1 - t) * x1 + t * x2, | ||
y: (1 - t) * y1 + t * y2 | ||
x: minX, | ||
y: minY, | ||
width: maxX - minX, | ||
height: maxY - minY, | ||
}; | ||
}, | ||
/** | ||
* 点到线段的距离 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @param {number} x 测试点 x | ||
* @param {number} y 测试点 y | ||
* @return {number} 距离 | ||
*/ | ||
pointDistance: function pointDistance(x1, y1, x2, y2, x, y) { | ||
// 投影距离 x1, y1 的向量,假设 p, p1, p2 三个点,投影点为 a | ||
// p1a = p1p.p1p2/|p1p2| * (p1p 的单位向量) | ||
var cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1); | ||
if (cross < 0) { | ||
return distance(x1, y1, x, y); | ||
} | ||
var lengthSquare = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); | ||
if (cross > lengthSquare) { | ||
return distance(x2, y2, x, y); | ||
} | ||
return this.pointToLine(x1, y1, x2, y2, x, y); | ||
}, | ||
/** | ||
* 点到直线的距离,而不是点到线段的距离 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @param {number} x 测试点 x | ||
* @param {number} y 测试点 y | ||
* @return {number} 距离 | ||
*/ | ||
pointToLine: function pointToLine(x1, y1, x2, y2, x, y) { | ||
var d = [x2 - x1, y2 - y1]; | ||
// 如果端点相等,则判定点到点的距离 | ||
if (glMatrix.vec2.exactEquals(d, [0, 0])) { | ||
return Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)); | ||
} | ||
var u = [-d[1], d[0]]; | ||
glMatrix.vec2.normalize(u, u); | ||
var a = [x - x1, y - y1]; | ||
return Math.abs(glMatrix.vec2.dot(a, u)); | ||
}, | ||
/** | ||
* 线段的角度 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {number} 导数 | ||
*/ | ||
tangentAngle: function tangentAngle(x1, y1, x2, y2) { | ||
return Math.atan2(y2 - y1, x2 - x1); | ||
} | ||
}; | ||
var EPSILON = 0.0001; | ||
/** | ||
* 使用牛顿切割法求最近的点 | ||
* @param {number[]} xArr 点的 x 数组 | ||
* @param {number[]} yArr 点的 y 数组 | ||
* @param {number} x 指定的点 x | ||
* @param {number} y 指定的点 y | ||
* @param {Function} tCallback 差值函数 | ||
*/ | ||
function nearestPoint(xArr, yArr, x, y, tCallback, length) { | ||
var t = -1; | ||
var d = Infinity; | ||
var v0 = [x, y]; | ||
var segNum = 20; | ||
if (length && length > 200) { | ||
segNum = length / 10; | ||
} | ||
var increaseRate = 1 / segNum; | ||
var interval = increaseRate / 10; | ||
for (var i = 0; i <= segNum; i++) { | ||
var _t = i * increaseRate; | ||
var v1 = [tCallback.apply(void 0, xArr.concat([_t])), tCallback.apply(void 0, yArr.concat([_t]))]; | ||
var d1 = distance(v0[0], v0[1], v1[0], v1[1]); | ||
if (d1 < d) { | ||
t = _t; | ||
d = d1; | ||
} | ||
} | ||
// 提前终止 | ||
if (t === 0) { | ||
return { | ||
x: xArr[0], | ||
y: yArr[0] | ||
}; | ||
} | ||
if (t === 1) { | ||
var count = xArr.length; | ||
return { | ||
x: xArr[count - 1], | ||
y: yArr[count - 1] | ||
}; | ||
} | ||
d = Infinity; | ||
for (var _i = 0; _i < 32; _i++) { | ||
if (interval < EPSILON) { | ||
break; | ||
} | ||
var prev = t - interval; | ||
var next = t + interval; | ||
var _v = [tCallback.apply(void 0, xArr.concat([prev])), tCallback.apply(void 0, yArr.concat([prev]))]; | ||
var _d = distance(v0[0], v0[1], _v[0], _v[1]); | ||
if (prev >= 0 && _d < d) { | ||
t = prev; | ||
d = _d; | ||
} else { | ||
var v2 = [tCallback.apply(void 0, xArr.concat([next])), tCallback.apply(void 0, yArr.concat([next]))]; | ||
var d2 = distance(v0[0], v0[1], v2[0], v2[1]); | ||
if (next <= 1 && d2 < d) { | ||
t = next; | ||
d = d2; | ||
} else { | ||
interval *= 0.5; | ||
} | ||
} | ||
} | ||
return { | ||
x: tCallback.apply(void 0, xArr.concat([t])), | ||
y: tCallback.apply(void 0, yArr.concat([t])) | ||
}; | ||
} | ||
// 近似求解 https://community.khronos.org/t/3d-cubic-bezier-segment-length/62363/2 | ||
function snapLength(xArr, yArr) { | ||
var totalLength = 0; | ||
var count = xArr.length; | ||
for (var i = 0; i < count; i++) { | ||
var x = xArr[i]; | ||
var y = yArr[i]; | ||
var nextX = xArr[(i + 1) % count]; | ||
var nextY = yArr[(i + 1) % count]; | ||
totalLength += distance(x, y, nextX, nextY); | ||
} | ||
return totalLength / 2; | ||
function piMod(angle) { | ||
return (angle + Math.PI * 2) % (Math.PI * 2); | ||
} | ||
// 差值公式 | ||
function quadraticAt(p0, p1, p2, t) { | ||
var onet = 1 - t; | ||
return onet * onet * p0 + 2 * t * onet * p1 + t * t * p2; | ||
} | ||
// 求极值 | ||
function extrema(p0, p1, p2) { | ||
var a = p0 + p2 - 2 * p1; | ||
if (isNumberEqual(a, 0)) { | ||
return [0.5]; | ||
} | ||
var rst = (p0 - p1) / a; | ||
if (rst <= 1 && rst >= 0) { | ||
return [rst]; | ||
} | ||
return []; | ||
} | ||
function derivativeAt(p0, p1, p2, t) { | ||
return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1); | ||
} | ||
// 分割贝塞尔曲线 | ||
function divideQuadratic(x1, y1, x2, y2, x3, y3, t) { | ||
// 划分点 | ||
var xt = quadraticAt(x1, x2, x3, t); | ||
var yt = quadraticAt(y1, y2, y3, t); | ||
// 分割的第一条曲线的控制点 | ||
var controlPoint1 = line.pointAt(x1, y1, x2, y2, t); | ||
// 分割的第二条曲线的控制点 | ||
var controlPoint2 = line.pointAt(x2, y2, x3, y3, t); | ||
return [[x1, y1, controlPoint1.x, controlPoint1.y, xt, yt], [xt, yt, controlPoint2.x, controlPoint2.y, x3, y3]]; | ||
} | ||
// 使用迭代法取贝塞尔曲线的长度 | ||
function quadraticLength(x1, y1, x2, y2, x3, y3, iterationCount) { | ||
if (iterationCount === 0) { | ||
return (distance(x1, y1, x2, y2) + distance(x2, y2, x3, y3) + distance(x1, y1, x3, y3)) / 2; | ||
} | ||
var quadratics = divideQuadratic(x1, y1, x2, y2, x3, y3, 0.5); | ||
var left = quadratics[0]; | ||
var right = quadratics[1]; | ||
left.push(iterationCount - 1); | ||
right.push(iterationCount - 1); | ||
return quadraticLength.apply(void 0, left) + quadraticLength.apply(void 0, right); | ||
} | ||
var quadratic = { | ||
box: function box(x1, y1, x2, y2, x3, y3) { | ||
var xExtrema = extrema(x1, x2, x3)[0]; | ||
var yExtrema = extrema(y1, y2, y3)[0]; | ||
// 控制点不加入 box 的计算 | ||
var xArr = [x1, x3]; | ||
var yArr = [y1, y3]; | ||
if (xExtrema !== undefined) { | ||
xArr.push(quadraticAt(x1, x2, x3, xExtrema)); | ||
} | ||
if (yExtrema !== undefined) { | ||
yArr.push(quadraticAt(y1, y2, y3, yExtrema)); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
}, | ||
length: function length(x1, y1, x2, y2, x3, y3) { | ||
return quadraticLength(x1, y1, x2, y2, x3, y3, 3); | ||
}, | ||
nearestPoint: function nearestPoint$1(x1, y1, x2, y2, x3, y3, x0, y0) { | ||
return nearestPoint([x1, x2, x3], [y1, y2, y3], x0, y0, quadraticAt); | ||
}, | ||
pointDistance: function pointDistance(x1, y1, x2, y2, x3, y3, x0, y0) { | ||
var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x0, y0); | ||
return distance(point.x, point.y, x0, y0); | ||
}, | ||
interpolationAt: quadraticAt, | ||
pointAt: function pointAt(x1, y1, x2, y2, x3, y3, t) { | ||
return { | ||
x: quadraticAt(x1, x2, x3, t), | ||
y: quadraticAt(y1, y2, y3, t) | ||
}; | ||
}, | ||
divide: function divide(x1, y1, x2, y2, x3, y3, t) { | ||
return divideQuadratic(x1, y1, x2, y2, x3, y3, t); | ||
}, | ||
tangentAngle: function tangentAngle(x1, y1, x2, y2, x3, y3, t) { | ||
var dx = derivativeAt(x1, x2, x3, t); | ||
var dy = derivativeAt(y1, y2, y3, t); | ||
var angle = Math.atan2(dy, dx); | ||
return piMod(angle); | ||
} | ||
}; | ||
function cubicAt(p0, p1, p2, p3, t) { | ||
var onet = 1 - t; // t * t * t 的性能大概是 Math.pow(t, 3) 的三倍 | ||
return onet * onet * onet * p0 + 3 * p1 * t * onet * onet + 3 * p2 * t * t * onet + p3 * t * t * t; | ||
} | ||
function derivativeAt$1(p0, p1, p2, p3, t) { | ||
var onet = 1 - t; | ||
return 3 * (onet * onet * (p1 - p0) + 2 * onet * t * (p2 - p1) + t * t * (p3 - p2)); | ||
} | ||
function extrema$1(p0, p1, p2, p3) { | ||
var a = -3 * p0 + 9 * p1 - 9 * p2 + 3 * p3; | ||
var b = 6 * p0 - 12 * p1 + 6 * p2; | ||
var c = 3 * p1 - 3 * p0; | ||
var extremas = []; | ||
var t1; | ||
var t2; | ||
var discSqrt; | ||
if (isNumberEqual(a, 0)) { | ||
if (!isNumberEqual(b, 0)) { | ||
t1 = -c / b; | ||
if (t1 >= 0 && t1 <= 1) { | ||
extremas.push(t1); | ||
} | ||
} | ||
} else { | ||
var disc = b * b - 4 * a * c; | ||
if (isNumberEqual(disc, 0)) { | ||
extremas.push(-b / (2 * a)); | ||
} else if (disc > 0) { | ||
discSqrt = Math.sqrt(disc); | ||
t1 = (-b + discSqrt) / (2 * a); | ||
t2 = (-b - discSqrt) / (2 * a); | ||
if (t1 >= 0 && t1 <= 1) { | ||
extremas.push(t1); | ||
} | ||
if (t2 >= 0 && t2 <= 1) { | ||
extremas.push(t2); | ||
} | ||
} | ||
} | ||
return extremas; | ||
} | ||
// 分割贝塞尔曲线 | ||
function divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
// 划分点 | ||
var xt = cubicAt(x1, x2, x3, x4, t); | ||
var yt = cubicAt(y1, y2, y3, y4, t); | ||
// 计算两点之间的差值点 | ||
var c1 = line.pointAt(x1, y1, x2, y2, t); | ||
var c2 = line.pointAt(x2, y2, x3, y3, t); | ||
var c3 = line.pointAt(x3, y3, x4, y4, t); | ||
var c12 = line.pointAt(c1.x, c1.y, c2.x, c2.y, t); | ||
var c23 = line.pointAt(c2.x, c2.y, c3.x, c3.y, t); | ||
return [[x1, y1, c1.x, c1.y, c12.x, c12.y, xt, yt], [xt, yt, c23.x, c23.y, c3.x, c3.y, x4, y4]]; | ||
} | ||
// 使用迭代法取贝塞尔曲线的长度,二阶和三阶分开写,更清晰和便于调试 | ||
function cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, iterationCount) { | ||
if (iterationCount === 0) { | ||
return snapLength([x1, x2, x3, x4], [y1, y2, y3, y4]); | ||
} | ||
var cubics = divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0.5); | ||
var left = [].concat(cubics[0], [iterationCount - 1]); | ||
var right = [].concat(cubics[1], [iterationCount - 1]); | ||
return cubicLength.apply(void 0, left) + cubicLength.apply(void 0, right); | ||
} | ||
var cubic = { | ||
extrema: extrema$1, | ||
box: function box(x1, y1, x2, y2, x3, y3, x4, y4) { | ||
var xArr = [x1, x4]; | ||
var yArr = [y1, y4]; | ||
var xExtrema = extrema$1(x1, x2, x3, x4); | ||
var yExtrema = extrema$1(y1, y2, y3, y4); | ||
for (var i = 0; i < xExtrema.length; i++) { | ||
xArr.push(cubicAt(x1, x2, x3, x4, xExtrema[i])); | ||
} | ||
for (var _i = 0; _i < yExtrema.length; _i++) { | ||
yArr.push(cubicAt(y1, y2, y3, y4, yExtrema[_i])); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
}, | ||
length: function length(x1, y1, x2, y2, x3, y3, x4, y4) { | ||
// 迭代三次,划分成 8 段求长度 | ||
return cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, 3); | ||
}, | ||
nearestPoint: function nearestPoint$1(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { | ||
return nearestPoint([x1, x2, x3, x4], [y1, y2, y3, y4], x0, y0, cubicAt, length); | ||
}, | ||
pointDistance: function pointDistance(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { | ||
var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length); | ||
return distance(point.x, point.y, x0, y0); | ||
}, | ||
interpolationAt: cubicAt, | ||
pointAt: function pointAt(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
return { | ||
x: cubicAt(x1, x2, x3, x4, t), | ||
y: cubicAt(y1, y2, y3, y4, t) | ||
}; | ||
}, | ||
divide: function divide(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
return divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t); | ||
}, | ||
tangentAngle: function tangentAngle(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
var dx = derivativeAt$1(x1, x2, x3, x4, t); | ||
var dy = derivativeAt$1(y1, y2, y3, y4, t); | ||
return piMod(Math.atan2(dy, dx)); | ||
} | ||
}; | ||
/** | ||
* @fileoverview 椭圆的一些计算, | ||
* - 周长计算参考:https://www.mathsisfun.com/geometry/ellipse-perimeter.html | ||
* - 距离计算参考:https://wet-robots.ghost.io/simple-method-for-distance-to-ellipse/ | ||
* @author dxq613@gmail.com | ||
*/ | ||
function copysign(v1, v2) { | ||
var absv = Math.abs(v1); | ||
return v2 > 0 ? absv : absv * -1; | ||
var absv = Math.abs(v1); | ||
return v2 > 0 ? absv : absv * -1; | ||
} | ||
var ellipse = { | ||
/** | ||
* 包围盒计算 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @return {object} 包围盒 | ||
*/ | ||
box: function box(x, y, rx, ry) { | ||
return { | ||
x: x - rx, | ||
y: y - ry, | ||
width: rx * 2, | ||
height: ry * 2 | ||
}; | ||
}, | ||
/** | ||
* 计算周长,使用近似法 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @return {number} 椭圆周长 | ||
*/ | ||
length: function length(x, y, rx, ry) { | ||
return Math.PI * (3 * (rx + ry) - Math.sqrt((3 * rx + ry) * (rx + 3 * ry))); | ||
}, | ||
/** | ||
* 距离椭圆最近的点 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} x0 指定的点 x | ||
* @param {number} y0 指定的点 y | ||
* @return {object} 椭圆上距离指定点最近的点 | ||
*/ | ||
nearestPoint: function nearestPoint(x, y, rx, ry, x0, y0) { | ||
function nearestPoint$4(x, y, rx, ry, x0, y0) { | ||
var a = rx; | ||
@@ -481,6 +39,6 @@ var b = ry; | ||
if (a === 0 || b === 0) { | ||
return { | ||
x: x, | ||
y: y | ||
}; | ||
return { | ||
x: x, | ||
y: y, | ||
}; | ||
} | ||
@@ -500,131 +58,74 @@ // 转换成 0, 0 为中心的椭圆计算 | ||
for (var i = 0; i < 4; i++) { | ||
nearestX = a * Math.cos(t); | ||
nearestY = b * Math.sin(t); | ||
var ex = (squareA - squareB) * Math.pow(Math.cos(t), 3) / a; | ||
var ey = (squareB - squareA) * Math.pow(Math.sin(t), 3) / b; | ||
var rx1 = nearestX - ex; | ||
var ry1 = nearestY - ey; | ||
var qx = px - ex; | ||
var qy = py - ey; | ||
var r = Math.hypot(ry1, rx1); | ||
var q = Math.hypot(qy, qx); | ||
var delta_c = r * Math.asin((rx1 * qy - ry1 * qx) / (r * q)); | ||
var delta_t = delta_c / Math.sqrt(squareA + squareB - nearestX * nearestX - nearestY * nearestY); | ||
t += delta_t; | ||
t = Math.min(Math.PI / 2, Math.max(0, t)); | ||
nearestX = a * Math.cos(t); | ||
nearestY = b * Math.sin(t); | ||
var ex = ((squareA - squareB) * Math.pow(Math.cos(t), 3)) / a; | ||
var ey = ((squareB - squareA) * Math.pow(Math.sin(t), 3)) / b; | ||
var rx1 = nearestX - ex; | ||
var ry1 = nearestY - ey; | ||
var qx = px - ex; | ||
var qy = py - ey; | ||
var r = Math.hypot(ry1, rx1); | ||
var q = Math.hypot(qy, qx); | ||
var delta_c = r * Math.asin((rx1 * qy - ry1 * qx) / (r * q)); | ||
var delta_t = delta_c / | ||
Math.sqrt(squareA + squareB - nearestX * nearestX - nearestY * nearestY); | ||
t += delta_t; | ||
t = Math.min(Math.PI / 2, Math.max(0, t)); | ||
} | ||
return { | ||
x: x + copysign(nearestX, relativeX), | ||
y: y + copysign(nearestY, relativeY) | ||
x: x + copysign(nearestX, relativeX), | ||
y: y + copysign(nearestY, relativeY), | ||
}; | ||
}, | ||
/** | ||
* 点到椭圆最近的距离 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} x0 指定的点 x | ||
* @param {number} y0 指定的点 y | ||
* @return {number} 点到椭圆的距离 | ||
*/ | ||
pointDistance: function pointDistance(x, y, rx, ry, x0, y0) { | ||
var nearestPoint = this.nearestPoint(x, y, rx, ry, x0, y0); | ||
return distance(nearestPoint.x, nearestPoint.y, x0, y0); | ||
}, | ||
/** | ||
* 根据比例获取点 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} t 指定比例,x轴方向为 0 | ||
* @return {object} 点 | ||
*/ | ||
pointAt: function pointAt(x, y, rx, ry, t) { | ||
var angle = 2 * Math.PI * t; // 按照角度进行计算,而不按照周长计算 | ||
return { | ||
x: x + rx * Math.cos(angle), | ||
y: y + ry * Math.sin(angle) | ||
}; | ||
}, | ||
/** | ||
* 根据比例计算切线角度 | ||
* @param {number} x 椭圆中心 x | ||
* @param {number} y 椭圆中心 y | ||
* @param {number} rx 椭圆 x 方向半径 | ||
* @param {number} ry 椭圆 y 方向半径 | ||
* @param {number} t 指定比例 0 - 1 之间,x轴方向为 0。在 0-1 范围之外是循环还是返回 null,还需要调整 | ||
* @return {number} 角度,在 0 - 2PI 之间 | ||
*/ | ||
tangentAngle: function tangentAngle(x, y, rx, ry, t) { | ||
var angle = 2 * Math.PI * t; // 按照角度进行计算,而不按照周长计算 | ||
// 直接使用 x,y 的导数计算, x' = -rx * sin(t); y' = ry * cos(t); | ||
var tangentAngle = Math.atan2(ry * Math.cos(angle), -rx * Math.sin(angle)); | ||
// 也可以使用指定点的切线方程计算,成本有些高 | ||
// const point = this.pointAt(0, 0, rx, ry, t); // 椭圆的切线同椭圆的中心不相关 | ||
// let tangentAngle = -1 * Math.atan((ry * ry * point.x) / (rx * rx * point.y)); | ||
// if (angle >= 0 && angle <= Math.PI) { | ||
// tangentAngle += Math.PI; | ||
// } | ||
return piMod(tangentAngle); | ||
} | ||
}; | ||
} | ||
// 偏导数 x | ||
function derivativeXAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle) { | ||
return -1 * rx * Math.cos(xRotation) * Math.sin(angle) - ry * Math.sin(xRotation) * Math.cos(angle); | ||
return (-1 * rx * Math.cos(xRotation) * Math.sin(angle) - | ||
ry * Math.sin(xRotation) * Math.cos(angle)); | ||
} | ||
// 偏导数 y | ||
function derivativeYAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle) { | ||
return -1 * rx * Math.sin(xRotation) * Math.sin(angle) + ry * Math.cos(xRotation) * Math.cos(angle); | ||
return (-1 * rx * Math.sin(xRotation) * Math.sin(angle) + | ||
ry * Math.cos(xRotation) * Math.cos(angle)); | ||
} | ||
// x 的极值 | ||
function xExtrema(rx, ry, xRotation) { | ||
return Math.atan(-ry / rx * Math.tan(xRotation)); | ||
return Math.atan((-ry / rx) * Math.tan(xRotation)); | ||
} | ||
// y 的极值 | ||
function yExtrema(rx, ry, xRotation) { | ||
return Math.atan(ry / (rx * Math.tan(xRotation))); | ||
return Math.atan(ry / (rx * Math.tan(xRotation))); | ||
} | ||
// 根据角度求 x 坐标 | ||
function xAt(cx, cy, rx, ry, xRotation, angle) { | ||
return rx * Math.cos(xRotation) * Math.cos(angle) - ry * Math.sin(xRotation) * Math.sin(angle) + cx; | ||
return (rx * Math.cos(xRotation) * Math.cos(angle) - | ||
ry * Math.sin(xRotation) * Math.sin(angle) + | ||
cx); | ||
} | ||
// 根据角度求 y 坐标 | ||
function yAt(cx, cy, rx, ry, xRotation, angle) { | ||
return rx * Math.sin(xRotation) * Math.cos(angle) + ry * Math.cos(xRotation) * Math.sin(angle) + cy; | ||
return (rx * Math.sin(xRotation) * Math.cos(angle) + | ||
ry * Math.cos(xRotation) * Math.sin(angle) + | ||
cy); | ||
} | ||
// 获取点在椭圆上的角度 | ||
function getAngle(rx, ry, x0, y0) { | ||
var angle = Math.atan2(y0 * rx, x0 * ry); | ||
// 转换到 0 - 2PI 内 | ||
return (angle + Math.PI * 2) % (Math.PI * 2); | ||
var angle = Math.atan2(y0 * rx, x0 * ry); | ||
// 转换到 0 - 2PI 内 | ||
return (angle + Math.PI * 2) % (Math.PI * 2); | ||
} | ||
// 根据角度获取,x,y | ||
function getPoint(rx, ry, angle) { | ||
return { | ||
x: rx * Math.cos(angle), | ||
y: ry * Math.sin(angle) | ||
}; | ||
return { | ||
x: rx * Math.cos(angle), | ||
y: ry * Math.sin(angle), | ||
}; | ||
} | ||
// 旋转 | ||
function rotate(x, y, angle) { | ||
var cos = Math.cos(angle); | ||
var sin = Math.sin(angle); | ||
return [x * cos - y * sin, x * sin + y * cos]; | ||
var cos = Math.cos(angle); | ||
var sin = Math.sin(angle); | ||
return [x * cos - y * sin, x * sin + y * cos]; | ||
} | ||
var arc = { | ||
/** | ||
* 计算包围盒 | ||
* @param {number} cx 圆心 x | ||
* @param {number} cy 圆心 y | ||
* @param {number} rx x 轴方向的半径 | ||
* @param {number} ry y 轴方向的半径 | ||
* @param {number} xRotation 旋转角度 | ||
* @param {number} startAngle 起始角度 | ||
* @param {number} endAngle 结束角度 | ||
* @return {object} 包围盒对象 | ||
*/ | ||
box: function box(cx, cy, rx, ry, xRotation, startAngle, endAngle) { | ||
function box$5(cx, cy, rx, ry, xRotation, startAngle, endAngle) { | ||
var xDim = xExtrema(rx, ry, xRotation); | ||
@@ -635,21 +136,22 @@ var minX = Infinity; | ||
for (var i = -Math.PI * 2; i <= Math.PI * 2; i += Math.PI) { | ||
var xAngle = xDim + i; | ||
if (startAngle < endAngle) { | ||
if (startAngle < xAngle && xAngle < endAngle) { | ||
xs.push(xAngle); | ||
var xAngle = xDim + i; | ||
if (startAngle < endAngle) { | ||
if (startAngle < xAngle && xAngle < endAngle) { | ||
xs.push(xAngle); | ||
} | ||
} | ||
} else { | ||
if (endAngle < xAngle && xAngle < startAngle) { | ||
xs.push(xAngle); | ||
else { | ||
if (endAngle < xAngle && xAngle < startAngle) { | ||
xs.push(xAngle); | ||
} | ||
} | ||
} | ||
} | ||
for (var _i = 0; _i < xs.length; _i++) { | ||
var x = xAt(cx, cy, rx, ry, xRotation, xs[_i]); | ||
if (x < minX) { | ||
minX = x; | ||
} | ||
if (x > maxX) { | ||
maxX = x; | ||
} | ||
for (var i = 0; i < xs.length; i++) { | ||
var x = xAt(cx, cy, rx, ry, xRotation, xs[i]); | ||
if (x < minX) { | ||
minX = x; | ||
} | ||
if (x > maxX) { | ||
maxX = x; | ||
} | ||
} | ||
@@ -660,62 +162,37 @@ var yDim = yExtrema(rx, ry, xRotation); | ||
var ys = [startAngle, endAngle]; | ||
for (var _i2 = -Math.PI * 2; _i2 <= Math.PI * 2; _i2 += Math.PI) { | ||
var yAngle = yDim + _i2; | ||
if (startAngle < endAngle) { | ||
if (startAngle < yAngle && yAngle < endAngle) { | ||
ys.push(yAngle); | ||
for (var i = -Math.PI * 2; i <= Math.PI * 2; i += Math.PI) { | ||
var yAngle = yDim + i; | ||
if (startAngle < endAngle) { | ||
if (startAngle < yAngle && yAngle < endAngle) { | ||
ys.push(yAngle); | ||
} | ||
} | ||
} else { | ||
if (endAngle < yAngle && yAngle < startAngle) { | ||
ys.push(yAngle); | ||
else { | ||
if (endAngle < yAngle && yAngle < startAngle) { | ||
ys.push(yAngle); | ||
} | ||
} | ||
} | ||
} | ||
for (var _i3 = 0; _i3 < ys.length; _i3++) { | ||
var y = yAt(cx, cy, rx, ry, xRotation, ys[_i3]); | ||
if (y < minY) { | ||
minY = y; | ||
} | ||
if (y > maxY) { | ||
maxY = y; | ||
} | ||
for (var i = 0; i < ys.length; i++) { | ||
var y = yAt(cx, cy, rx, ry, xRotation, ys[i]); | ||
if (y < minY) { | ||
minY = y; | ||
} | ||
if (y > maxY) { | ||
maxY = y; | ||
} | ||
} | ||
return { | ||
x: minX, | ||
y: minY, | ||
width: maxX - minX, | ||
height: maxY - minY | ||
x: minX, | ||
y: minY, | ||
width: maxX - minX, | ||
height: maxY - minY, | ||
}; | ||
}, | ||
/** | ||
* 获取圆弧的长度,计算圆弧长度时不考虑旋转角度, | ||
* 仅跟 rx, ry, startAngle, endAngle 相关 | ||
* @param {number} cx 圆心 x | ||
* @param {number} cy 圆心 y | ||
* @param {number} rx x 轴方向的半径 | ||
* @param {number} ry y 轴方向的半径 | ||
* @param {number} xRotation 旋转角度 | ||
* @param {number} startAngle 起始角度 | ||
* @param {number} endAngle 结束角度 | ||
*/ | ||
length: function length(cx, cy, rx, ry, xRotation, startAngle, endAngle) {}, | ||
/** | ||
* 获取指定点到圆弧的最近距离的点 | ||
* @param {number} cx 圆心 x | ||
* @param {number} cy 圆心 y | ||
* @param {number} rx x 轴方向的半径 | ||
* @param {number} ry y 轴方向的半径 | ||
* @param {number} xRotation 旋转角度 | ||
* @param {number} startAngle 起始角度 | ||
* @param {number} endAngle 结束角度 | ||
* @param {number} x0 指定点的 x | ||
* @param {number} y0 指定点的 y | ||
* @return {object} 到指定点最近距离的点 | ||
*/ | ||
nearestPoint: function nearestPoint(cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0) { | ||
} | ||
function nearestPoint$3(cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0) { | ||
// 将最近距离问题转换成到椭圆中心 0,0 没有旋转的椭圆问题 | ||
var relativeVector = rotate(x0 - cx, y0 - cy, -xRotation); | ||
var x1 = relativeVector[0], | ||
y1 = relativeVector[1]; | ||
var _a = tslib.__read(relativeVector, 2), x1 = _a[0], y1 = _a[1]; | ||
// 计算点到椭圆的最近的点 | ||
var relativePoint = ellipse.nearestPoint(0, 0, rx, ry, x1, y1); | ||
var relativePoint = nearestPoint$4(0, 0, rx, ry, x1, y1); | ||
// 获取点在椭圆上的角度 | ||
@@ -725,66 +202,295 @@ var angle = getAngle(rx, ry, relativePoint.x, relativePoint.y); | ||
if (angle < startAngle) { | ||
// 小于起始圆弧 | ||
relativePoint = getPoint(rx, ry, startAngle); | ||
} else if (angle > endAngle) { | ||
// 大于结束圆弧 | ||
relativePoint = getPoint(rx, ry, endAngle); | ||
// 小于起始圆弧 | ||
relativePoint = getPoint(rx, ry, startAngle); | ||
} | ||
else if (angle > endAngle) { | ||
// 大于结束圆弧 | ||
relativePoint = getPoint(rx, ry, endAngle); | ||
} | ||
// 旋转到 xRotation 的角度 | ||
var vector = rotate(relativePoint.x, relativePoint.y, xRotation); | ||
return { | ||
x: vector[0] + cx, | ||
y: vector[1] + cy | ||
x: vector[0] + cx, | ||
y: vector[1] + cy, | ||
}; | ||
}, | ||
pointDistance: function pointDistance(cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0) { | ||
var nearestPoint = this.nearestPoint(cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0); | ||
return distance(nearestPoint.x, nearestPoint.y, x0, y0); | ||
}, | ||
pointAt: function pointAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, t) { | ||
} | ||
function tangentAngle$4(cx, cy, rx, ry, xRotation, startAngle, endAngle, t) { | ||
var angle = (endAngle - startAngle) * t + startAngle; | ||
return { | ||
x: xAt(cx, cy, rx, ry, xRotation, angle), | ||
y: yAt(cx, cy, rx, ry, xRotation, angle) | ||
}; | ||
}, | ||
tangentAngle: function tangentAngle(cx, cy, rx, ry, xRotation, startAngle, endAngle, t) { | ||
var angle = (endAngle - startAngle) * t + startAngle; | ||
var dx = derivativeXAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle); | ||
var dy = derivativeYAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle); | ||
return piMod(Math.atan2(dy, dx)); | ||
} | ||
}; | ||
} | ||
function analyzePoints(points) { | ||
// 计算每段的长度和总的长度 | ||
var totalLength = 0; | ||
var segments = []; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var from = points[i]; | ||
var to = points[i + 1]; | ||
var length = distance(from[0], from[1], to[0], to[1]); | ||
var seg = { | ||
from: from, | ||
to: to, | ||
length: length | ||
var EPSILON = 0.0001; | ||
/** | ||
* 使用牛顿切割法求最近的点 | ||
* @param {number[]} xArr 点的 x 数组 | ||
* @param {number[]} yArr 点的 y 数组 | ||
* @param {number} x 指定的点 x | ||
* @param {number} y 指定的点 y | ||
* @param {Function} tCallback 差值函数 | ||
*/ | ||
function nearestPoint$2(xArr, yArr, x, y, tCallback, length) { | ||
var t = -1; | ||
var d = Infinity; | ||
var v0 = [x, y]; | ||
var segNum = 20; | ||
if (length && length > 200) { | ||
segNum = length / 10; | ||
} | ||
var increaseRate = 1 / segNum; | ||
var interval = increaseRate / 10; | ||
for (var i = 0; i <= segNum; i++) { | ||
var _t = i * increaseRate; | ||
var v1 = [ | ||
tCallback.apply(void 0, tslib.__spreadArray([], tslib.__read(xArr.concat([_t])), false)), | ||
tCallback.apply(void 0, tslib.__spreadArray([], tslib.__read(yArr.concat([_t])), false)), | ||
]; | ||
var d1 = distance(v0[0], v0[1], v1[0], v1[1]); | ||
if (d1 < d) { | ||
t = _t; | ||
d = d1; | ||
} | ||
} | ||
// 提前终止 | ||
if (t === 0) { | ||
return { | ||
x: xArr[0], | ||
y: yArr[0], | ||
}; | ||
} | ||
if (t === 1) { | ||
var count = xArr.length; | ||
return { | ||
x: xArr[count - 1], | ||
y: yArr[count - 1], | ||
}; | ||
} | ||
d = Infinity; | ||
for (var i = 0; i < 32; i++) { | ||
if (interval < EPSILON) { | ||
break; | ||
} | ||
var prev = t - interval; | ||
var next = t + interval; | ||
var v1 = [ | ||
tCallback.apply(void 0, tslib.__spreadArray([], tslib.__read(xArr.concat([prev])), false)), | ||
tCallback.apply(void 0, tslib.__spreadArray([], tslib.__read(yArr.concat([prev])), false)), | ||
]; | ||
var d1 = distance(v0[0], v0[1], v1[0], v1[1]); | ||
if (prev >= 0 && d1 < d) { | ||
t = prev; | ||
d = d1; | ||
} | ||
else { | ||
var v2 = [ | ||
tCallback.apply(void 0, tslib.__spreadArray([], tslib.__read(xArr.concat([next])), false)), | ||
tCallback.apply(void 0, tslib.__spreadArray([], tslib.__read(yArr.concat([next])), false)), | ||
]; | ||
var d2 = distance(v0[0], v0[1], v2[0], v2[1]); | ||
if (next <= 1 && d2 < d) { | ||
t = next; | ||
d = d2; | ||
} | ||
else { | ||
interval *= 0.5; | ||
} | ||
} | ||
} | ||
return { | ||
x: tCallback.apply(void 0, tslib.__spreadArray([], tslib.__read(xArr.concat([t])), false)), | ||
y: tCallback.apply(void 0, tslib.__spreadArray([], tslib.__read(yArr.concat([t])), false)), | ||
}; | ||
segments.push(seg); | ||
totalLength += length; | ||
} | ||
return { | ||
segments: segments, | ||
totalLength: totalLength | ||
}; | ||
} | ||
// 近似求解 https://community.khronos.org/t/3d-cubic-bezier-segment-length/62363/2 | ||
function snapLength(xArr, yArr) { | ||
var totalLength = 0; | ||
var count = xArr.length; | ||
for (var i = 0; i < count; i++) { | ||
var x = xArr[i]; | ||
var y = yArr[i]; | ||
var nextX = xArr[(i + 1) % count]; | ||
var nextY = yArr[(i + 1) % count]; | ||
totalLength += distance(x, y, nextX, nextY); | ||
} | ||
return totalLength / 2; | ||
} | ||
function box$4(x1, y1, x2, y2) { | ||
return getBBoxByArray([x1, x2], [y1, y2]); | ||
} | ||
function length$4(x1, y1, x2, y2) { | ||
return distance(x1, y1, x2, y2); | ||
} | ||
function pointAt$3(x1, y1, x2, y2, t) { | ||
return { | ||
x: (1 - t) * x1 + t * x2, | ||
y: (1 - t) * y1 + t * y2, | ||
}; | ||
} | ||
function pointDistance$4(x1, y1, x2, y2, x, y) { | ||
// 投影距离 x1, y1 的向量,假设 p, p1, p2 三个点,投影点为 a | ||
// p1a = p1p.p1p2/|p1p2| * (p1p 的单位向量) | ||
var cross = (x2 - x1) * (x - x1) + (y2 - y1) * (y - y1); | ||
if (cross < 0) { | ||
return distance(x1, y1, x, y); | ||
} | ||
var lengthSquare = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1); | ||
if (cross > lengthSquare) { | ||
return distance(x2, y2, x, y); | ||
} | ||
return this.pointToLine(x1, y1, x2, y2, x, y); | ||
} | ||
function pointToLine(x1, y1, x2, y2, x, y) { | ||
var d = [x2 - x1, y2 - y1]; | ||
// 如果端点相等,则判定点到点的距离 | ||
if (glMatrix.vec2.exactEquals(d, [0, 0])) { | ||
return Math.sqrt((x - x1) * (x - x1) + (y - y1) * (y - y1)); | ||
} | ||
var u = [-d[1], d[0]]; | ||
glMatrix.vec2.normalize(u, u); | ||
var a = [x - x1, y - y1]; | ||
return Math.abs(glMatrix.vec2.dot(a, u)); | ||
} | ||
function tangentAngle$3(x1, y1, x2, y2) { | ||
return Math.atan2(y2 - y1, x2 - x1); | ||
} | ||
function cubicAt(p0, p1, p2, p3, t) { | ||
var onet = 1 - t; // t * t * t 的性能大概是 Math.pow(t, 3) 的三倍 | ||
return (onet * onet * onet * p0 + | ||
3 * p1 * t * onet * onet + | ||
3 * p2 * t * t * onet + | ||
p3 * t * t * t); | ||
} | ||
function derivativeAt(p0, p1, p2, p3, t) { | ||
var onet = 1 - t; | ||
return (3 * (onet * onet * (p1 - p0) + 2 * onet * t * (p2 - p1) + t * t * (p3 - p2))); | ||
} | ||
function extrema$1(p0, p1, p2, p3) { | ||
var a = -3 * p0 + 9 * p1 - 9 * p2 + 3 * p3; | ||
var b = 6 * p0 - 12 * p1 + 6 * p2; | ||
var c = 3 * p1 - 3 * p0; | ||
var extremas = []; | ||
var t1; | ||
var t2; | ||
var discSqrt; | ||
if (isNumberEqual(a, 0)) { | ||
if (!isNumberEqual(b, 0)) { | ||
t1 = -c / b; | ||
if (t1 >= 0 && t1 <= 1) { | ||
extremas.push(t1); | ||
} | ||
} | ||
} | ||
else { | ||
var disc = b * b - 4 * a * c; | ||
if (isNumberEqual(disc, 0)) { | ||
extremas.push(-b / (2 * a)); | ||
} | ||
else if (disc > 0) { | ||
discSqrt = Math.sqrt(disc); | ||
t1 = (-b + discSqrt) / (2 * a); | ||
t2 = (-b - discSqrt) / (2 * a); | ||
if (t1 >= 0 && t1 <= 1) { | ||
extremas.push(t1); | ||
} | ||
if (t2 >= 0 && t2 <= 1) { | ||
extremas.push(t2); | ||
} | ||
} | ||
} | ||
return extremas; | ||
} | ||
// 分割贝塞尔曲线 | ||
function divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
// 划分点 | ||
var xt = cubicAt(x1, x2, x3, x4, t); | ||
var yt = cubicAt(y1, y2, y3, y4, t); | ||
// 计算两点之间的差值点 | ||
var c1 = pointAt$3(x1, y1, x2, y2, t); | ||
var c2 = pointAt$3(x2, y2, x3, y3, t); | ||
var c3 = pointAt$3(x3, y3, x4, y4, t); | ||
var c12 = pointAt$3(c1.x, c1.y, c2.x, c2.y, t); | ||
var c23 = pointAt$3(c2.x, c2.y, c3.x, c3.y, t); | ||
return [ | ||
[x1, y1, c1.x, c1.y, c12.x, c12.y, xt, yt], | ||
[xt, yt, c23.x, c23.y, c3.x, c3.y, x4, y4], | ||
]; | ||
} | ||
// 使用迭代法取贝塞尔曲线的长度,二阶和三阶分开写,更清晰和便于调试 | ||
function cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, iterationCount) { | ||
if (iterationCount === 0) { | ||
return snapLength([x1, x2, x3, x4], [y1, y2, y3, y4]); | ||
} | ||
var cubics = divideCubic(x1, y1, x2, y2, x3, y3, x4, y4, 0.5); | ||
var left = tslib.__spreadArray(tslib.__spreadArray([], tslib.__read(cubics[0]), false), [iterationCount - 1], false); | ||
var right = tslib.__spreadArray(tslib.__spreadArray([], tslib.__read(cubics[1]), false), [iterationCount - 1], false); | ||
return cubicLength.apply(void 0, tslib.__spreadArray([], tslib.__read(left), false)) + cubicLength.apply(void 0, tslib.__spreadArray([], tslib.__read(right), false)); | ||
} | ||
function box$3(x1, y1, x2, y2, x3, y3, x4, y4) { | ||
var xArr = [x1, x4]; | ||
var yArr = [y1, y4]; | ||
var xExtrema = extrema$1(x1, x2, x3, x4); | ||
var yExtrema = extrema$1(y1, y2, y3, y4); | ||
for (var i = 0; i < xExtrema.length; i++) { | ||
xArr.push(cubicAt(x1, x2, x3, x4, xExtrema[i])); | ||
} | ||
for (var i = 0; i < yExtrema.length; i++) { | ||
yArr.push(cubicAt(y1, y2, y3, y4, yExtrema[i])); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
} | ||
function length$3(x1, y1, x2, y2, x3, y3, x4, y4) { | ||
// 迭代三次,划分成 8 段求长度 | ||
return cubicLength(x1, y1, x2, y2, x3, y3, x4, y4, 3); | ||
} | ||
function nearestPoint$1(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { | ||
return nearestPoint$2([x1, x2, x3, x4], [y1, y2, y3, y4], x0, y0, cubicAt, length); | ||
} | ||
function pointDistance$3(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length) { | ||
var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x4, y4, x0, y0, length); | ||
return distance(point.x, point.y, x0, y0); | ||
} | ||
function pointAt$2(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
return { | ||
x: cubicAt(x1, x2, x3, x4, t), | ||
y: cubicAt(y1, y2, y3, y4, t), | ||
}; | ||
} | ||
function tangentAngle$2(x1, y1, x2, y2, x3, y3, x4, y4, t) { | ||
var dx = derivativeAt(x1, x2, x3, x4, t); | ||
var dy = derivativeAt(y1, y2, y3, y4, t); | ||
return piMod(Math.atan2(dy, dx)); | ||
} | ||
function analyzePoints(points) { | ||
// 计算每段的长度和总的长度 | ||
var totalLength = 0; | ||
var segments = []; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var from = points[i]; | ||
var to = points[i + 1]; | ||
var length_1 = distance(from[0], from[1], to[0], to[1]); | ||
var seg = { | ||
from: from, | ||
to: to, | ||
length: length_1, | ||
}; | ||
segments.push(seg); | ||
totalLength += length_1; | ||
} | ||
return { segments: segments, totalLength: totalLength }; | ||
} | ||
function lengthOfSegment(points) { | ||
if (points.length < 2) { | ||
return 0; | ||
} | ||
var totalLength = 0; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var from = points[i]; | ||
var to = points[i + 1]; | ||
totalLength += distance(from[0], from[1], to[0], to[1]); | ||
} | ||
return totalLength; | ||
if (points.length < 2) { | ||
return 0; | ||
} | ||
var totalLength = 0; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var from = points[i]; | ||
var to = points[i + 1]; | ||
totalLength += distance(from[0], from[1], to[0], to[1]); | ||
} | ||
return totalLength; | ||
} | ||
@@ -798,32 +504,29 @@ /** | ||
function pointAtSegments(points, t) { | ||
// 边界判断 | ||
if (t > 1 || t < 0 || points.length < 2) { | ||
return null; | ||
} | ||
var _analyzePoints = analyzePoints(points), | ||
segments = _analyzePoints.segments, | ||
totalLength = _analyzePoints.totalLength; | ||
// 多个点有可能重合 | ||
if (totalLength === 0) { | ||
return { | ||
x: points[0][0], | ||
y: points[0][1] | ||
}; | ||
} | ||
// 计算比例 | ||
var startRatio = 0; | ||
var point = null; | ||
for (var i = 0; i < segments.length; i++) { | ||
var seg = segments[i]; | ||
var from = seg.from, | ||
to = seg.to; | ||
var currentRatio = seg.length / totalLength; | ||
if (t >= startRatio && t <= startRatio + currentRatio) { | ||
var localRatio = (t - startRatio) / currentRatio; | ||
point = line.pointAt(from[0], from[1], to[0], to[1], localRatio); | ||
break; | ||
// 边界判断 | ||
if (t > 1 || t < 0 || points.length < 2) { | ||
return null; | ||
} | ||
startRatio += currentRatio; | ||
} | ||
return point; | ||
var _a = analyzePoints(points), segments = _a.segments, totalLength = _a.totalLength; | ||
// 多个点有可能重合 | ||
if (totalLength === 0) { | ||
return { | ||
x: points[0][0], | ||
y: points[0][1], | ||
}; | ||
} | ||
// 计算比例 | ||
var startRatio = 0; | ||
var point = null; | ||
for (var i = 0; i < segments.length; i++) { | ||
var seg = segments[i]; | ||
var from = seg.from, to = seg.to; | ||
var currentRatio = seg.length / totalLength; | ||
if (t >= startRatio && t <= startRatio + currentRatio) { | ||
var localRatio = (t - startRatio) / currentRatio; | ||
point = pointAt$3(from[0], from[1], to[0], to[1], localRatio); | ||
break; | ||
} | ||
startRatio += currentRatio; | ||
} | ||
return point; | ||
} | ||
@@ -836,152 +539,182 @@ /** | ||
function angleAtSegments(points, t) { | ||
// 边界判断 | ||
if (t > 1 || t < 0 || points.length < 2) { | ||
return 0; | ||
} | ||
var _analyzePoints2 = analyzePoints(points), | ||
segments = _analyzePoints2.segments, | ||
totalLength = _analyzePoints2.totalLength; | ||
// 计算比例 | ||
var startRatio = 0; | ||
var angle = 0; | ||
for (var i = 0; i < segments.length; i++) { | ||
var seg = segments[i]; | ||
var from = seg.from, | ||
to = seg.to; | ||
var currentRatio = seg.length / totalLength; | ||
if (t >= startRatio && t <= startRatio + currentRatio) { | ||
angle = Math.atan2(to[1] - from[1], to[0] - from[0]); | ||
break; | ||
// 边界判断 | ||
if (t > 1 || t < 0 || points.length < 2) { | ||
return 0; | ||
} | ||
startRatio += currentRatio; | ||
} | ||
return angle; | ||
var _a = analyzePoints(points), segments = _a.segments, totalLength = _a.totalLength; | ||
// 计算比例 | ||
var startRatio = 0; | ||
var angle = 0; | ||
for (var i = 0; i < segments.length; i++) { | ||
var seg = segments[i]; | ||
var from = seg.from, to = seg.to; | ||
var currentRatio = seg.length / totalLength; | ||
if (t >= startRatio && t <= startRatio + currentRatio) { | ||
angle = Math.atan2(to[1] - from[1], to[0] - from[0]); | ||
break; | ||
} | ||
startRatio += currentRatio; | ||
} | ||
return angle; | ||
} | ||
function distanceAtSegment(points, x, y) { | ||
var minDistance = Infinity; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var point = points[i]; | ||
var nextPoint = points[i + 1]; | ||
var _distance = line.pointDistance(point[0], point[1], nextPoint[0], nextPoint[1], x, y); | ||
if (_distance < minDistance) { | ||
minDistance = _distance; | ||
var minDistance = Infinity; | ||
for (var i = 0; i < points.length - 1; i++) { | ||
var point = points[i]; | ||
var nextPoint = points[i + 1]; | ||
var distance_1 = pointDistance$4(point[0], point[1], nextPoint[0], nextPoint[1], x, y); | ||
if (distance_1 < minDistance) { | ||
minDistance = distance_1; | ||
} | ||
} | ||
} | ||
return minDistance; | ||
return minDistance; | ||
} | ||
var polyline = { | ||
/** | ||
* 计算多折线的包围盒 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 包围盒 | ||
*/ | ||
box: function box(points) { | ||
function box$2(points) { | ||
var xArr = []; | ||
var yArr = []; | ||
for (var i = 0; i < points.length; i++) { | ||
var point = points[i]; | ||
xArr.push(point[0]); | ||
yArr.push(point[1]); | ||
var point = points[i]; | ||
xArr.push(point[0]); | ||
yArr.push(point[1]); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
}, | ||
/** | ||
* 计算多折线的长度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 多条边的长度 | ||
*/ | ||
length: function length(points) { | ||
} | ||
function length$2(points) { | ||
return lengthOfSegment(points); | ||
}, | ||
/** | ||
* 根据比例获取多折线的点 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多折线的长度上的比例 | ||
* @return {object} 根据比例值计算出来的点 | ||
*/ | ||
pointAt: function pointAt(points, t) { | ||
} | ||
function pointAt$1(points, t) { | ||
return pointAtSegments(points, t); | ||
}, | ||
/** | ||
* 指定点到多折线的距离 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} x 指定点的 x | ||
* @param {number} y 指定点的 y | ||
* @return {number} 点到多折线的距离 | ||
*/ | ||
pointDistance: function pointDistance(points, x, y) { | ||
} | ||
function pointDistance$2(points, x, y) { | ||
return distanceAtSegment(points, x, y); | ||
}, | ||
/** | ||
* 根据比例获取多折线的切线角度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多折线的长度上的比例 | ||
* @return {object} 根据比例值计算出来的角度 | ||
*/ | ||
tangentAngle: function tangentAngle(points, t) { | ||
} | ||
function tangentAngle$1(points, t) { | ||
return angleAtSegments(points, t); | ||
} | ||
}; | ||
} | ||
function getAllPoints(points) { | ||
var tmp = points.slice(0); | ||
if (points.length) { | ||
tmp.push(points[0]); | ||
} | ||
return tmp; | ||
var tmp = points.slice(0); | ||
if (points.length) { | ||
tmp.push(points[0]); | ||
} | ||
return tmp; | ||
} | ||
var polygon = { | ||
/** | ||
* 计算多边形的包围盒 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 包围盒 | ||
*/ | ||
box: function box(points) { | ||
return polyline.box(points); | ||
}, | ||
/** | ||
* 计算多边形的长度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 多边形边的长度 | ||
*/ | ||
length: function length(points) { | ||
function box$1(points) { | ||
return box$2(points); | ||
} | ||
function length$1(points) { | ||
return lengthOfSegment(getAllPoints(points)); | ||
}, | ||
/** | ||
* 根据比例获取多边形的点 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多边形的长度上的比例 | ||
* @return {object} 根据比例值计算出来的点 | ||
*/ | ||
pointAt: function pointAt(points, t) { | ||
} | ||
function pointAt(points, t) { | ||
return pointAtSegments(getAllPoints(points), t); | ||
}, | ||
/** | ||
* 指定点到多边形的距离 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} x 指定点的 x | ||
* @param {number} y 指定点的 y | ||
* @return {number} 点到多边形的距离 | ||
*/ | ||
pointDistance: function pointDistance(points, x, y) { | ||
} | ||
function pointDistance$1(points, x, y) { | ||
return distanceAtSegment(getAllPoints(points), x, y); | ||
}, | ||
/** | ||
* 根据比例获取多边形的切线角度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多边形的长度上的比例 | ||
* @return {object} 根据比例值计算出来的角度 | ||
*/ | ||
tangentAngle: function tangentAngle(points, t) { | ||
} | ||
function tangentAngle(points, t) { | ||
return angleAtSegments(getAllPoints(points), t); | ||
} | ||
}; | ||
} | ||
exports.Arc = arc; | ||
exports.Cubic = cubic; | ||
exports.Line = line; | ||
exports.Polygon = polygon; | ||
exports.Polyline = polyline; | ||
exports.Quad = quadratic; | ||
exports.Util = util; | ||
// 差值公式 | ||
function quadraticAt(p0, p1, p2, t) { | ||
var onet = 1 - t; | ||
return onet * onet * p0 + 2 * t * onet * p1 + t * t * p2; | ||
} | ||
// 求极值 | ||
function extrema(p0, p1, p2) { | ||
var a = p0 + p2 - 2 * p1; | ||
if (isNumberEqual(a, 0)) { | ||
return [0.5]; | ||
} | ||
var rst = (p0 - p1) / a; | ||
if (rst <= 1 && rst >= 0) { | ||
return [rst]; | ||
} | ||
return []; | ||
} | ||
// 分割贝塞尔曲线 | ||
function divideQuadratic(x1, y1, x2, y2, x3, y3, t) { | ||
// 划分点 | ||
var xt = quadraticAt(x1, x2, x3, t); | ||
var yt = quadraticAt(y1, y2, y3, t); | ||
// 分割的第一条曲线的控制点 | ||
var controlPoint1 = pointAt$3(x1, y1, x2, y2, t); | ||
// 分割的第二条曲线的控制点 | ||
var controlPoint2 = pointAt$3(x2, y2, x3, y3, t); | ||
return [ | ||
[x1, y1, controlPoint1.x, controlPoint1.y, xt, yt], | ||
[xt, yt, controlPoint2.x, controlPoint2.y, x3, y3], | ||
]; | ||
} | ||
// 使用迭代法取贝塞尔曲线的长度 | ||
function quadraticLength(x1, y1, x2, y2, x3, y3, iterationCount) { | ||
if (iterationCount === 0) { | ||
return ((distance(x1, y1, x2, y2) + | ||
distance(x2, y2, x3, y3) + | ||
distance(x1, y1, x3, y3)) / | ||
2); | ||
} | ||
var quadratics = divideQuadratic(x1, y1, x2, y2, x3, y3, 0.5); | ||
var left = quadratics[0]; | ||
var right = quadratics[1]; | ||
left.push(iterationCount - 1); | ||
right.push(iterationCount - 1); | ||
return quadraticLength.apply(void 0, tslib.__spreadArray([], tslib.__read(left), false)) + quadraticLength.apply(void 0, tslib.__spreadArray([], tslib.__read(right), false)); | ||
} | ||
function box(x1, y1, x2, y2, x3, y3) { | ||
var xExtrema = extrema(x1, x2, x3)[0]; | ||
var yExtrema = extrema(y1, y2, y3)[0]; | ||
// 控制点不加入 box 的计算 | ||
var xArr = [x1, x3]; | ||
var yArr = [y1, y3]; | ||
if (xExtrema !== undefined) { | ||
xArr.push(quadraticAt(x1, x2, x3, xExtrema)); | ||
} | ||
if (yExtrema !== undefined) { | ||
yArr.push(quadraticAt(y1, y2, y3, yExtrema)); | ||
} | ||
return getBBoxByArray(xArr, yArr); | ||
} | ||
function length(x1, y1, x2, y2, x3, y3) { | ||
return quadraticLength(x1, y1, x2, y2, x3, y3, 3); | ||
} | ||
function nearestPoint(x1, y1, x2, y2, x3, y3, x0, y0) { | ||
return nearestPoint$2([x1, x2, x3], [y1, y2, y3], x0, y0, quadraticAt); | ||
} | ||
function pointDistance(x1, y1, x2, y2, x3, y3, x0, y0) { | ||
var point = this.nearestPoint(x1, y1, x2, y2, x3, y3, x0, y0); | ||
return distance(point.x, point.y, x0, y0); | ||
} | ||
exports.arcBox = box$5; | ||
exports.arcNearestPoint = nearestPoint$3; | ||
exports.arcTangentAngle = tangentAngle$4; | ||
exports.cubicBox = box$3; | ||
exports.cubicLength = length$3; | ||
exports.cubicNearestPoint = nearestPoint$1; | ||
exports.cubicPointAt = pointAt$2; | ||
exports.cubicPointDistance = pointDistance$3; | ||
exports.cubicTangentAngle = tangentAngle$2; | ||
exports.distance = distance; | ||
exports.lineBox = box$4; | ||
exports.lineLength = length$4; | ||
exports.linePointAt = pointAt$3; | ||
exports.linePointDistance = pointDistance$4; | ||
exports.linePointToLine = pointToLine; | ||
exports.lineTangentAngle = tangentAngle$3; | ||
exports.polygonBox = box$1; | ||
exports.polygonLength = length$1; | ||
exports.polygonPointAt = pointAt; | ||
exports.polygonPointDistance = pointDistance$1; | ||
exports.polygonTangentAngle = tangentAngle; | ||
exports.polylineBox = box$2; | ||
exports.polylineLength = length$2; | ||
exports.polylinePointAt = pointAt$1; | ||
exports.polylinePointDistance = pointDistance$2; | ||
exports.polylineTangentAngle = tangentAngle$1; | ||
exports.quadBox = box; | ||
exports.quadLength = length; | ||
exports.quadNearestPoint = nearestPoint; | ||
exports.quadPointDistance = pointDistance; | ||
//# sourceMappingURL=index.js.map |
@@ -1,1 +0,2 @@ | ||
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(((t="undefined"!=typeof globalThis?globalThis:t||self).G=t.G||{},t.G.Math={}))}(this,(function(t){"use strict";function n(t,n,r,a){var o=t-r,e=n-a;return Math.sqrt(o*o+e*e)}function r(t,n){return.001>Math.abs(t-n)}function a(t,n){var r=Math.min.apply(Math,t),a=Math.min.apply(Math,n);return{x:r,y:a,width:Math.max.apply(Math,t)-r,height:Math.max.apply(Math,n)-a}}function o(t){return(t+2*Math.PI)%(2*Math.PI)}var e=Object.freeze({__proto__:null,distance:n,isNumberEqual:r,getBBoxByArray:a,getBBoxRange:function(t,n,r,a){return{minX:Math.min(t,r),maxX:Math.max(t,r),minY:Math.min(n,a),maxY:Math.max(n,a)}},piMod:o}),i="undefined"!=typeof Float32Array?Float32Array:Array;Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)});u=new i(2),i!=Float32Array&&(u[0]=0,u[1]=0),h=u;var u,h,f={box:function(t,n,r,o){return a([t,r],[n,o])},length:function(t,r,a,o){return n(t,r,a,o)},pointAt:function(t,n,r,a,o){return{x:(1-o)*t+o*r,y:(1-o)*n+o*a}},pointDistance:function(t,r,a,o,e,i){var u=(a-t)*(e-t)+(o-r)*(i-r);return 0>u?n(t,r,e,i):u>(a-t)*(a-t)+(o-r)*(o-r)?n(a,o,e,i):this.pointToLine(t,r,a,o,e,i)},pointToLine:function(t,n,r,a,o,e){var i=[r-t,a-n];if(function(t,n){return t[0]===n[0]&&t[1]===n[1]}(i,[0,0]))return Math.sqrt((o-t)*(o-t)+(e-n)*(e-n));var u=[-i[1],i[0]];return function(t,n){var r=n[0],a=n[1],o=r*r+a*a;o>0&&(o=1/Math.sqrt(o)),t[0]=n[0]*o,t[1]=n[1]*o}(u,u),Math.abs(function(t,n){return t[0]*n[0]+t[1]*n[1]}([o-t,e-n],u))},tangentAngle:function(t,n,r,a){return Math.atan2(a-n,r-t)}};function c(t,r,a,o,e,i){var u=-1,h=1/0,f=[a,o],c=20;i&&i>200&&(c=i/10);for(var p=1/c,s=p/10,v=0;c>=v;v++){var M=v*p,l=[e.apply(void 0,t.concat([M])),e.apply(void 0,r.concat([M]))],y=n(f[0],f[1],l[0],l[1]);h>y&&(u=M,h=y)}if(0===u)return{x:t[0],y:r[0]};if(1===u){var g=t.length;return{x:t[g-1],y:r[g-1]}}h=1/0;for(var x=0;32>x&&1e-4<=s;x++){var d=u-s,A=u+s,m=[e.apply(void 0,t.concat([d])),e.apply(void 0,r.concat([d]))],b=n(f[0],f[1],m[0],m[1]);if(d>=0&&h>b)u=d,h=b;else{var P=[e.apply(void 0,t.concat([A])),e.apply(void 0,r.concat([A]))],I=n(f[0],f[1],P[0],P[1]);1>=A&&h>I?(u=A,h=I):s*=.5}}return{x:e.apply(void 0,t.concat([u])),y:e.apply(void 0,r.concat([u]))}}function p(t,n,r,a){var o=1-a;return o*o*t+2*a*o*n+a*a*r}function s(t,n,a){var o=t+a-2*n;if(r(o,0))return[.5];var e=(t-n)/o;return e>1||0>e?[]:[e]}function v(t,n,r,a){return 2*(1-a)*(n-t)+2*a*(r-n)}function M(t,n,r,a,o,e,i){var u=p(t,r,o,i),h=p(n,a,e,i),c=f.pointAt(t,n,r,a,i),s=f.pointAt(r,a,o,e,i);return[[t,n,c.x,c.y,u,h],[u,h,s.x,s.y,o,e]]}function l(t,r,a,o,e,i,u){if(0===u)return(n(t,r,a,o)+n(a,o,e,i)+n(t,r,e,i))/2;var h=M(t,r,a,o,e,i,.5),f=h[0],c=h[1];return f.push(u-1),c.push(u-1),l.apply(void 0,f)+l.apply(void 0,c)}var y={box:function(t,n,r,o,e,i){var u=s(t,r,e)[0],h=s(n,o,i)[0],f=[t,e],c=[n,i];return void 0!==u&&f.push(p(t,r,e,u)),void 0!==h&&c.push(p(n,o,i,h)),a(f,c)},length:function(t,n,r,a,o,e){return l(t,n,r,a,o,e,3)},nearestPoint:function(t,n,r,a,o,e,i,u){return c([t,r,o],[n,a,e],i,u,p)},pointDistance:function(t,r,a,o,e,i,u,h){var f=this.nearestPoint(t,r,a,o,e,i,u,h);return n(f.x,f.y,u,h)},interpolationAt:p,pointAt:function(t,n,r,a,o,e,i){return{x:p(t,r,o,i),y:p(n,a,e,i)}},divide:function(t,n,r,a,o,e,i){return M(t,n,r,a,o,e,i)},tangentAngle:function(t,n,r,a,e,i,u){var h=v(t,r,e,u),f=v(n,a,i,u);return o(Math.atan2(f,h))}};function g(t,n,r,a,o){var e=1-o;return e*e*e*t+3*n*o*e*e+3*r*o*o*e+a*o*o*o}function x(t,n,r,a,o){var e=1-o;return 3*(e*e*(n-t)+2*e*o*(r-n)+o*o*(a-r))}function d(t,n,a,o){var e,i,u,h=-3*t+9*n-9*a+3*o,f=6*t-12*n+6*a,c=3*n-3*t,p=[];if(r(h,0))r(f,0)||0>(e=-c/f)||e>1||p.push(e);else{var s=f*f-4*h*c;r(s,0)?p.push(-f/(2*h)):s>0&&(i=(-f-(u=Math.sqrt(s)))/(2*h),0>(e=(-f+u)/(2*h))||e>1||p.push(e),0>i||i>1||p.push(i))}return p}function A(t,n,r,a,o,e,i,u,h){var c=g(t,r,o,i,h),p=g(n,a,e,u,h),s=f.pointAt(t,n,r,a,h),v=f.pointAt(r,a,o,e,h),M=f.pointAt(o,e,i,u,h),l=f.pointAt(s.x,s.y,v.x,v.y,h),y=f.pointAt(v.x,v.y,M.x,M.y,h);return[[t,n,s.x,s.y,l.x,l.y,c,p],[c,p,y.x,y.y,M.x,M.y,i,u]]}function m(t,r,a,o,e,i,u,h,f){if(0===f)return function(t,r){for(var a=0,o=t.length,e=0;o>e;e++)a+=n(t[e],r[e],t[(e+1)%o],r[(e+1)%o]);return a/2}([t,a,e,u],[r,o,i,h]);var c=A(t,r,a,o,e,i,u,h,.5),p=[].concat(c[0],[f-1]),s=[].concat(c[1],[f-1]);return m.apply(void 0,p)+m.apply(void 0,s)}var b={extrema:d,box:function(t,n,r,o,e,i,u,h){for(var f=[t,u],c=[n,h],p=d(t,r,e,u),s=d(n,o,i,h),v=0;p.length>v;v++)f.push(g(t,r,e,u,p[v]));for(var M=0;s.length>M;M++)c.push(g(n,o,i,h,s[M]));return a(f,c)},length:function(t,n,r,a,o,e,i,u){return m(t,n,r,a,o,e,i,u,3)},nearestPoint:function(t,n,r,a,o,e,i,u,h,f,p){return c([t,r,o,i],[n,a,e,u],h,f,g,p)},pointDistance:function(t,r,a,o,e,i,u,h,f,c,p){var s=this.nearestPoint(t,r,a,o,e,i,u,h,f,c,p);return n(s.x,s.y,f,c)},interpolationAt:g,pointAt:function(t,n,r,a,o,e,i,u,h){return{x:g(t,r,o,i,h),y:g(n,a,e,u,h)}},divide:function(t,n,r,a,o,e,i,u,h){return A(t,n,r,a,o,e,i,u,h)},tangentAngle:function(t,n,r,a,e,i,u,h,f){var c=x(t,r,e,u,f),p=x(n,a,i,h,f);return o(Math.atan2(p,c))}};function P(t,n){var r=Math.abs(t);return n>0?r:-1*r}var I=function(t,n,r,a,o,e){var i=r,u=a;if(0===i||0===u)return{x:t,y:n};for(var h=o-t,f=e-n,c=Math.abs(h),p=Math.abs(f),s=i*i,v=u*u,M=Math.PI/4,l=0,y=0,g=0;4>g;g++){l=i*Math.cos(M),y=u*Math.sin(M);var x=(s-v)*Math.pow(Math.cos(M),3)/i,d=(v-s)*Math.pow(Math.sin(M),3)/u,A=l-x,m=y-d,b=c-x,I=p-d,q=Math.hypot(m,A),D=Math.hypot(I,b);M=Math.min(Math.PI/2,Math.max(0,M+=q*Math.asin((A*I-m*b)/(q*D))/Math.sqrt(s+v-l*l-y*y)))}return{x:t+P(l,h),y:n+P(y,f)}};function q(t,n,r,a,o,e){return r*Math.cos(o)*Math.cos(e)-a*Math.sin(o)*Math.sin(e)+t}function D(t,n,r,a,o,e){return r*Math.sin(o)*Math.cos(e)+a*Math.cos(o)*Math.sin(e)+n}function L(t,n,r){return{x:t*Math.cos(r),y:n*Math.sin(r)}}function _(t,n,r){var a=Math.cos(r),o=Math.sin(r);return[t*a-n*o,t*o+n*a]}var w={box:function(t,n,r,a,o,e,i){for(var u=function(t,n,r){return Math.atan(-n/t*Math.tan(r))}(r,a,o),h=1/0,f=-1/0,c=[e,i],p=2*-Math.PI;2*Math.PI>=p;p+=Math.PI){var s=u+p;i>e?s>e&&i>s&&c.push(s):s>i&&e>s&&c.push(s)}for(var v=0;c.length>v;v++){var M=q(t,0,r,a,o,c[v]);h>M&&(h=M),M>f&&(f=M)}for(var l=function(t,n,r){return Math.atan(n/(t*Math.tan(r)))}(r,a,o),y=1/0,g=-1/0,x=[e,i],d=2*-Math.PI;2*Math.PI>=d;d+=Math.PI){var A=l+d;i>e?A>e&&i>A&&x.push(A):A>i&&e>A&&x.push(A)}for(var m=0;x.length>m;m++){var b=D(0,n,r,a,o,x[m]);y>b&&(y=b),b>g&&(g=b)}return{x:h,y:y,width:f-h,height:g-y}},length:function(t,n,r,a,o,e,i){},nearestPoint:function(t,n,r,a,o,e,i,u,h){var f=_(u-t,h-n,-o),c=I(0,0,r,a,f[0],f[1]),p=function(t,n,r,a){return(Math.atan2(a*t,r*n)+2*Math.PI)%(2*Math.PI)}(r,a,c.x,c.y);e>p?c=L(r,a,e):p>i&&(c=L(r,a,i));var s=_(c.x,c.y,o);return{x:s[0]+t,y:s[1]+n}},pointDistance:function(t,r,a,o,e,i,u,h,f){var c=this.nearestPoint(t,r,a,o,e,i,u,h,f);return n(c.x,c.y,h,f)},pointAt:function(t,n,r,a,o,e,i,u){var h=(i-e)*u+e;return{x:q(t,0,r,a,o,h),y:D(0,n,r,a,o,h)}},tangentAngle:function(t,n,r,a,e,i,u,h){var f=(u-i)*h+i,c=function(t,n,r,a,o,e,i,u){return-1*r*Math.cos(o)*Math.sin(u)-a*Math.sin(o)*Math.cos(u)}(0,0,r,a,e,0,0,f),p=function(t,n,r,a,o,e,i,u){return-1*r*Math.sin(o)*Math.sin(u)+a*Math.cos(o)*Math.cos(u)}(0,0,r,a,e,0,0,f);return o(Math.atan2(p,c))}};function B(t){for(var r=0,a=[],o=0;t.length-1>o;o++){var e=t[o],i=t[o+1],u=n(e[0],e[1],i[0],i[1]);a.push({from:e,to:i,length:u}),r+=u}return{segments:a,totalLength:r}}function T(t){if(2>t.length)return 0;for(var r=0,a=0;t.length-1>a;a++){var o=t[a],e=t[a+1];r+=n(o[0],o[1],e[0],e[1])}return r}function j(t,n){if(n>1||0>n||2>t.length)return null;var r=B(t),a=r.segments,o=r.totalLength;if(0===o)return{x:t[0][0],y:t[0][1]};for(var e=0,i=null,u=0;a.length>u;u++){var h=a[u],c=h.from,p=h.to,s=h.length/o;if(n>=e&&e+s>=n){i=f.pointAt(c[0],c[1],p[0],p[1],(n-e)/s);break}e+=s}return i}function F(t,n){if(n>1||0>n||2>t.length)return 0;for(var r=B(t),a=r.segments,o=r.totalLength,e=0,i=0,u=0;a.length>u;u++){var h=a[u],f=h.from,c=h.to,p=h.length/o;if(n>=e&&e+p>=n){i=Math.atan2(c[1]-f[1],c[0]-f[0]);break}e+=p}return i}function G(t,n,r){for(var a=1/0,o=0;t.length-1>o;o++){var e=t[o],i=t[o+1],u=f.pointDistance(e[0],e[1],i[0],i[1],n,r);a>u&&(a=u)}return a}var k={box:function(t){for(var n=[],r=[],o=0;t.length>o;o++){var e=t[o];n.push(e[0]),r.push(e[1])}return a(n,r)},length:function(t){return T(t)},pointAt:function(t,n){return j(t,n)},pointDistance:function(t,n,r){return G(t,n,r)},tangentAngle:function(t,n){return F(t,n)}};function O(t){var n=t.slice(0);return t.length&&n.push(t[0]),n}var X={box:function(t){return k.box(t)},length:function(t){return T(O(t))},pointAt:function(t,n){return j(O(t),n)},pointDistance:function(t,n,r){return G(O(t),n,r)},tangentAngle:function(t,n){return F(O(t),n)}};t.Arc=w,t.Cubic=b,t.Line=f,t.Polygon=X,t.Polyline=k,t.Quad=y,t.Util=e,Object.defineProperty(t,"__esModule",{value:!0})})); | ||
!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(((t="undefined"!=typeof globalThis?globalThis:t||self).G=t.G||{},t.G.Math={}))}(this,(function(t){"use strict";function n(t,n){var r="function"==typeof Symbol&&t[Symbol.iterator];if(!r)return t;var a,o,e=r.call(t),u=[];try{for(;(void 0===n||n-- >0)&&!(a=e.next()).done;)u.push(a.value)}catch(t){o={error:t}}finally{try{a&&!a.done&&(r=e.return)&&r.call(e)}finally{if(o)throw o.error}}return u}function r(t,n,r){if(r||2===arguments.length)for(var a,o=0,e=n.length;e>o;o++)!a&&o in n||(a||(a=Array.prototype.slice.call(n,0,o)),a[o]=n[o]);return t.concat(a||Array.prototype.slice.call(n))}function a(t,n,r,a){var o=t-r,e=n-a;return Math.sqrt(o*o+e*e)}function o(t,n){return.001>Math.abs(t-n)}function e(t,a){var o=Math.min.apply(Math,r([],n(t),!1)),e=Math.min.apply(Math,r([],n(a),!1));return{x:o,y:e,width:Math.max.apply(Math,r([],n(t),!1))-o,height:Math.max.apply(Math,r([],n(a),!1))-e}}function u(t){return(t+2*Math.PI)%(2*Math.PI)}function i(t,n){var r=Math.abs(t);return n>0?r:-1*r}function h(t,n,r,a,o,e){return r*Math.cos(o)*Math.cos(e)-a*Math.sin(o)*Math.sin(e)+t}function c(t,n,r,a,o,e){return r*Math.sin(o)*Math.cos(e)+a*Math.cos(o)*Math.sin(e)+n}function f(t,n,r){return{x:t*Math.cos(r),y:n*Math.sin(r)}}function l(t,n,r){var a=Math.cos(r),o=Math.sin(r);return[t*a-n*o,t*o+n*a]}var s=1e-4;function p(t,o,e,u,i,h){var c=-1,f=1/0,l=[e,u],p=20;h&&h>200&&(p=h/10);for(var v=1/p,y=v/10,M=0;p>=M;M++){var g=M*v,x=[i.apply(void 0,r([],n(t.concat([g])),!1)),i.apply(void 0,r([],n(o.concat([g])),!1))];f>(m=a(l[0],l[1],x[0],x[1]))&&(c=g,f=m)}if(0===c)return{x:t[0],y:o[0]};if(1===c){var d=t.length;return{x:t[d-1],y:o[d-1]}}f=1/0;for(M=0;32>M&&s<=y;M++){var P=c-y,b=c+y,m=(x=[i.apply(void 0,r([],n(t.concat([P])),!1)),i.apply(void 0,r([],n(o.concat([P])),!1))],a(l[0],l[1],x[0],x[1]));if(P>=0&&f>m)c=P,f=m;else{var A=[i.apply(void 0,r([],n(t.concat([b])),!1)),i.apply(void 0,r([],n(o.concat([b])),!1))],I=a(l[0],l[1],A[0],A[1]);1>=b&&f>I?(c=b,f=I):y*=.5}}return{x:i.apply(void 0,r([],n(t.concat([c])),!1)),y:i.apply(void 0,r([],n(o.concat([c])),!1))}}var v,y="undefined"!=typeof Float32Array?Float32Array:Array;function M(t,n,r,a,o){return{x:(1-o)*t+o*r,y:(1-o)*n+o*a}}function g(t,n,r,o,e,u){var i=(r-t)*(e-t)+(o-n)*(u-n);return 0>i?a(t,n,e,u):i>(r-t)*(r-t)+(o-n)*(o-n)?a(r,o,e,u):this.pointToLine(t,n,r,o,e,u)}function x(t,n,r,a,o){var e=1-o;return e*e*e*t+3*n*o*e*e+3*r*o*o*e+a*o*o*o}function d(t,n,r,a,o){var e=1-o;return 3*(e*e*(n-t)+2*e*o*(r-n)+o*o*(a-r))}function P(t,n,r,a){var e,u,i,h=-3*t+9*n-9*r+3*a,c=6*t-12*n+6*r,f=3*n-3*t,l=[];if(o(h,0))o(c,0)||0>(e=-f/c)||e>1||l.push(e);else{var s=c*c-4*h*f;o(s,0)?l.push(-c/(2*h)):s>0&&(u=(-c-(i=Math.sqrt(s)))/(2*h),0>(e=(-c+i)/(2*h))||e>1||l.push(e),0>u||u>1||l.push(u))}return l}function b(t,o,e,u,i,h,c,f,l){if(0===l)return function(t,n){for(var r=0,o=t.length,e=0;o>e;e++)r+=a(t[e],n[e],t[(e+1)%o],n[(e+1)%o]);return r/2}([t,e,i,c],[o,u,h,f]);var s=function(t,n,r,a,o,e,u,i,h){var c=x(t,r,o,u,h),f=x(n,a,e,i,h),l=M(t,n,r,a,h),s=M(r,a,o,e,h),p=M(o,e,u,i,h),v=M(l.x,l.y,s.x,s.y,h),y=M(s.x,s.y,p.x,p.y,h);return[[t,n,l.x,l.y,v.x,v.y,c,f],[c,f,y.x,y.y,p.x,p.y,u,i]]}(t,o,e,u,i,h,c,f,.5),p=r(r([],n(s[0]),!1),[l-1],!1),v=r(r([],n(s[1]),!1),[l-1],!1);return b.apply(void 0,r([],n(p),!1))+b.apply(void 0,r([],n(v),!1))}function m(t){for(var n=0,r=[],o=0;t.length-1>o;o++){var e=t[o],u=t[o+1],i=a(e[0],e[1],u[0],u[1]);r.push({from:e,to:u,length:i}),n+=i}return{segments:r,totalLength:n}}function A(t){if(2>t.length)return 0;for(var n=0,r=0;t.length-1>r;r++){var o=t[r],e=t[r+1];n+=a(o[0],o[1],e[0],e[1])}return n}function I(t,n){if(n>1||0>n||2>t.length)return null;var r=m(t),a=r.segments,o=r.totalLength;if(0===o)return{x:t[0][0],y:t[0][1]};for(var e=0,u=null,i=0;a.length>i;i++){var h=a[i],c=h.from,f=h.to,l=h.length/o;if(n>=e&&e+l>=n){u=M(c[0],c[1],f[0],f[1],(n-e)/l);break}e+=l}return u}function q(t,n){if(n>1||0>n||2>t.length)return 0;for(var r=m(t),a=r.segments,o=r.totalLength,e=0,u=0,i=0;a.length>i;i++){var h=a[i],c=h.from,f=h.to,l=h.length/o;if(n>=e&&e+l>=n){u=Math.atan2(f[1]-c[1],f[0]-c[0]);break}e+=l}return u}function L(t,n,r){for(var a=1/0,o=0;t.length-1>o;o++){var e=t[o],u=t[o+1],i=g(e[0],e[1],u[0],u[1],n,r);a>i&&(a=i)}return a}function T(t){for(var n=[],r=[],a=0;t.length>a;a++){var o=t[a];n.push(o[0]),r.push(o[1])}return e(n,r)}function w(t){var n=t.slice(0);return t.length&&n.push(t[0]),n}function B(t,n,r,a){var o=1-a;return o*o*t+2*a*o*n+a*a*r}function D(t,n,r){var a=t+r-2*n;if(o(a,0))return[.5];var e=(t-n)/a;return e>1||0>e?[]:[e]}function F(t,o,e,u,i,h,c){if(0===c)return(a(t,o,e,u)+a(e,u,i,h)+a(t,o,i,h))/2;var f=function(t,n,r,a,o,e,u){var i=B(t,r,o,u),h=B(n,a,e,u),c=M(t,n,r,a,u),f=M(r,a,o,e,u);return[[t,n,c.x,c.y,i,h],[i,h,f.x,f.y,o,e]]}(t,o,e,u,i,h,.5),l=f[0],s=f[1];return l.push(c-1),s.push(c-1),F.apply(void 0,r([],n(l),!1))+F.apply(void 0,r([],n(s),!1))}Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)}),v=new y(2),y!=Float32Array&&(v[0]=0,v[1]=0),t.arcBox=function(t,n,r,a,o,e,u){for(var i=function(t,n,r){return Math.atan(-n/t*Math.tan(r))}(r,a,o),f=1/0,l=-1/0,s=[e,u],p=2*-Math.PI;2*Math.PI>=p;p+=Math.PI){var v=i+p;u>e?v>e&&u>v&&s.push(v):v>u&&e>v&&s.push(v)}for(p=0;s.length>p;p++){var y=h(t,0,r,a,o,s[p]);f>y&&(f=y),y>l&&(l=y)}var M=function(t,n,r){return Math.atan(n/(t*Math.tan(r)))}(r,a,o),g=1/0,x=-1/0,d=[e,u];for(p=2*-Math.PI;2*Math.PI>=p;p+=Math.PI){var P=M+p;u>e?P>e&&u>P&&d.push(P):P>u&&e>P&&d.push(P)}for(p=0;d.length>p;p++){var b=c(0,n,r,a,o,d[p]);g>b&&(g=b),b>x&&(x=b)}return{x:f,y:g,width:l-f,height:x-g}},t.arcNearestPoint=function(t,r,a,o,e,u,h,c,s){var p=n(l(c-t,s-r,-e),2),v=function(t,n,r,a,o,e){var u=r,h=a;if(0===u||0===h)return{x:t,y:n};for(var c=o-t,f=e-n,l=Math.abs(c),s=Math.abs(f),p=u*u,v=h*h,y=Math.PI/4,M=0,g=0,x=0;4>x;x++){M=u*Math.cos(y),g=h*Math.sin(y);var d=(p-v)*Math.pow(Math.cos(y),3)/u,P=(v-p)*Math.pow(Math.sin(y),3)/h,b=M-d,m=g-P,A=l-d,I=s-P,q=Math.hypot(m,b),L=Math.hypot(I,A);y=Math.min(Math.PI/2,Math.max(0,y+=q*Math.asin((b*I-m*A)/(q*L))/Math.sqrt(p+v-M*M-g*g)))}return{x:t+i(M,c),y:n+i(g,f)}}(0,0,a,o,p[0],p[1]),y=function(t,n,r,a){return(Math.atan2(a*t,r*n)+2*Math.PI)%(2*Math.PI)}(a,o,v.x,v.y);u>y?v=f(a,o,u):y>h&&(v=f(a,o,h));var M=l(v.x,v.y,e);return{x:M[0]+t,y:M[1]+r}},t.arcTangentAngle=function(t,n,r,a,o,e,i,h){var c=(i-e)*h+e,f=function(t,n,r,a,o,e,u,i){return-1*r*Math.cos(o)*Math.sin(i)-a*Math.sin(o)*Math.cos(i)}(0,0,r,a,o,0,0,c),l=function(t,n,r,a,o,e,u,i){return-1*r*Math.sin(o)*Math.sin(i)+a*Math.cos(o)*Math.cos(i)}(0,0,r,a,o,0,0,c);return u(Math.atan2(l,f))},t.cubicBox=function(t,n,r,a,o,u,i,h){for(var c=[t,i],f=[n,h],l=P(t,r,o,i),s=P(n,a,u,h),p=0;l.length>p;p++)c.push(x(t,r,o,i,l[p]));for(p=0;s.length>p;p++)f.push(x(n,a,u,h,s[p]));return e(c,f)},t.cubicLength=function(t,n,r,a,o,e,u,i){return b(t,n,r,a,o,e,u,i,3)},t.cubicNearestPoint=function(t,n,r,a,o,e,u,i,h,c,f){return p([t,r,o,u],[n,a,e,i],h,c,x,f)},t.cubicPointAt=function(t,n,r,a,o,e,u,i,h){return{x:x(t,r,o,u,h),y:x(n,a,e,i,h)}},t.cubicPointDistance=function(t,n,r,o,e,u,i,h,c,f,l){var s=this.nearestPoint(t,n,r,o,e,u,i,h,c,f,l);return a(s.x,s.y,c,f)},t.cubicTangentAngle=function(t,n,r,a,o,e,i,h,c){var f=d(t,r,o,i,c),l=d(n,a,e,h,c);return u(Math.atan2(l,f))},t.distance=a,t.lineBox=function(t,n,r,a){return e([t,r],[n,a])},t.lineLength=function(t,n,r,o){return a(t,n,r,o)},t.linePointAt=M,t.linePointDistance=g,t.linePointToLine=function(t,n,r,a,o,e){var u=[r-t,a-n];if(function(t,n){return t[0]===n[0]&&t[1]===n[1]}(u,[0,0]))return Math.sqrt((o-t)*(o-t)+(e-n)*(e-n));var i=[-u[1],u[0]];return function(t,n){var r=n[0],a=n[1],o=r*r+a*a;o>0&&(o=1/Math.sqrt(o)),t[0]=n[0]*o,t[1]=n[1]*o}(i,i),Math.abs(function(t,n){return t[0]*n[0]+t[1]*n[1]}([o-t,e-n],i))},t.lineTangentAngle=function(t,n,r,a){return Math.atan2(a-n,r-t)},t.polygonBox=function(t){return T(t)},t.polygonLength=function(t){return A(w(t))},t.polygonPointAt=function(t,n){return I(w(t),n)},t.polygonPointDistance=function(t,n,r){return L(w(t),n,r)},t.polygonTangentAngle=function(t,n){return q(w(t),n)},t.polylineBox=T,t.polylineLength=function(t){return A(t)},t.polylinePointAt=function(t,n){return I(t,n)},t.polylinePointDistance=function(t,n,r){return L(t,n,r)},t.polylineTangentAngle=function(t,n){return q(t,n)},t.quadBox=function(t,n,r,a,o,u){var i=D(t,r,o)[0],h=D(n,a,u)[0],c=[t,o],f=[n,u];return void 0!==i&&c.push(B(t,r,o,i)),void 0!==h&&f.push(B(n,a,u,h)),e(c,f)},t.quadLength=function(t,n,r,a,o,e){return F(t,n,r,a,o,e,3)},t.quadNearestPoint=function(t,n,r,a,o,e,u,i){return p([t,r,o],[n,a,e],u,i,B)},t.quadPointDistance=function(t,n,r,o,e,u,i,h){var c=this.nearestPoint(t,n,r,o,e,u,i,h);return a(c.x,c.y,i,h)}})); | ||
//# sourceMappingURL=index.umd.min.js.map |
import type { BBox, Point } from './types'; | ||
declare const _default: { | ||
/** | ||
* 计算线段的包围盒 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {object} 包围盒对象 | ||
*/ | ||
box(x1: number, y1: number, x2: number, y2: number): BBox; | ||
/** | ||
* 线段的长度 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {number} 距离 | ||
*/ | ||
length(x1: number, y1: number, x2: number, y2: number): number; | ||
/** | ||
* 根据比例获取点 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @param {number} t 指定比例 | ||
* @return {object} 包含 x, y 的点 | ||
*/ | ||
pointAt(x1: number, y1: number, x2: number, y2: number, t: number): Point; | ||
/** | ||
* 点到线段的距离 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @param {number} x 测试点 x | ||
* @param {number} y 测试点 y | ||
* @return {number} 距离 | ||
*/ | ||
pointDistance(x1: number, y1: number, x2: number, y2: number, x: number, y: number): number; | ||
/** | ||
* 点到直线的距离,而不是点到线段的距离 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @param {number} x 测试点 x | ||
* @param {number} y 测试点 y | ||
* @return {number} 距离 | ||
*/ | ||
pointToLine(x1: number, y1: number, x2: number, y2: number, x: number, y: number): number; | ||
/** | ||
* 线段的角度 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {number} 导数 | ||
*/ | ||
tangentAngle(x1: number, y1: number, x2: number, y2: number): number; | ||
}; | ||
export default _default; | ||
//# sourceMappingURL=line.d.ts.map | ||
export declare function box(x1: number, y1: number, x2: number, y2: number): BBox; | ||
export declare function length(x1: number, y1: number, x2: number, y2: number): number; | ||
export declare function pointAt(x1: number, y1: number, x2: number, y2: number, t: number): Point; | ||
export declare function pointDistance(x1: number, y1: number, x2: number, y2: number, x: number, y: number): number; | ||
export declare function pointToLine(x1: number, y1: number, x2: number, y2: number, x: number, y: number): number; | ||
export declare function tangentAngle(x1: number, y1: number, x2: number, y2: number): number; |
import type { PointTuple } from './types'; | ||
declare const _default: { | ||
/** | ||
* 计算多边形的包围盒 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 包围盒 | ||
*/ | ||
box(points: PointTuple[]): import("./types").BBox; | ||
/** | ||
* 计算多边形的长度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 多边形边的长度 | ||
*/ | ||
length(points: PointTuple[]): number; | ||
/** | ||
* 根据比例获取多边形的点 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多边形的长度上的比例 | ||
* @return {object} 根据比例值计算出来的点 | ||
*/ | ||
pointAt(points: PointTuple[], t: number): import("./types").Point; | ||
/** | ||
* 指定点到多边形的距离 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} x 指定点的 x | ||
* @param {number} y 指定点的 y | ||
* @return {number} 点到多边形的距离 | ||
*/ | ||
pointDistance(points: PointTuple[], x: number, y: number): number; | ||
/** | ||
* 根据比例获取多边形的切线角度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多边形的长度上的比例 | ||
* @return {object} 根据比例值计算出来的角度 | ||
*/ | ||
tangentAngle(points: PointTuple[], t: number): number; | ||
}; | ||
export default _default; | ||
//# sourceMappingURL=polygon.d.ts.map | ||
export declare function box(points: PointTuple[]): import("./types").BBox; | ||
export declare function length(points: PointTuple[]): number; | ||
export declare function pointAt(points: PointTuple[], t: number): import("./types").Point; | ||
export declare function pointDistance(points: PointTuple[], x: number, y: number): number; | ||
export declare function tangentAngle(points: PointTuple[], t: number): number; |
@@ -1,39 +0,6 @@ | ||
import type { PointTuple, BBox } from './types'; | ||
declare const _default: { | ||
/** | ||
* 计算多折线的包围盒 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 包围盒 | ||
*/ | ||
box(points: PointTuple[]): BBox; | ||
/** | ||
* 计算多折线的长度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @return {object} 多条边的长度 | ||
*/ | ||
length(points: PointTuple[]): number; | ||
/** | ||
* 根据比例获取多折线的点 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多折线的长度上的比例 | ||
* @return {object} 根据比例值计算出来的点 | ||
*/ | ||
pointAt(points: PointTuple[], t: number): import("./types").Point; | ||
/** | ||
* 指定点到多折线的距离 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} x 指定点的 x | ||
* @param {number} y 指定点的 y | ||
* @return {number} 点到多折线的距离 | ||
*/ | ||
pointDistance(points: PointTuple[], x: number, y: number): number; | ||
/** | ||
* 根据比例获取多折线的切线角度 | ||
* @param {array} points 点的集合 [x,y] 的形式 | ||
* @param {number} t 在多折线的长度上的比例 | ||
* @return {object} 根据比例值计算出来的角度 | ||
*/ | ||
tangentAngle(points: PointTuple[], t: number): number; | ||
}; | ||
export default _default; | ||
//# sourceMappingURL=polyline.d.ts.map | ||
import type { BBox, PointTuple } from './types'; | ||
export declare function box(points: PointTuple[]): BBox; | ||
export declare function length(points: PointTuple[]): number; | ||
export declare function pointAt(points: PointTuple[], t: number): import("./types").Point; | ||
export declare function pointDistance(points: PointTuple[], x: number, y: number): number; | ||
export declare function tangentAngle(points: PointTuple[], t: number): number; |
import type { Point } from './types'; | ||
declare function quadraticAt(p0: number, p1: number, p2: number, t: number): number; | ||
declare const _default: { | ||
box(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): import("./types").BBox; | ||
length(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): number; | ||
nearestPoint(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x0: number, y0: number): Point; | ||
pointDistance(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x0: number, y0: number): number; | ||
interpolationAt: typeof quadraticAt; | ||
pointAt(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, t: number): Point; | ||
divide(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, t: number): number[][]; | ||
tangentAngle(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, t: number): number; | ||
}; | ||
export default _default; | ||
//# sourceMappingURL=quadratic.d.ts.map | ||
export declare function box(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): import("./types").BBox; | ||
export declare function length(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): number; | ||
export declare function nearestPoint(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x0: number, y0: number): Point; | ||
export declare function pointDistance(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x0: number, y0: number): number; | ||
export declare function pointAt(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, t: number): Point; | ||
export declare function divide(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, t: number): number[][]; | ||
export declare function tangentAngle(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, t: number): number; |
@@ -17,2 +17,1 @@ import type { Point, PointTuple } from './types'; | ||
export declare function distanceAtSegment(points: PointTuple[], x: number, y: number): number; | ||
//# sourceMappingURL=segments.d.ts.map |
@@ -29,2 +29,1 @@ /** | ||
}; | ||
//# sourceMappingURL=types.d.ts.map |
import type { BBox } from './types'; | ||
/** | ||
* 两点之间的距离 | ||
* @param {number} x1 起始点 x | ||
* @param {number} y1 起始点 y | ||
* @param {number} x2 结束点 x | ||
* @param {number} y2 结束点 y | ||
* @return {number} 距离 | ||
*/ | ||
export declare function distance(x1: number, y1: number, x2: number, y2: number): number; | ||
@@ -20,2 +12,1 @@ export declare function isNumberEqual(v1: number, v2: number): boolean; | ||
export declare function piMod(angle: number): number; | ||
//# sourceMappingURL=util.d.ts.map |
{ | ||
"name": "@antv/g-math", | ||
"version": "1.7.49", | ||
"version": "1.8.0-alpha.1", | ||
"description": "Geometry util", | ||
@@ -19,2 +19,7 @@ "keywords": [ | ||
"author": "https://github.com/orgs/antvis/people", | ||
"exports": { | ||
"types": "./dist/index.d.ts", | ||
"import": "./dist/index.esm.js", | ||
"default": "./dist/index.js" | ||
}, | ||
"main": "dist/index.js", | ||
@@ -30,16 +35,15 @@ "unpkg": "dist/index.umd.min.js", | ||
], | ||
"scripts": { | ||
"sync": "tnpm sync" | ||
}, | ||
"dependencies": { | ||
"gl-matrix": "^3.1.0", | ||
"tslib": "^2.3.1" | ||
"tslib": "^2.5.3" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^25.0.0" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"gitHead": "53932c66ed9f2cbc28993e1e359c8df27703fc52" | ||
} | ||
"scripts": { | ||
"build": "npm run clean && rollup -c", | ||
"clean": "rimraf dist", | ||
"sync": "tnpm sync", | ||
"watch": "rollup -c -w" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
180982
0
21
1539
1
1
Updatedtslib@^2.5.3