【问题标题】:Fast, crude version of atan2() for C/Objective-C/Swift?用于 C/Objective-C/Swift 的 atan2() 的快速粗略版本?
【发布时间】:2017-05-23 20:41:51
【问题描述】:

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

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

我的法线(垂直线)的长度和角度不需要精确。如果它减少了十分之一,那也没关系。

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

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

编辑:

更多细节:

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

(Catmull-Rom 样条曲线是一种类似于众所周知的 Bezier 曲线的曲线,但该曲线的所有控制点都位于该曲线上,因此可以直接平滑用户使用“徒手”输入的曲线输入顶点进行平滑处理。)

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

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

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

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

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

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

想象通过每个顶点绘制一系列“哈希标记”,每个 6 点长,以其中一个顶点为中心,并垂直于在该顶点处结束的平滑曲线的第一条线段.

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

【问题讨论】:

  • 我不够聪明,无法回答您的问题,但这似乎是一个非常有趣的话题。你引起了我的兴趣。
  • @AntonínLejsek,查看我的编辑。
  • 只是好奇,从 math.h 桥接到 Darwin 的 atan2 函数对您来说不够快吗?

标签: ios performance graphics normals atan2


【解决方案1】:

对于您的问题,如果您只想找到一条与另一条垂直的线,您甚至不需要使用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 的一个公共领域实现。尝试这两种方法,看看哪种方法更适合您的目的。

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

【讨论】:

  • 彼得,我知道使用斜率的倒数可以给我一条垂直于我的输入线段的线段,但我需要一个固定长度的垂直线段,其中源线段是任意的长度。
  • 要将 (dx, dy) 转换为单位向量,这就是您的想法,请找到 sqrt(dx*dx+dy*dy),然后将 (dx, dy) 除以结果。现在您有了一个垂直单位向量 (dx, dy),您可以将其重新缩放到所需的长度。
  • 或者,如果您坚持使用atan2,我知道dspguru.com/dsp/tricks/… 有一个公共域实现。尝试这两种方法,看看哪种方法更适合您的目的。
  • 彼得,明白了。但是,平方根是计算机上最慢的函数之一。我正在寻找一种性能足以计算这些单位法线并在用户绘制时“实时”绘制平滑边缘曲线的算法。您的解决方案涉及平方根(非常慢)和除法(性能不错,但比乘法和加法慢。)
  • 我开始认为基于查找表的平方根算法可能是可行的方法。 (在表格条目之间使用线性插值。)
猜你喜欢
  • 2014-08-07
  • 1970-01-01
  • 2017-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-16
  • 1970-01-01
  • 2014-09-23
相关资源
最近更新 更多