C/Objective-C/Swift 的 atan2() 的快速粗略版本?

Fast, crude version of atan2() for C/Objective-C/Swift?

我正在编写一些图形代码,用于实时绘制平滑、连续的曲线。我想添加对羽毛笔刷的支持。为此,我需要能够计算构成曲线的线段的“法线”或垂直线。

这样做的纯数学方法是使用 arctan 找到线段的角度,旋转 90 度,然后使用正弦和余弦找到我的法线的 x 和 y 偏移量。一旦我有了自己的角度,使用查找 table 来替换正弦和余弦将非常容易,但是编写 atan2() 的高性能、低精度版本似乎很棘手。

我的法线(垂直线)的长度和角度不需要精确。差十分之一也没关系。

你们中有人为这种图形工作开发了 atan2() 的高速粗略版本吗?为性能优化这类事情既繁琐又耗时。

我在 Swift 3 工作,但我是“多语种”。我也可以集成用 C/Objective-C 编写的代码。 (或者可能将其转换为 Swift。)

编辑:

更多详情:

该项目涉及徒手画,它提供了一系列点,如果用户快速拖动手指,这些点有时会相距很远,并使用 Catmull-Rom splines 添加中间点以创建一系列线段足够小,它们看起来像一条平滑的曲线。

(Catmull-Rom splines 是一条类似于著名的 Bezier 曲线的曲线,但是曲线的所有控制点都在曲线上,因此用户“徒手”输入的曲线很容易平滑使用输入顶点进行平滑。)

(从现在开始我会提到“曲线”,但我真正的意思是由线段组成的多段线,这些线段很短,看起来像是平滑的曲线)

我已经分解了我的代码,以便我只为发生变化的曲线部分生成样条曲线。它现在非常快,并且可以像您绘制的那样快地创建精美平滑的曲线。主观上,我似乎在画一条曲线,一点一点地跟随你的手指轨迹,点与点之间没有跳跃。

下一个目标是能够用柔边画笔作画。为此,我想在用户手指轨迹的左右两侧找到与曲线平行的曲线。然后,我将使用 OpenGL 创建三角形条带,定义左右线条之间的粗曲线,并使用多边形阴影将曲线从沿着用户手指轨迹曲线的不透明羽化为沿着左右平行曲线的透明。

假设我想绘制一条 6 磅厚的软边曲线。在左侧和右侧跟随用户手指轨迹的曲线各需要从用户曲线延伸 3 个点。

我打算通过找到垂直于用户手指轨迹线段并穿过手指轨迹顶点的线段来找到左右曲线的端点顶点,并向用户手指轨迹的左侧和右侧延伸所需线宽的 1/2。

下面是当前版本程序绘制的曲线截图,输入顶点绘制为蓝色菱形,我添加的平滑点绘制为空心正方形。 (我减少了添加的平滑点的数量,以便您可以更好地了解发生了什么。)

想象一下,通过每个顶点绘制一系列“散列标记”,每 6 个点长,以其中一个顶点为中心,并垂直于直线的第一个线段,该直线段结束于那个顶点。

正如 Peter O. 在他的回答中指出的那样,找到垂直于任何特定线段的线段很容易 - 您只需反转斜率即可。但是,我想要特定长度的线段。 (在我的示例中,6 个点,顶点两侧各 3 个点。)我正在寻找实现此目的的方法 fast。我可以使用三角函数或平方根计算法线的终点,这两种方法都非常慢。

对于你的问题,如果你只想找到一条垂直于另一条线的线,你甚至不需要使用atan2;您可以改用以下方法。令 (x1, y1) 和 (x2, y2) 为输入线段。

// Find deltas
dx=x2-x1
dy=y2-y1
// Find perpendicular vector to (dx, dy)
 pdx=-dy
 pdy=dx
 // Normalize the vector to a unit vector
 length=sqrt(pdx*pdx+pdy*pdy)
 if(length!=0){
    invlength=1.0/length
// Scale the vector as desired
    invlength*=scale
    pdx*=invlength
   pdy*=invlength
 }
 // Now, find a line segment parallel to the vector
 x2=x1+pdx
 y2=y1+pdy

或者,如果您坚持 atan2,我知道在 http://www.dspguru.com/dsp/tricks/fixed-point-atan2-with-self-normalization 有一个 public 域实现。尝试这两种方法,看看哪种方法更适合您的目的。

一般来说,如果您发现自己调用 atan2(dy,dx) 只是为了获得 cossin 的正确角度,您通常可以只使用归一化的 x 和 y 分量(dx, dy) 分别取余弦和正弦向量。