docs: def concentric_circle(center, radius, size=None):
      """
      Draws a circle with the given center and radius.
      This is designed to ensure that concentric circles with integer radii are "airtight",
      i.e. there are not unfilled pixels between them.
      :param center: The (x, y) coordinates of the center of the circle
      :param radius:
      :param size: If not None, the size of the image. This is used to skip pizxels that are out of bounds.
      :return: This is a generator that yields (x,y) coordinates of the circle one at a time
      """
      c_out = bresenham_circle_octant(radius + 1)
      c_in = bresenham_circle_octant(radius)
      coords = []
  
      # note that in this loop, y also serves as the array index,
      # since it starts at 0 and increments each element.
      for x, y in c_in:
          for x1 in range(x, c_out[y][0]):
              coords.append((x1, y))
      # copy octant 8 times to get other pixels
      # TODO might recount pixels where x == y
      next_octant = [(y, x) for x, y in reversed(coords)]
      coords.extend(next_octant)
      next_quadrant = [(-y, x) for x, y in coords]
      coords.extend(next_quadrant)
      next_half = [(-x, -y) for x, y in coords]
      coords.extend(next_half)
  
      for x, y in coords:
          c = x + center[0], y + center[1]
          if size is not None:
              if not in_bounds((0, 0), size, c):
                  continue
          yield c