簡體   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