我试图计算最适合椭圆的线数;给定所需的误差范围(距边界的最小距离)。
因此我的单位圈解决方案就是这样。
def f(u, v, r):
mid_uv = (u + v) * 0.5
N = normalized(mid_uv)
return N * r
重复v = f(u, v, r)
直到radius - |v| < error
。
然后简单地将2^i
(i
作为迭代次数)作为所需的段数。
这个算法可能是O(1)
,并不适用于省略号(我需要它)。
我该如何适应它? 或者更好的是,还有另一种解决方案吗?
答案 0 :(得分:3)
我无法形成一个很好的答案 - 使用省略号对圈子来说更具挑战性 - 但是这里有步骤:
首先 - 我会通过使用一点trig来收紧圆圈的算法。如果您绘制一个跨越角度angle
通过单位圆的和弦(线段),则计算从圆到弦的最大距离:
error = 1 - math.cos( angle / 2 )
(如果您使用圆,弦和弦的平分线绘制图表,则可以看到此情况。)反转此公式,您可以计算给定容许误差的角度。第一行代码给出了精确的角度;如果需要,第二行会缩小角度,使其成为整个圆的精确分数。
angle = 2 * math.acos( 1 - error )
angle = (2*math.pi) / math.ceil( (2*math.pi) / angle )
一旦你有角度,就可以很容易地计算和弦终点的单位圆周围的点数:[(1,0), (cos(angle),sin(angle)), cos(2*angle),sin(2*angle)), ... ]
。你最终会得到一个正多边形。
第二个 - 对于半径为radius
的圆,运行上述公式,调整如下:
angle = 2 * math.acos( 1 - error/radius )
angle = (2*math.pi) / math.ceil( (2*math.pi) / angle )
通过将sin和cos值乘以半径来计算和弦终点。
第三 - 对于具有最大和最小半径major
和minor
的椭圆,我会使用圆公式再次计算角度:
radius = max( major, minor )
angle = 2 * math.acos( 1 - error/radius )
angle = (2*math.pi) / math.ceil( (2*math.pi) / angle )
如果主半径在x方向而小半径在y方向,那么你可以像这样计算和弦终点:
[ (major, 0),
(major*cos(angle), minor*sin(angle)),
(major*cos(2*angle), minor*sin(2*angle)),
... ]
这并不总是为您提供椭圆的最小多边形(它将在短轴附近有更多的和弦,特别是对于非常宽的椭圆),但您只需要进行一次角度计算。如果你真的需要最小化和弦的数量,那么在绘制每个和弦之后,你需要在每个和弦之后重新计算角度,并且公式不是直接的(其中“不直接”=“难以我想弄清楚“)。
答案 1 :(得分:1)
圆圈有O(1)解:您可以计算相等段数,以获得所需的sagitta。椭圆是更难的情况。对于与较大半轴(近焦点)垂直的弦而言,最大矢量将是合理的,因此在较大半轴的末端选择段的连接点似乎是合理的(至少 - 作为第一近似值)