这是一个常见的访谈问题(根据一些访谈网站)但我在互联网上找不到正常的答案 - 有些是错的,有些人指的是复杂的理论我期望在访谈中不需要(比如Bressenham算法)。 / p>
问题很简单:
圆方程为:x ^ 2 + y ^ 2 = R ^ 2。 给定R,尽可能最好地绘制0,0居中的圆而不使用任何 浮点(没有三角形,平方根等,只有整数)
答案 0 :(得分:8)
类似Bresenham的算法可能是预期的答案,并且可以在没有“复杂理论”的情况下得出。从圆上的(x,y)
点开始:(R,0)
并保持值d=x^2+y^2-R^2
,最初为0. D是从当前点到圆的平方距离。我们递增Y,并根据需要递减X以保持D最小值:
// Discretize 1/8 circle:
x = R ; y = 0 ; d = 0
while x >= y
print (x,y)
// increment Y, D must be updated by (Y+1)^2 - Y^2 = 2*Y+1
d += (2*y+1) ; y++
// now if we decrement X, D will be updated by -2*X+1
// do it only if it keeps D closer to 0
if d >= 0
d += (-2*x+1) ; x--
答案 1 :(得分:6)
老实说,Midpoint circle algorithm不够吗?只需在所有象限中镜像它。并且无论如何 no - 除非您试图获得作为窗口应用程序测试人员的工作,Bresenham's Line Algorithm并不是复杂的理论。
答案 2 :(得分:5)
来自this page的第二种方法:
对于每个像素,进行评估 x 2 + y 2 并查看是否 它在...的范围内 R 2 -R + 1至R 2 + R. 包括的。如果是这样,请为像素着色 屏幕,如果没有,不要。
在上述页面上给出了进一步的细节和解释,但关键是你正在寻找距离原点R-0.5和R + 0.5之间距离的像素,因此距离平方为x 2 < / sup> + y 2 且阈值距离平方为R 2 -R + 0.25且R 2 + R + 0.25。
对于其他方法,Google“仅使用整数运算绘制圆圈”。
答案 3 :(得分:4)
相当古老的问题,但我会尝试在python中提供可视化测试的最终解决方案,作为Bresenham算法的替代方案 - 这项任务的最佳和最短解决方案。我认为这个想法也可以有一个地方,也许更容易理解,但需要更多的代码。有人也可能最终得到这个解决方案。
这个想法基于以下事实:
import matplotlib.pyplot as plt
from itertools import chain
def get_distance(x1, y1, x2, y2):
"""
Calculates squared distance between (x1, y1) and (x2, y2) points
"""
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
def get_next_point(x, y, dx, dy, cx, cy, r):
"""
Returns the next circle point base on base point (x, y),
direction (dx, dy), circle central point (cx, cy) and radius r
"""
r2 = r * r
# three possible points
x1, y1 = x + dx, y + dy
x2, y2 = x, y + dy
x3, y3 = x + dx, y
# calculate difference between possible point distances
# with central point and squared radius
dif1 = abs(get_distance(x1, y1, cx, cy) - r2)
dif2 = abs(get_distance(x2, y2, cx, cy) - r2)
dif3 = abs(get_distance(x3, y3, cx, cy) - r2)
# choosing the point with minimum distance difference
diff_min = min(dif1, dif2, dif3)
if diff_min == dif1:
return x1, y1
elif diff_min == dif2:
return x2, y2
else:
return x3, y3
def get_quadrant(bx, by, dx, dy, cx, cy, r):
"""
Returns circle quadrant starting from base point (bx, by),
direction (dx, dy), circle central point (cx, cy) and radius r
"""
x = bx
y = by
# maximum or minimum quadrant point (x, y) values
max_x = bx + dx * r
max_y = by + dy * r
# choosing only quadrant points
while (dx * (x - max_x) <= 0) and (dy * (y - max_y) <= 0):
x, y = get_next_point(x, y, dx, dy, cx, cy, r)
yield x, y
def get_circle(r, cx, cy):
"""
Returns circle points (list) with radius r and center point (cx, cy)
"""
north_east_quadrant = get_quadrant(cx, cy - r, 1, 1, cx, cy, r)
south_east_quadrant = get_quadrant(cx + r, cy, -1, 1, cx, cy, r)
south_west_quadrant = get_quadrant(cx, cy + r, -1, -1, cx, cy, r)
north_west_quadrant = get_quadrant(cy - r, cy, 1, -1, cx, cy, r)
return chain(north_east_quadrant, south_east_quadrant,
south_west_quadrant, north_west_quadrant)
# testing
r = 500
circle_points = get_circle(r, r, r)
for x, y in circle_points:
plt.plot([x], [y], marker='o', markersize=3, color="red")
plt.show()
答案 4 :(得分:3)
我将使用Bressenham的Circle绘图算法或Midpoint Circle绘图算法。两者都产生相同的坐标点。由于圆的8个八分圆之间的对称性,我们只需要生成一个八分圆,然后将其反射并复制到所有其他位置。
答案 5 :(得分:2)
这是我的面试答案(没有研究,这是当场的)......
设置两个嵌套的for循环,它们共同循环遍历由{-R,-R,2R,2R}定义的方块。对于每个像素,计算(i ^ 2 + j ^ 2)其中i和j是您的循环变量。如果这在R ^ 2的某个容差范围内,则将该像素设置为黑色,如果不是则将该像素单独留下。
我太懒了,无法确定应该容忍的是什么。您可能需要将最后计算的值存储为零,哪个像素最能代表圆圈...但这个基本方法应该可以很好地工作。
答案 6 :(得分:2)
使用一阶泰勒近似可以很容易地计算x ^ 2 = r ^ 2- y ^ 2中的x
sqrt(u ^ 2 + a)= u + a / 2u
这是Mathematica中的一个程序(简短,但可能不太好)
rad=87; (* Example *)
Calcy[r_,x_]:= (
y2 = rad^2 - x^2;
u = Ordering[Table[ Abs[n^2-y2], {n,1,y2}]] [[1]]; (* get the nearest perfect square*)
Return[ u-(u^2-y2)/(2 u) ]; (* return Taylor approx *)
)
lista = Flatten[Table[{h Calcy[rad, x], j x}, {x, 0, rad}, {h, {-1, 1}}, {j, {-1, 1}}], 2];
ListPlot[Union[lista, Map[Reverse, lista]], AspectRatio -> 1];
这是结果
alt text http://i47.tinypic.com/246nfxt.jpg
恕我直言......我对图形算法一无所知......
答案 7 :(得分:2)
有没有人认为他们可能正在寻找一个侧面的答案,例如“用指南针和铅笔”或“使用一卷卖点作为模板”。
每个人都认为所有问题都必须通过计算机来解决。