"""Routines for drawing anti-aliased circles onto a Pygame surface.

Adapted from the DrawCircles example Delphi program,
Copyright (c) 2003 by Nils Haeck M.Sc. (Simdesign)
http://www.simdesign.nl/tips/tip002.html

"""

from __future__ import division
import math

def DrawDisk(Bitmap, Position, Radius, Feather=1.0):
    """Draw a filled, anti-aliased, disk

    Bitmap is a Pygame surface.
    Position is an (x, y) pair of floats.
    Radius is a float.
    Feather is an optional width of the anti-aliasing area as a float (default 1.0).
    
    """
    CenterX, CenterY = Position

    RPF2 = (Radius + Feather / 2.0) ** 2.0
    RMF2 = (Radius - Feather / 2.0) ** 2.0

    LX = max(int(math.floor(CenterX - RPF2)), 0)
    RX = min(int(math.ceil(CenterX + RPF2)), Bitmap.get_width() - 1)
    LY = max(int(math.floor(CenterY - RPF2)), 0)
    RY = min(int(math.ceil(CenterY + RPF2)), Bitmap.get_height() - 1)

    SqX = [(x - CenterX) ** 2 for x in range(LX, RX+1)]

    for y in range(LY, RY+1):
        SqY = (y - CenterY) ** 2
        for x in range(LX, RX):
            SqDist = float(SqY + SqX[x - LX])

            if SqDist < RMF2:
                Bitmap.set_at((x, y), (255, 255, 255, 255))
            elif SqDist < RPF2:
                Fact = int(round(((Radius - math.sqrt(SqDist)) * 2.0 / Feather) * 127.5 + 127.5))
                Alpha = max(0, min(Fact, 255))
                Bitmap.set_at((x, y), (255, 255, 255, Alpha))
            else:
                Bitmap.set_at((x, y), (255, 255, 255, 0))

def DrawCircle(Bitmap, Position, Radius, LineWidth=1.0, Feather=1.0):
    """Draw an anti-aliased circle with line width.

    Bitmap is a Pygame surface.
    Position is an (x, y) pair of floats.
    Radius is a float.
    LindWidth is an optional float (default 1.0).
    Feather is an optional width of the anti-aliasing area as a float (default 1.0).
    
    """
    CenterX, CenterY = Position

    OutRad = Radius + LineWidth / 2.0
    InRad = Radius - LineWidth / 2.0
    ROPF2 = (OutRad + Feather / 2.0) ** 2.0
    ROMF2 = (OutRad - Feather / 2.0) ** 2.0
    RIPF2 = (InRad + Feather / 2.0) ** 2.0
    RIMF2 = (InRad - Feather / 2.0) ** 2.0

    LX = max(int(math.floor(CenterX - ROPF2)), 0)
    RX = min(int(math.ceil(CenterX + ROPF2)), Bitmap.get_width() - 1)
    LY = max(int(math.floor(CenterY - ROPF2)), 0)
    RY = min(int(math.ceil(CenterY + ROPF2)), Bitmap.get_height() - 1)

    if Feather > LineWidth:
        Feather = LineWidth

    SqX = [(x - CenterX) ** 2.0 for x in range(LX, RX+1)]

    for y in range(LY, RY+1):
        SqY = (y - CenterY) ** 2.0
        for x in range(LX, RX+1):
            SqDist = SqY + SqX[x-LX]

            if SqDist < RIMF2:
                Bitmap.set_at((x, y), (255, 255, 255, 0))
            else:
                if SqDist < ROPF2:
                    if SqDist < ROMF2:
                        if SqDist < RIPF2:
                            Fact = int(round(((math.sqrt(SqDist) - InRad) * 2.0 / Feather) * 127.5 + 127.5))
                            Alpha = max(0, min(Fact, 255))
                            Bitmap.set_at((x, y), (255, 255, 255, Alpha))
                        else:
                            Bitmap.set_at((x, y), (255, 255, 255, 255))
                    else:
                        Fact = int(round(((OutRad - math.sqrt(SqDist)) * 2.0 / Feather) * 127.5 + 127.5))
                        Alpha = max(0, min(Fact, 255))
                        Bitmap.set_at((x, y), (255, 255, 255, Alpha))
                else:
                    Bitmap.set_at((x, y), (255, 255, 255, 0))
