[英]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
解決由此產生的二次方程,得到t1
和t2
解決方案(如果它們確實存在並且位於 0..1 范圍內)
您可以擴展並求解多項式,但我相信有一個計算更簡單的解決方案。 令 P 0 =(a 1 ,a 2 ), P 1 =(b 1 ,b 2 ), P 2 =(c 1 ,c 2 )。 讓 (x,y) 成為您要找到切線的點。
首先,我想移動坐標,使 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的坐標,我也會對它們使用素號。
然后我想以 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.