[英]How to find the halfway mark on a bezier curve?
我正在尝试计算点在贝塞尔曲线上的位置,并且我正在使用标准公式进行计算。 那是:
x = (1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * cpX + t * t * x2;
y = (1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * cpY + t * t * y2;
但是,我对结果感到非常困惑。 我已经为我在下面谈论的内容开发了一个演示:
let c = document.querySelector("canvas"); let ctx = c.getContext("2d"); let x1 = 25; let y1 = 25; let cpX = 35; let cpY = 35; let x2 = 200; let y2 = 25; let f = 0; function calcX(t) { return (1 - t) * (1 - t) * x1 + 2 * (1 - t) * t * cpX + t * t * x2; } function calcY(t) { return (1 - t) * (1 - t) * y1 + 2 * (1 - t) * t * cpY + t * t * y2; } function drawCurve() { ctx.beginPath(); ctx.moveTo(x1, y1); ctx.quadraticCurveTo(cpX, cpY, x2, y2); ctx.stroke(); } function drawLoop(elapsed) { c.width = 600; c.height = 600; let x = calcX(f); let y = calcY(f); drawCurve(); ctx.beginPath(); ctx.rect(x, y, 3, 3); ctx.stroke(); f = f < 1 ? f + 0.001 : 0; document.querySelector(".debug").innerHTML = f.toFixed(2); requestAnimationFrame(drawLoop); } drawLoop(0);
.debug { position: absolute; left: 9px; top: 6px; }
<canvas></canvas> <div class="debug"></div>
如您所见,50% 标记似乎离左边太远了:
我知道有一条曲线,但中间标记仍然离左边太远。 也就是说,如果你问一群人,这条曲线的中间标记在哪里,我相信他们都会说向右更远。
这可能是一个长镜头,但是否有另一个公式可以计算更“接近现实世界”的贝塞尔曲线上的点?
编辑:我只是想到了另一种更具体地阐明这种现象的方法。 您会注意到,如果将cpX
和cpY
变量值设置为任意数字,然后运行模拟,方形标记会沿着曲线的不同部分以不同的速度移动。 也就是说,它可能在开始时快速移动,然后减速,然后再次加速到曲线的末端。
我正在寻找的是一个公式,这样方形标记会沿着整个曲线以恒定的速度运行,并且不会在此过程中加速或减速。 这可能吗?
我最终根据 Chris G 的评论创建了一个函数,该函数沿贝塞尔曲线预先计算了所有这些点。 其他人可能会发现它很有用:
function calcPoints() {
const step = 0.001;
const segments = [];
for (let i = 0; i <= 1 - step; i += step) {
let dx = this.calcX(i) - this.calcX(i + step);
let dy = this.calcY(i) - this.calcY(i + step);
segments.push(Math.sqrt(dx * dx + dy * dy));
}
const len = segments.reduce((a, c) => a + c, 0);
let result = [];
let l = 0;
let co = 0;
for (let i = 0; i < segments.length; i++) {
l += segments[i];
co += step;
result.push({ t: l / len, co });
}
return result;
}
// Example pseudo-code:
let pointCache = calcPoints();
let co = binarySearch(pointCache, 0.5).co;
let x = this.calcX(co);
let y = this.calcY(co);
我认为这有效吗? 您只需对结果数组进行二分搜索以查找您要查找的值。 如果您的曲线之后没有改变,则该函数只需要运行一次。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.