繁体   English   中英

如何设置贝塞尔曲线的控制点来弯曲一条线?

[英]How to set control points of a bezier curve to bend a line?

我想用贝塞尔曲线画一条稍微弯曲的线。

这是贝塞尔曲线函数:

function bezierCurve(controlPoint1, controlPoint2, line) { }

我不知道如何设置控制点以实现任何线条的略微弯曲的线条。

我试图找到这条线的垂直点:

function Line(a, b) {

  let mid = [(a[0] + b[0]) / 2,
             (a[1] + b[1]) / 2];

  let dX = b[0] - a[0],
      dY = b[1] - a[1];

  this.perpPoint = (y) => {
    let x1 = mid[0],
        y1 = mid[1],
        x;

    if (dX === 0 || dY === 0) {
      x = y;
      y = y1;

      return [x, y];
    }

    let m = dX / dY;

    let perpendicularM = - 1 / m;

    // y - y1 = m(x - x1)
    // x = (y - y1) / m + x1

    x = (y - y1) / m + x1;

    return [x, y];
  };

并以某种方式使用它来找到线中点正上方的点作为控制点,但没有用。

功能

function bezierCurve(controlPoint1, controlPoint2, line) { }

建议曲线是三次贝塞尔曲线(两个控制点),您给出的函数看起来像是只在中间找到一个点并偏移一些固定量。 您将需要更多地控制点与线的关系。

与线的垂直偏移。

下面的函数会给你更多的控制,让你指定你想要点的沿着线的位置以及该点应该离线多远。

参数alongdist是一条线的分数,例如along = 0.5是一半,而dist = 0.2是线长度的 1/5。 dist > 0并且该点偏移到线dist < 0的右侧并且偏移量向左(Y 轴向下)

function pointFromLine(along, dist, p1, p2, res = {}) {
    const dx = p2.x - p1.x;
    const dy = p2.y - p1.y;
    res.x = p1.x + dx * along - dy * dist;
    res.y = p1.y + dy * along + dx * dist;
    return res;
}   

找到距离中心线长 1/5 的中点

const p1 = {x: 10, y: 10};
const p2 = {x: 510, y: 310};
const offset = pointFromLine(0.5, 0.2, p1, p2);

为三次贝塞尔曲线找到两个控制点。

const p1 = {x: 10, y: 10};
const p2 = {x: 510, y: 310};
const cp1 = pointFromLine(0.333, 0.2, p1, p2);     // 1/3rd dist from start
const cp2 = pointFromLine(1 - 0.333, 0.2, p1, p2); // equal dist (1/3rd) from end of line



 

使用示例

以下代码段显示了用于为三次贝塞尔曲线创建对称曲线的函数。 移动滑块以控制沿线的 dist 和与线的 dist 偏移

 function pointFromLine(along, dist, p1, p2, res = {}) { const dx = p2.x - p1.x; const dy = p2.y - p1.y; res.x = p1.x + dx * along - dy * dist; res.y = p1.y + dy * along + dx * dist; return res; } const p1 = {x: 40, y: 40}; const p2 = {x: 160, y: 160}; const cp1 ={x: 0, y: 0}; const cp2 ={x: 0, y: 0}; const ctx = canvas.getContext("2d"); update(); function drawPoint(p) { ctx.beginPath(); ctx.arc(px, py, 4, 0, Math.PI * 2); ctx.fill(); } function drawLine(p1, p2) { ctx.lineWidth = 1; ctx.beginPath(); ctx.lineTo(p1.x, p1.y); ctx.lineTo(p2.x, p2.y); ctx.stroke(); } function drawCubicBezier(p1, p2, cp1, cp2) { ctx.lineWidth = 3; ctx.beginPath(); ctx.lineTo(p1.x, p1.y); ctx.bezierCurveTo(cp1.x, cp1.y, cp2.x, cp2.y, p2.x, p2.y); ctx.stroke(); drawLine(p1,cp1); drawLine(p2,cp2); drawPoint(p1); drawPoint(p2); drawPoint(cp1); drawPoint(cp2); } alongIn.addEventListener("input", update); distIn.addEventListener("input", update); function update() { const a = alongIn.value * 1; const d = distIn.value * 1; info.textContent = `Along: ${a.toFixed(2)} Offset: ${d.toFixed(2)}` ctx.clearRect(0,0,200,200); drawCubicBezier( p1, p2, pointFromLine(a , d, p1, p2, cp1), pointFromLine(1 - a, d, p1, p2, cp2) ); }
 canvas { border: 1px solid black; }
 Dist along: <input id="alongIn" type="range" min="-1" max="2" step="0.01" value="0.3"/> Dist out: <input id="distIn" type="range" min="-1" max="2" step="0.01" value="0.3"/> <div id="info"> </div> <canvas id="canvas" width="200" height="200" ></canvas>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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