def _drawline(surface, c_color, start, end): # Bresenham algorithm x0, y0 = start x1, y1 = end dx = abs(x1 - x0) dy = abs(y1 - y0) sx = -1 if x0 > x1 else 1 sy = -1 if y0 > y1 else 1 err = dx - dy while True: surface._set_at(x0, y0, c_color) if x0 == x1 and y0 == y1: break e2 = err * 2 if e2 > -dy: err -= dy x0 += sx if x0 == x1 and y0 == y1: surface._set_at(x0, y0, c_color) break if e2 < dx: err += dx y0 += sy
def _check_special_ellipse(surface, c_x, c_y, radius_x, radius_y, c_color): if radius_x == 0 and radius_y == 0: with locked(surface._c_surface): surface._set_at(c_x, c_y, c_color) return True elif radius_x == 0: # vertical line _drawvertline(surface, c_color, c_y - radius_y, c_y + radius_y, c_x) return True elif radius_y == 0: _drawhorizline(surface, c_color, c_x - radius_x, c_x + radius_x, c_y) return True return False
def _check_special_ellipse(surface, c_x, c_y, radius_x, radius_y, c_color): if radius_x == 0 and radius_y == 0: clip = surface.get_clip() # Throw away points outside the clip area if c_x < clip.x or c_x >= (clip.x + clip.w): return True if c_y < clip.y or c_y >= (clip.y + clip.h): return True with locked(surface._c_surface): surface._set_at(c_x, c_y, c_color) return True elif radius_x == 0: # vertical line _drawvertline(surface, c_color, c_y - radius_y, c_y + radius_y, c_x) return True elif radius_y == 0: _drawhorizline(surface, c_color, c_x - radius_x, c_x + radius_x, c_y) return True return False
def _check_special_ellipse(surface, c_x, c_y, radius_x, radius_y, c_color): if radius_x == 0 and radius_y == 0: clip = surface.get_clip() # Throw away points outside the clip area if c_x < clip.x or c_x > (clip.x + clip.w): return True if c_y < clip.y or c_y > (clip.y + clip.h): return True with locked(surface._c_surface): surface._set_at(c_x, c_y, c_color) return True elif radius_x == 0: # vertical line _drawvertline(surface, c_color, c_y - radius_y, c_y + radius_y, c_x) return True elif radius_y == 0: _drawhorizline(surface, c_color, c_x - radius_x, c_x + radius_x, c_y) return True return False
def _drawline(surface, c_color, start, end): # Bresenham algorithm (more or less as approximated by pygame) x0, y0 = start x1, y1 = end if x0 == x1: _drawvertline(surface, c_color, y0, y1, x0) return if y0 == y1: _drawhorizline(surface, c_color, x0, x1, y0) return # Because of how we approximate pygame's pointer # arthimetic, we don't handle the ends of the lines # the same way - this fakes it surface._set_at(x0, y0, c_color) surface._set_at(x1, y1, c_color) steep = False if abs(y1 - y0) > abs(x1 - x0): steep = True x0, y0 = y0, x0 x1, y1 = y1, x1 dx = abs(x1 - x0) + 1 dy = abs(y1 - y0) + 1 ystep = 1 if y0 < y1 else -1 xstep = 1 if x0 < x1 else -1 y = y0 error = 0 for x in range(x0, x1, xstep): if steep: surface._set_at(y, x, c_color) else: surface._set_at(x, y, c_color) error = error + dy if error >= dx: y += ystep error -= dx
def _ellipse(surface, pos, radius_x, radius_y, color): """Internal helper function draw a ellipse with line thickness 1 on surface.""" c_surf = surface._c_surface c_x, c_y = pos c_color = create_color(color, surface._format) if _check_special_ellipse(surface, c_x, c_y, radius_x, radius_y, c_color): return # Draw the ellipse # Pygame's ellipse drawing algorithm appears to come from allegro, via sge # and SDL_gfxPrimitives. It's known to be non-optimal, but we're aiming # for pygame compatibility, so we're doing the same thing, much as # it grates me to do so. # We assume suitable diligence in terms of the licensing, but allegro's # zlib'ish license should mean we're OK anyway. stop_h = stop_i = stop_j = stop_k = -1 bounds = surface.get_bounding_rect() with locked(c_surf): i = 1 h = 0 if radius_x > radius_y: ix = 0 iy = radius_x * 64 while i > h: h = (ix + 16) // 64 i = (iy + 16) // 64 j = (h * radius_y) // radius_x k = (i * radius_y) // radius_x if (stop_k != k and stop_j != k) or (stop_j != j and stop_k != k) or (k != j): plus_x = c_x + h - 1 minus_x = c_x - h if k > 0: plus_y = c_y + k - 1 minus_y = c_y - k if h > 0: if bounds.collidepoint(minus_x, plus_y): surface._set_at(minus_x, plus_y, c_color) if bounds.collidepoint(minus_x, minus_y): surface._set_at(minus_x, minus_y, c_color) if bounds.collidepoint(plus_x, plus_y): surface._set_at(plus_x, plus_y, c_color) if bounds.collidepoint(plus_x, minus_y): surface._set_at(plus_x, minus_y, c_color) stop_k = k plus_x = c_x + i - 1 minus_x = c_x - i if j > 0: plus_y = c_y + j - 1 minus_y = c_y - j if bounds.collidepoint(plus_x, plus_y): surface._set_at(plus_x, plus_y, c_color) if bounds.collidepoint(plus_x, minus_y): surface._set_at(plus_x, minus_y, c_color) if bounds.collidepoint(minus_x, plus_y): surface._set_at(minus_x, plus_y, c_color) if bounds.collidepoint(minus_x, minus_y): surface._set_at(minus_x, minus_y, c_color) stop_j = j ix = ix + _c_div(iy, radius_x) iy = iy - _c_div(ix, radius_x) else: ix = 0 iy = radius_y * 64 while i > h: h = (ix + 32) // 64 i = (iy + 32) // 64 j = (h * radius_x) // radius_y k = (i * radius_x) // radius_y if (stop_i != i and stop_h != i) or (stop_i != h and stop_h != h) or (h != i): plus_x = c_x + j - 1 minus_x = c_x - j if i > 0: plus_y = c_y + i - 1 minus_y = c_y - i if j > 0: if bounds.collidepoint(minus_x, plus_y): surface._set_at(minus_x, plus_y, c_color) if bounds.collidepoint(minus_x, minus_y): surface._set_at(minus_x, minus_y, c_color) if bounds.collidepoint(plus_x, plus_y): surface._set_at(plus_x, plus_y, c_color) if bounds.collidepoint(plus_x, minus_y): surface._set_at(plus_x, minus_y, c_color) stop_i = i plus_x = c_x + k - 1 minus_x = c_x - k if h > 0: plus_y = c_y + h - 1 minus_y = c_y - h if bounds.collidepoint(plus_x, plus_y): surface._set_at(plus_x, plus_y, c_color) if bounds.collidepoint(plus_x, minus_y): surface._set_at(plus_x, minus_y, c_color) if bounds.collidepoint(minus_x, plus_y): surface._set_at(minus_x, plus_y, c_color) if bounds.collidepoint(minus_x, minus_y): surface._set_at(minus_x, minus_y, c_color) stop_h = h ix = ix + _c_div(iy, radius_y) iy = iy - _c_div(ix, radius_y)