简体   繁体   English

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

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

I want to draw a slightly bent line using bezier curve.我想用贝塞尔曲线画一条稍微弯曲的线。

This is the bezier curve function:这是贝塞尔曲线函数:

function bezierCurve(controlPoint1, controlPoint2, line) { }

I don't know how to set control points to achieve a slightly bent line for any line.我不知道如何设置控制点以实现任何线条的略微弯曲的线条。

I tried to find the perpendicular point of this 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];
  };

And use that somehow to find the points just above the midpoint of the line as control points, but didn't work.并以某种方式使用它来找到线中点正上方的点作为控制点,但没有用。

The function功能

function bezierCurve(controlPoint1, controlPoint2, line) { }

Suggest that the curve is a cubic bezier (two control points) the function you give looks like its only finding a point mid way and offset some fixed amount.建议曲线是三次贝塞尔曲线(两个控制点),您给出的函数看起来像是只在中间找到一个点并偏移一些固定量。 you will need more control over where the point is in relationship to the line.您将需要更多地控制点与线的关系。

Perpendicular offset from line.与线的垂直偏移。

The following function will give you a little more control letting you specifty where along the line you want the point and how far that point should be from the line.下面的函数会给你更多的控制,让你指定你想要点的沿着线的位置以及该点应该离线多远。

The argument along and dist are fractions of a line such the along = 0.5 is halfway and dist = 0.2 is 1/5th the length of the line away.参数alongdist是一条线的分数,例如along = 0.5是一半,而dist = 0.2是线长度的 1/5。 dist > 0 and the point is offset to the right of the line dist < 0 and the offset is to the left (Y axis pointing down) 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;
}   

To find the mid point 1/5th the line length away from the center找到距离中心线长 1/5 的中点

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

To find two control point for a cubic bezier.为三次贝塞尔曲线找到两个控制点。

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



 

Usage example使用示例

The following snippet show the function used to create a symmetrical curve for a cubic bezier.以下代码段显示了用于为三次贝塞尔曲线创建对称曲线的函数。 Move the slider to control the dist along the line and the dist offset from the 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