from math import sin, cos, pi

from PIL import Image

from commons import clear

class Hough:
    def __init__(self, size):
        self.size = size
        self.dt = pi / size[1]
        self.initial_angle = (pi / 4) + (self.dt / 2)

    def transform(self, image):
        image_l = image.load()
        size = image.size
        
        matrix = [[0]*size[1] for _ in xrange(size[0])]

        dt = self.dt
        initial_angle = self.initial_angle

        for x in xrange(size[0]):
            clear()
            print "hough transform: {0:>3}/{1}".format(x + 1, size[0])
            for y in xrange(size[1]):
                if image_l[x, y]:
                    # for every angle:
                    for a in xrange(size[1]):
                        # find the distance:
                        # distance is the dot product of vector (x, y) - centerpoint
                        # and a unit vector orthogonal to the angle
                        distance = (((x - (size[0] / 2)) * sin((dt * a) + initial_angle)) + 
                                    ((y - (size[1] / 2)) * -cos((dt * a) + initial_angle)) +
                                    size[0] / 2)
                        # column of the matrix closest to the distance
                        column = int(round(distance)) 
                        if column >= 0 and column < size[0]:
                            matrix[column][a] += 1

        new_image = Image.new('L', size)
        new_image_l = new_image.load()

        minimum = min([min(m) for m in matrix])

        maximum = max([max(m) for m in matrix]) - minimum

        for y in xrange(size[1]):
            for x in xrange(size[0]):
                new_image_l[x, y] = (float(matrix[x][y] - minimum) / maximum) * 255
            
        return new_image

    def all_lines(self, image):
        im_l = image.load()
        lines = []
        for x in xrange(image.size[0]):
            for y in xrange(image.size[1]):
                if im_l[x, y]:
                    lines.append(self.angle_distance((x, y)))
        return lines
    
    def find_angle_distance(self, image):
        image_l = image.load()

        points = []

        count = 0
        point_x = 0
        point_y = 0
        for x in xrange(image.size[0] / 2):
            for y in xrange(image.size[1] / 2, image.size[1]):
                if image_l[x, y]:
                    count += 1
                    point_x += x
                    point_y += y
        points.append((float(point_x) / count, float(point_y) / count))

        count = 0
        point_x = 0
        point_y = 0
        for x in xrange(image.size[0] / 2, image.size[0]):
            for y in xrange(image.size[1] / 2, image.size[1]):
                if image_l[x, y]:
                    count += 1
                    point_x += x
                    point_y += y
        points.append((float(point_x) / count, float(point_y) / count))

        return [self.angle_distance(p) for p in points]

    def angle_distance(self, point):
        return (self.dt * point[1] + self.initial_angle, point[0] - self.size[0] / 2)
        
