简体   繁体   中英

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. 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)

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

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

 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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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