求三次贝塞尔曲线上一点的正切
对于三次贝塞尔曲线,通常有四个点 a、b、c 和 d,
对于给定值 t,
如何最优雅地找到该点的切线?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
对于三次贝塞尔曲线,通常有四个点 a、b、c 和 d,
对于给定值 t,
如何最优雅地找到该点的切线?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(5)
曲线的正切就是它的导数。米哈尔使用的参数方程:
应该有一个导数
,顺便说一句,在你之前的问题中似乎是错误的。我相信您使用的是二次贝塞尔曲线的斜率,而不是三次贝塞尔曲线。
从这里开始,实现执行此计算的 C 函数应该很简单,就像 Michal 已经为曲线本身提供的那样。
The tangent of a curve is simply its derivative. The parametric equation that Michal uses:
should have a derivative of
Which, by the way, appears to be wrong in your earlier question. I believe you're using the slope for a quadratic Bezier curve there, not cubic.
From there, it should be trivial to implement a C function that performs this calculation, like Michal has already provided for the curve itself.
下面是经过充分测试的复制和粘贴代码:
它沿曲线绘制近似点,并且绘制切线。
bezierInterpolation
查找点bezierTangent
查找切线下面提供了
bezierInterpolation
的两个版本:bezierInterpolation< /code> 工作完美。
altBezierInterpolation
完全相同,但它是以扩展、清晰、解释性的方式编写的。它使算术更容易理解。使用这两个例程中的任何一个:结果是相同的。
在这两种情况下,都使用
bezierTangent
来查找切线。 (注意:Michal 的精彩代码库此处。)如何使用
drawRect:
的完整示例也包括在内。以下是沿贝塞尔曲线计算近似等距点及其切线的两个例程。
为了清晰和可靠,这些例程以尽可能最简单、最具解释性的方式编写。
四个预先计算的值 C1 C2 C3 C4 有时称为贝塞尔曲线的系数。 (回想一下,abcd 通常称为四个控制点。)
当然,t 从 0 到 1,例如每 0.05。
只需为 X 调用一次这些例程,然后为 Y 分别调用一次。
希望它对某人有所帮助!
重要事实:
(1) 这是一个绝对事实:不幸的是,Apple 绝对没有提供从 UIBezierPath 中提取点的方法。截至 2019 年,确实如此。
(2) 不要忘记,沿着 UIBezierPath 为某些内容设置动画非常简单。谷歌很多例子。
(3) 许多人问,“CGPathApply 不能用于从 UIBezierPath 中提取点吗?” 不,CGPathApply 完全不相关:它只是为您提供了一个列表你的“制作任何路径的说明”(因此,“从这里开始”,“画一条直线到这一点”等等)这个名字很令人困惑,但 CGPathApply 与贝塞尔路径完全无关。
对于游戏程序员 - 正如@Engineer指出的那样,您可能很需要切线的法线,幸运的是Apple有内置的向量数学:
https://developer.apple.com/documentation/accelerate/simd/working_with_vectors
https://developer.apple.com/documentation/simd/2896658-simd_normalize
Here is fully tested code to copy and paste:
It draws approxidistant points along the curve, and it draws the tangents.
bezierInterpolation
finds the pointsbezierTangent
finds the tangentsThere are TWO VERSIONS of
bezierInterpolation
supplied below:bezierInterpolation
works perfectly.altBezierInterpolation
is exactly the same, BUT it is written in an expanded, clear, explanatory manner. It makes the arithmetic much easier to understand.Use either of those two routines: the results are identical.
In both cases, use
bezierTangent
to find the tangents. (Note: Michal's fabulous code base here.)A full example of how to use with
drawRect:
is also included.Here are the two routines to calculate approximately equidistant points, and the tangents of those, along a bezier cubic.
For clarity and reliability, these routines are written in the simplest, most explanatory, way possible.
The four precalculated values, C1 C2 C3 C4, are sometimes called the coefficients of the bezier. (Recall that a b c d are usually called the four control points.)
Of course, t runs from 0 to 1, for example every 0.05.
Simply call these routines once for X, and then once separately for Y.
Hope it helps someone!
Important facts:
(1) It is an absolute fact that: unfortunately, there is, definitely, NO method, provided by Apple, to extract points from a UIBezierPath. True as of 2019.
(2) Don't forget it's as easy as pie to animate something along a UIBezierPath. Google many examples.
(3) Many ask, "Can't CGPathApply be used to extract the points from a UIBezierPath?" No, CGPathApply is totally unrelated: it simply gives you a list of your "instructions in making any path" (so, "start here", "draw a straight line to this point", etc etc.) The name is confusing but CGPathApply is totally unrelated to bezier paths.
For game programmers - as @Engineer points out you may well want the normal of the tangent, fortunately Apple has vector math built-in:
https://developer.apple.com/documentation/accelerate/simd/working_with_vectors
https://developer.apple.com/documentation/simd/2896658-simd_normalize
我发现使用提供的方程太容易出错。太容易错过细微的 t 或放错位置的括号。
相比之下,维基百科提供了一个更清晰、更干净、更衍生的恕我直言:
...在代码中轻松实现为:(
假设您有用您选择的语言配置的向量减号;问题没有专门标记为 ObjC,iOS 现在有几种可用的语言)
I found it too error-prone to use the supplied equations. Too easy to miss a subtle t or misplaced bracket.
By contrast, Wikipedia provides a much clearer, cleaner, derivative IMHO:
...which implements easily in code as:
(assuming you have vector-minus configured in your language of choice; question isn't marked as ObjC specifically, and iOS now has several langs available)
这是我的 Swift 实现。
我尽力通过消除所有冗余数学运算来优化速度。即对数学运算的调用次数最少。并使用尽可能少的乘法(这比求和要昂贵得多)。
创建贝塞尔曲线需要 0 次乘法。
然后进行 3 次乘法得到贝塞尔曲线点。
并进行 2 次乘法以获得贝塞尔曲线的切线。
使用如下:
Here goes my Swift implementation.
Which I tried my best to optimize for speed, by eliminating all redundant math operations. i.e. make the minimal numbers of calls to math operations. And use the least possible number of multiplications (which are much more expensive than sums).
There are 0 multiplications to create the bezier.
Then 3 multiplications to get a point of bezier.
And 2 multiplications to get a tangent to the bezier.
Use like:
在我意识到对于参数方程,(dy/dt)/(dx/dt) = dy/dx 之前,我无法让这些起作用。
I couldn't get any of this to work until I realized that for parametric equations, (dy/dt)/(dx/dt) = dy/dx