Merge pull request #410 from sciunto/circle

Circle perimeter: add new method: Andres
This commit is contained in:
Johannes Schönberger
2013-01-13 02:35:55 -08:00
2 changed files with 77 additions and 11 deletions
+44 -8
View File
@@ -189,7 +189,7 @@ def circle(double cy, double cx, double radius, shape=None):
return ellipse(cy, cx, radius, radius, shape)
def circle_perimeter(int cy, int cx, int radius):
def circle_perimeter(int cy, int cx, int radius, method='bresenham'):
"""Generate circle perimeter coordinates.
Parameters
@@ -198,6 +198,10 @@ def circle_perimeter(int cy, int cx, int radius):
Centre coordinate of circle.
radius: int
Radius of circle.
method : {'bresenham', 'andres'}, optional
bresenham : Bresenham method
andres : Andres method
Returns
-------
@@ -206,6 +210,19 @@ def circle_perimeter(int cy, int cx, int radius):
May be used to directly index into an array, e.g.
``img[rr, cc] = 1``.
Notes
-----
Andres method presents the advantage that concentric
circles create a disc whereas Bresenham can make holes. There
is also less distortions when Andres circles are rotated.
Bresenham method is also known as midpoint circle algorithm.
References
----------
.. [1] J.E. Bresenham, "Algorithm for computer control of a digital
plotter", 4 (1965) 25-30.
.. [2] E. Andres, "Discrete circles, rings and spheres", 18 (1994) 695-706.
"""
cdef list rr = list()
@@ -213,17 +230,36 @@ def circle_perimeter(int cy, int cx, int radius):
cdef int x = 0
cdef int y = radius
cdef int d = 3 - 2 * radius
cdef int d = 0
if method == 'bresenham':
d = 3 - 2 * radius
elif method == 'andres':
d = radius - 1
else:
raise ValueError('Wrong method')
while y >= x:
rr.extend([y, -y, y, -y, x, -x, x, -x])
cc.extend([x, x, -x, -x, y, y, -y, -y])
if d < 0:
d += 4 * x + 6
else:
d += 4 * (x - y) + 10
y -= 1
x += 1
if method == 'bresenham':
if d < 0:
d += 4 * x + 6
else:
d += 4 * (x - y) + 10
y -= 1
x += 1
elif method == 'andres':
if d >= 2 * (x - 1):
d = d - 2 * x
x = x + 1
elif d <= 2 * (radius - y):
d = d + 2 * y - 1
y = y - 1
else:
d = d + 2 * (y - x - 1)
y = y - 1
x = x + 1
return np.array(rr) + cy, np.array(cc) + cx
+33 -3
View File
@@ -150,14 +150,14 @@ def test_circle():
assert_array_equal(img, img_)
def test_circle_perimeter():
def test_circle_perimeter_bresenham():
img = np.zeros((15, 15), 'uint8')
rr, cc = circle_perimeter(7, 7, 0)
rr, cc = circle_perimeter(7, 7, 0, method='bresenham')
img[rr, cc] = 1
assert(np.sum(img) == 1)
img = np.zeros((17, 15), 'uint8')
rr, cc = circle_perimeter(7, 7, 7)
rr, cc = circle_perimeter(7, 7, 7, method='bresenham')
img[rr, cc] = 1
img_ = np.array(
[[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
@@ -180,6 +180,36 @@ def test_circle_perimeter():
)
assert_array_equal(img, img_)
def test_circle_perimeter_andres():
img = np.zeros((15, 15), 'uint8')
rr, cc = circle_perimeter(7, 7, 0, method='andres')
img[rr, cc] = 1
assert(np.sum(img) == 1)
img = np.zeros((17, 15), 'uint8')
rr, cc = circle_perimeter(7, 7, 7, method='andres')
img[rr, cc] = 1
img_ = np.array(
[[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
[0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
)
assert_array_equal(img, img_)
def test_ellipse():
img = np.zeros((15, 15), 'uint8')