Scan pixels in a circle pattern around a center point

    :param x0: Center x-coordinate
    :type x0: float
    :param y0: Center y-coordinate
    :type y0: float
    :param r1: Initial radius
    :type r1: float
    :param r2: Final radius
    :type r2: float
    :returns: Coordinate generator
    :rtype: function

def circlescan(x0, y0, r1, r2):
    """Scan pixels in a circle pattern around a center point

    :param x0: Center x-coordinate
    :type x0: float
    :param y0: Center y-coordinate
    :type y0: float
    :param r1: Initial radius
    :type r1: float
    :param r2: Final radius
    :type r2: float
    :returns: Coordinate generator
    :rtype: function
    """

    # Validate inputs
    if r1 < 0: raise ValueError("Initial radius must be non-negative")
    if r2 < 0: raise ValueError("Final radius must be non-negative")

    # List of pixels visited in previous diameter
    previous = []
    
    # Scan distances outward (1) or inward (-1)
    rstep = 1 if r2 >= r1 else -1
    for distance in range(r1, r2 + rstep, rstep):

        if distance == 0:

            yield x0, y0

        else:

            # Computes points for first octant and the rotate by multiples of
            # 45 degrees to compute the other octants
            a = 0.707107
            rotations = {0: [[ 1, 0], [ 0, 1]],
                         1: [[ a, a], [-a, a]],
                         2: [[ 0, 1], [-1, 0]],
                         3: [[-a, a], [-a,-a]],
                         4: [[-1, 0], [ 0,-1]],
                         5: [[-a,-a], [ a,-a]],
                         6: [[ 0,-1], [ 1, 0]],
                         7: [[ a,-a], [ a, a]]}
            nangles = len(rotations)

            # List of pixels visited in current diameter
            current = []

            for angle in range(nangles):
                x = 0
                y = distance
                d = 1 - distance
                while x < y:
                    xr = rotations[angle][0][0]*x + rotations[angle][0][1]*y
                    yr = rotations[angle][1][0]*x + rotations[angle][1][1]*y
                    xr = x0 + xr
                    yr = y0 + yr
                    
                    # First check  if point was in previous diameter
                    # since our scan pattern can lead to duplicates in
                    # neighboring diameters
                    point = (int(round(xr)), int(round(yr)))
                    if point not in previous:
                        yield xr, yr
                        current.append(point)

                    # Move pixel according to circle constraint
                    if (d < 0):
                        d += 3 + 2 * x
                    else:
                        d += 5 - 2 * (y-x)
                        y -= 1
                    x += 1

            previous = current