簡體   English   中英

計算二次貝塞爾曲線的交點

[英]calculating intersection point of quadratic bezier curve

這絕對是我的三角知識的極限。

是否有計算二次貝塞爾曲線和直線交點的公式?

例子:

在下圖中,我有 P1、P2、C(這是控制點)和 X1、X2(對於我的特定計算,它只是 X 軸上的一條直線。)

我想知道的是 T 的 X、Y 位置以及 T 處的切線角度。在紅色曲線和黑色線之間的交點處。

曲線示例

在做了一些研究並找到這個問題之后,我知道我可以使用:

t = 0.5; // given example value
x = (1 - t) * (1 - t) * p[0].x + 2 * (1 - t) * t * p[1].x + t * t * p[2].x;
y = (1 - t) * (1 - t) * p[0].y + 2 * (1 - t) * t * p[1].y + t * t * p[2].y;

計算我在曲線上任何給定點的 X、Y 位置。 所以使用它,我可以沿着曲線循環遍歷一堆點,檢查是否有任何點在我的相交 X 軸上。 從那里嘗試計算我的切線角。 但這似乎真的不是最好的方法。 任何數學大師都知道最好的方法是什么?

我在想,也許它比我想要的要復雜一些。

在此處輸入圖片說明

二次曲線公式:

y=ax^2+bx+c // where a,b,c are known

線公式:

// note: this `B` is not the same as the `b` in the quadratic formula ;-)

y=m*x+B  // where m,B are known.

曲線和直線相交,其中兩個方程對於相同的 [x,y] 成立:

這是帶注釋的代碼和演示:

 // canvas vars var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); var cw=canvas.width; var ch=canvas.height; // linear interpolation utility var lerp=function(a,b,x){ return(a+x*(ba)); }; // qCurve & line defs var p1={x:125,y:200}; var p2={x:250,y:225}; var p3={x:275,y:100}; var a1={x:30,y:125}; var a2={x:300,y:175}; // calc the intersections var points=calcQLintersects(p1,p2,p3,a1,a2); // plot the curve, line & solution(s) var textPoints='Intersections: '; ctx.beginPath(); ctx.moveTo(p1.x,p1.y); ctx.quadraticCurveTo(p2.x,p2.y,p3.x,p3.y); ctx.moveTo(a1.x,a1.y); ctx.lineTo(a2.x,a2.y); ctx.stroke(); ctx.beginPath(); for(var i=0;i<points.length;i++){ var p=points[i]; ctx.moveTo(px,py); ctx.arc(px,py,4,0,Math.PI*2); ctx.closePath(); textPoints+=' ['+parseInt(px)+','+parseInt(py)+']'; } ctx.font='14px verdana'; ctx.fillText(textPoints,10,20); ctx.fillStyle='red'; ctx.fill(); /////////////////////////////////////////////////// function calcQLintersects(p1, p2, p3, a1, a2) { var intersections=[]; // inverse line normal var normal={ x: a1.y-a2.y, y: a2.x-a1.x, } // Q-coefficients var c2={ x: p1.x + p2.x*-2 + p3.x, y: p1.y + p2.y*-2 + p3.y } var c1={ x: p1.x*-2 + p2.x*2, y: p1.y*-2 + p2.y*2, } var c0={ x: p1.x, y: p1.y } // Transform to line var coefficient=a1.x*a2.y-a2.x*a1.y; var a=normal.x*c2.x + normal.y*c2.y; var b=(normal.x*c1.x + normal.y*c1.y)/a; var c=(normal.x*c0.x + normal.y*c0.y + coefficient)/a; // solve the roots var roots=[]; d=b*b-4*c; if(d>0){ var e=Math.sqrt(d); roots.push((-b+Math.sqrt(d))/2); roots.push((-b-Math.sqrt(d))/2); }else if(d==0){ roots.push(-b/2); } // calc the solution points for(var i=0;i<roots.length;i++){ var minX=Math.min(a1.x,a2.x); var minY=Math.min(a1.y,a2.y); var maxX=Math.max(a1.x,a2.x); var maxY=Math.max(a1.y,a2.y); var t = roots[i]; if (t>=0 && t<=1) { // possible point -- pending bounds check var point={ x:lerp(lerp(p1.x,p2.x,t),lerp(p2.x,p3.x,t),t), y:lerp(lerp(p1.y,p2.y,t),lerp(p2.y,p3.y,t),t) } var x=point.x; var y=point.y; // bounds checks if(a1.x==a2.x && y>=minY && y<=maxY){ // vertical line intersections.push(point); }else if(a1.y==a2.y && x>=minX && x<=maxX){ // horizontal line intersections.push(point); }else if(x>=minX && y>=minY && x<=maxX && y<=maxY){ // line passed bounds check intersections.push(point); } } } return intersections; }
 body{ background-color: ivory; padding:10px; } #canvas{border:1px solid red;}
 <h4>Calculate intersections of QBez-Curve and Line</h4> <canvas id="canvas" width=350 height=350></canvas>

如果您只需要在 x 方向上與直線相交,您就已經知道相交的 y 坐標。 要獲得 x 坐標,請執行以下操作:

  • 你的線的方程只是y = b
  • 將它設置為與貝塞爾函數y(t) y 方程相等可以得到:
    b = (1 - t) * (1 - t) * p[0].y + 2 * (1 - t) * t * p[1].y + t * t * p[2].y
  • 為 t 求解 * 可以得到:
    t = (p[0].y - p[1].y - sqrt(b*a + p[1].y*p[1].y - p[0].y*p[2].y)) / a
    a = p[0].y - 2*p[1].y + p[2].y
  • 將得到的 t 插入到貝塞爾函數x(t) x 方程中以獲得 x 坐標,然后就完成了。

您可能需要注意一些特殊情況,例如不存在解時,因為平方根的參數可能會變為負數,或者分母 ( a ) 可能會變為零,或者類似的情況。

如果您需要更多幫助或與任意線條的交集,請發表評論。

(*) 我使用 wolfram alpha 來求解方程,因為我很懶: Wolfram alpha solution

用 x 坐標計算線的 tangθ

那么曲線的 (x, y) 的交點應該是相同的 tangθ

所以解決方案是

a = 從 (line.x,0) 到 (0,0) 的線的 x 距離

(curve.x + a) / curve.y = tangθ(θ可以從與x坐標的線交點得到)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM