I have a bezier curve and a line which intersects with the bezier curve (the one in the top left).
I am able to find the points at which the line intersects with the curve. I would like to find the tangent of the bezier curve at both of those point. I have a function which finds the tangent at a point t on the curve, though this t is a value between 0 and 1, rather than a coordinate. It looks like this:
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 };
}
How do I find the tangent for a point with x and y coordinates rather than a value for t?
The formula for a point on a bezier is curve looks like this:
Can I simply rearrange this equation for t, and then use that value in my function above?
There seems like there would be a better way of achieving this, rather than converting backwards and forwards between the value t and some point.
Just search curve-line intersection in terms of t
.
Having parametric equation of line (through points L0, L1
)
L(u) = L0 + (L1-L0)*u = L0 + DL*u
we can write equation system
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
Express u
from the first equation, substitute it in the second one,
u = (P0x*(1-t)^2+2*(1-t)*t*P1x+t^2*P2x - L0x)/Dlx
substitute it in the second one,
(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
solve resulting quadratic eqiation, get t1
and t2
solutions (if they do exist and lie in 0..1 range)
You could expand and solve the polynomials, but I believe there is a computationally simpler solution. Let P 0 =(a 1 ,a 2 ), P 1 =(b 1 ,b 2 ), P 2 =(c 1 ,c 2 ). Let (x,y) be the point where you want to find the tangent.
First I want to move coordinates so that P 1 is the origin: let x=x'+b 1 , y=y'+b 2 . Now in the (x',y') coordinates the curve is given by
B(t) = (1-t) 2 P 0 + t 2 P 2
After that the coordinates of P 0 and P 2 will be recalculated, I will use prime signs for them as well.
Then I want to rotate and scale the coodinate system in such a way that P 0 and P 2 move to points (0,1) and (1,0). This can be done by inverting the following matrix:
Note that this always has an inverse if points P 0 , P 1 , P 2 don't lie on one line and it looks like this:
So the new coordinates (x'',y'') are given by (x',y')=A(x'',y''). In this coordinate system the curve is given by
B(t) = (1-t) 2 e 1 + t 2 e 2
Where e 1 =(1,0) and e 2 =(0,1). This simplifies to
x''(t) = (1-t) 2
y''(t) = t 2
If you know y'', it is trivial to find t=sqrt(y''). Note that the square root always exists (if you started with a point that lies on the bezier curve) since we changed coordinates in such a way that the curve lies where x>0 and y>0. And it is quite easy to find (x'',y'') knowing (x,y) from the formula (x'',y'')=(x+c 1 , y+c 2 )B. This is what it looks like
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)
}
Or shorter
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))
)
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.