繁体   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