2020-07-23 11:00:46 +08:00
|
|
|
|
module es {
|
2020-12-09 17:56:48 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 三次方和二次方贝塞尔帮助器(cubic and quadratic bezier helper)
|
|
|
|
|
|
*/
|
2020-07-23 11:00:46 +08:00
|
|
|
|
export class Bezier {
|
|
|
|
|
|
/**
|
2020-12-09 17:56:48 +08:00
|
|
|
|
* 求解二次曲折线
|
2020-07-23 11:00:46 +08:00
|
|
|
|
* @param p0
|
|
|
|
|
|
* @param p1
|
|
|
|
|
|
* @param p2
|
|
|
|
|
|
* @param t
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static getPoint(p0: Vector2, p1: Vector2, p2: Vector2, t: number): Vector2 {
|
|
|
|
|
|
t = MathHelper.clamp01(t);
|
|
|
|
|
|
let oneMinusT = 1 - t;
|
|
|
|
|
|
return Vector2.add(Vector2.add(Vector2.multiply(new Vector2(oneMinusT * oneMinusT), p0),
|
|
|
|
|
|
Vector2.multiply(new Vector2(2 * oneMinusT * t), p1)), Vector2.multiply(new Vector2(t * t), p2));
|
|
|
|
|
|
}
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 得到二次贝塞尔函数的一阶导数
|
|
|
|
|
|
* @param p0
|
|
|
|
|
|
* @param p1
|
|
|
|
|
|
* @param p2
|
|
|
|
|
|
* @param t
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static getFirstDerivative(p0: Vector2, p1: Vector2, p2: Vector2, t: number) {
|
|
|
|
|
|
return Vector2.add(Vector2.multiply(new Vector2(2 * (1 - t)), Vector2.subtract(p1, p0)),
|
|
|
|
|
|
Vector2.multiply(new Vector2(2 * t), Vector2.subtract(p2, p1)));
|
|
|
|
|
|
}
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 得到一个三次贝塞尔函数的一阶导数
|
|
|
|
|
|
* @param start
|
|
|
|
|
|
* @param firstControlPoint
|
|
|
|
|
|
* @param secondControlPoint
|
|
|
|
|
|
* @param end
|
|
|
|
|
|
* @param t
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static getFirstDerivativeThree(start: Vector2, firstControlPoint: Vector2, secondControlPoint: Vector2,
|
|
|
|
|
|
end: Vector2, t: number) {
|
|
|
|
|
|
t = MathHelper.clamp01(t);
|
|
|
|
|
|
let oneMunusT = 1 - t;
|
|
|
|
|
|
return Vector2.add(Vector2.add(Vector2.multiply(new Vector2(3 * oneMunusT * oneMunusT), Vector2.subtract(firstControlPoint, start)),
|
|
|
|
|
|
Vector2.multiply(new Vector2(6 * oneMunusT * t), Vector2.subtract(secondControlPoint, firstControlPoint))),
|
|
|
|
|
|
Vector2.multiply(new Vector2(3 * t * t), Vector2.subtract(end, secondControlPoint)));
|
|
|
|
|
|
}
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 计算一个三次贝塞尔
|
|
|
|
|
|
* @param start
|
|
|
|
|
|
* @param firstControlPoint
|
|
|
|
|
|
* @param secondControlPoint
|
|
|
|
|
|
* @param end
|
|
|
|
|
|
* @param t
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static getPointThree(start: Vector2, firstControlPoint: Vector2, secondControlPoint: Vector2,
|
|
|
|
|
|
end: Vector2, t: number) {
|
|
|
|
|
|
t = MathHelper.clamp01(t);
|
|
|
|
|
|
let oneMunusT = 1 - t;
|
|
|
|
|
|
return Vector2.add(Vector2.add(Vector2.add(Vector2.multiply(new Vector2(oneMunusT * oneMunusT * oneMunusT), start),
|
|
|
|
|
|
Vector2.multiply(new Vector2(3 * oneMunusT * oneMunusT * t), firstControlPoint)),
|
|
|
|
|
|
Vector2.multiply(new Vector2(3 * oneMunusT * t * t), secondControlPoint)),
|
|
|
|
|
|
Vector2.multiply(new Vector2(t * t * t), end));
|
|
|
|
|
|
}
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 递归地细分bezier曲线,直到满足距离校正
|
|
|
|
|
|
* 在这种算法中,平面切片的点要比曲面切片少。返回完成后应返回到ListPool的合并列表。
|
|
|
|
|
|
* @param start
|
|
|
|
|
|
* @param firstCtrlPoint
|
|
|
|
|
|
* @param secondCtrlPoint
|
|
|
|
|
|
* @param end
|
|
|
|
|
|
* @param distanceTolerance
|
|
|
|
|
|
*/
|
|
|
|
|
|
public static getOptimizedDrawingPoints(start: Vector2, firstCtrlPoint: Vector2, secondCtrlPoint: Vector2,
|
|
|
|
|
|
end: Vector2, distanceTolerance: number = 1) {
|
|
|
|
|
|
let points = ListPool.obtain<Vector2>();
|
|
|
|
|
|
points.push(start);
|
|
|
|
|
|
this.recursiveGetOptimizedDrawingPoints(start, firstCtrlPoint, secondCtrlPoint, end, points, distanceTolerance);
|
|
|
|
|
|
points.push(end);
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
return points;
|
|
|
|
|
|
}
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 递归地细分bezier曲线,直到满足距离校正。在这种算法中,平面切片的点要比曲面切片少。
|
|
|
|
|
|
* @param start
|
|
|
|
|
|
* @param firstCtrlPoint
|
|
|
|
|
|
* @param secondCtrlPoint
|
|
|
|
|
|
* @param end
|
|
|
|
|
|
* @param points
|
|
|
|
|
|
* @param distanceTolerance
|
|
|
|
|
|
*/
|
|
|
|
|
|
private static recursiveGetOptimizedDrawingPoints(start: Vector2, firstCtrlPoint: Vector2, secondCtrlPoint: Vector2,
|
|
|
|
|
|
end: Vector2, points: Vector2[], distanceTolerance: number) {
|
|
|
|
|
|
// 计算线段的所有中点
|
|
|
|
|
|
let pt12 = Vector2.divide(Vector2.add(start, firstCtrlPoint), new Vector2(2));
|
|
|
|
|
|
let pt23 = Vector2.divide(Vector2.add(firstCtrlPoint, secondCtrlPoint), new Vector2(2));
|
|
|
|
|
|
let pt34 = Vector2.divide(Vector2.add(secondCtrlPoint, end), new Vector2(2));
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
// 计算新半直线的中点
|
|
|
|
|
|
let pt123 = Vector2.divide(Vector2.add(pt12, pt23), new Vector2(2));
|
|
|
|
|
|
let pt234 = Vector2.divide(Vector2.add(pt23, pt34), new Vector2(2));
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
// 最后再细分最后两个中点。如果我们满足我们的距离公差,这将是我们使用的最后一点。
|
|
|
|
|
|
let pt1234 = Vector2.divide(Vector2.add(pt123, pt234), new Vector2(2));
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
// 试着用一条直线来近似整个三次曲线
|
|
|
|
|
|
let deltaLine = Vector2.subtract(end, start);
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
let d2 = Math.abs(((firstCtrlPoint.x, end.x) * deltaLine.y - (firstCtrlPoint.y - end.y) * deltaLine.x));
|
|
|
|
|
|
let d3 = Math.abs(((secondCtrlPoint.x - end.x) * deltaLine.y - (secondCtrlPoint.y - end.y) * deltaLine.x));
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
if ((d2 + d3) * (d2 + d3) < distanceTolerance * (deltaLine.x * deltaLine.x + deltaLine.y * deltaLine.y)) {
|
|
|
|
|
|
points.push(pt1234);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2020-07-17 11:07:57 +08:00
|
|
|
|
|
2020-07-23 11:00:46 +08:00
|
|
|
|
// 继续细分
|
|
|
|
|
|
this.recursiveGetOptimizedDrawingPoints(start, pt12, pt123, pt1234, points, distanceTolerance);
|
|
|
|
|
|
this.recursiveGetOptimizedDrawingPoints(pt1234, pt234, pt34, end, points, distanceTolerance);
|
|
|
|
|
|
}
|
2020-07-17 11:07:57 +08:00
|
|
|
|
}
|
2020-07-23 11:00:46 +08:00
|
|
|
|
}
|