簡體   English   中英

給定 x 和 y 坐標點而不是 0 < t < 1 的貝塞爾曲線的切線

[英]Tangent of bezier curve given a point with x and y coords rather than 0 < t < 1

我有一條貝塞爾曲線和一條與貝塞爾曲線相交的線(左上角的那條)。

在此處輸入圖像描述

我能夠找到直線與曲線相交的點。 我想在這兩個點找到貝塞爾曲線的切線。 我有一個 function,它在曲線上的點 t 處找到切線,盡管這個 t 是介於 0 和 1 之間的值,而不是坐標。 它看起來像這樣:

let bezierCurveTangent = function(start: Point, end: Point, controlPoint: Point, t: number): Point {

    let x = 2 * (1 - t) * (controlPoint.x - start.x) + 2 * t * (end.x - controlPoint.x);

    let y = 2 * (1 - t) * (controlPoint.y - start.y) + 2 * t * (end.y - controlPoint.y);

    return { x, y };
}

如何找到具有 x 和 y 坐標而不是 t 值的點的切線?

貝塞爾曲線上的一個點的公式如下所示:

在此處輸入圖像描述

我可以簡單地重新排列 t 的這個等式,然后在上面的 function 中使用該值嗎?

似乎有更好的方法來實現這一點,而不是在值 t 和某個點之間來回轉換。

只需根據t搜索曲線交點。

具有線的參數方程(通過點L0, L1

L(u) = L0 + (L1-L0)*u = L0 + DL*u

我們可以寫方程組

P0x*(1-t)^2+2*(1-t)*t*P1x+t^2*P2x = L0x+u*DLx
P0y*(1-t)^2+2*(1-t)*t*P1y+t^2*P2y = L0y+u*DLy

從第一個方程中表達u ,代入第二個方程,

u = (P0x*(1-t)^2+2*(1-t)*t*P1x+t^2*P2x - L0x)/Dlx

將其替換為第二個,

(P0y*(1-t)^2+2*(1-t)*t*P1y+t^2*P2y-L0y)*Dlx=
   (P0x*(1-t)^2+2*(1-t)*t*P1x+t^2*P2x-L0x)*DLy

解決由此產生的二次方程,得到t1t2解決方案(如果它們確實存在並且位於 0..1 范圍內)

您可以擴展並求解多項式,但我相信有一個計算更簡單的解決方案。 令 P 0 =(a 1 ,a 2 ), P 1 =(b 1 ,b 2 ), P 2 =(c 1 ,c 2 )。 讓 (x,y) 成為您要找到切線的點。

  1. 首先,我想移動坐標,使 P 1成為原點:令 x=x'+b 1 , y=y'+b 2 現在在 (x',y') 坐標中,曲線由下式給出

    B(t) = (1-t) 2 P 0 + t 2 P 2

    之后會重新計算P 0和P 2的坐標,我也會對它們使用素號。

  2. 然后我想以 P 0和 P 2移動到點 (0,1) 和 (1,0) 的方式旋轉和縮放坐標系。 這可以通過反轉以下矩陣來完成:

    矩陣

    請注意,如果點 P 0 、 P 1 、 P 2不在一條線上,則它總是有一個倒數,它看起來像這樣:

    逆

    因此新坐標 (x'',y'') 由 (x',y')=A(x'',y'') 給出。 在這個坐標系中,曲線由下式給出

    B(t) = (1-t) 2 e 1 + t 2 e 2

    其中 e 1 =(1,0) 和 e 2 =(0,1)。 這簡化為

    x''(t) = (1-t) 2
    y''(t) = t 2

如果您知道 y'',則很容易找到 t=sqrt(y'')。 請注意,平方根始終存在(如果您從貝塞爾曲線上的一個點開始),因為我們以曲線位於 x>0 和 y>0 的方式更改坐標。 從公式(x'',y'')=(x+c 1 , y+c 2 )B 知道(x,y) 很容易找到(x'',y'')。 這就是它的樣子

const getT = (start: Point, end: Point, controlPoint: Point, x: number, y: number) => {
  // xp stands for x'
  const xp = x - controlPoint.x
  const yp = y - controlPoint.y
  const a1p = start.x - controlPoint.x
  const a2p = start.y - controlPoint.y
  const c1p = end.x - controlPoint.x
  const c2p = end.y - controlPoint.y

  const det = a1p * c2p - a2p * c1p

  // This variable is redundant, but I left it for clarity
  const xpp = (xp * c2p - yp * c1p) / det
  const ypp = (- xp * a2p + yp * a1p) / det

  return Math.sqrt(ypp)
}

或者更短

const getT = (start: Point, end: Point, controlPoint: Point, x: number, y: number) => Math.sqrt(
  (- (x - controlPoint.x) * (start.y - controlPoint.y) 
    + (y - controlPoint.y) * (start.x - controlPoint.x)) / 
  ((start.x - controlPoint.x) * (end.y - controlPoint.y) -
    (start.y - controlPoint.y) * (end.x - controlPoint.x))
)

暫無
暫無

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

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