繁体   English   中英

如何在贝塞尔曲线上找到中间标记?

[英]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% 标记似乎离左边太远了:

在此处输入图片说明

我知道有一条曲线,但中间标记仍然离左边太远。 也就是说,如果你问一群人,这条曲线的中间标记在哪里,我相信他们都会说向右更远。

这可能是一个长镜头,但是否有另一个公式可以计算更“接近现实世界”的贝塞尔曲线上的点?

编辑:我只是想到了另一种更具体地阐明这种现象的方法。 您会注意到,如果将cpXcpY变量值设置为任意数字,然后运行模拟,方形标记会沿着曲线的不同部分以不同的速度移动。 也就是说,它可能在开始时快速移动,然后减速,然后再次加速到曲线的末端。

我正在寻找的是一个公式,这样方形标记会沿着整个曲线以恒定的速度运行,并且不会在此过程中加速或减速。 这可能吗?

我最终根据 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM