from numpy import sqrt, dot, sin, array, pi

from math import atan2, acos


def two_point_arc_to_kiva_arc(p1, p2, theta):
    """
    Converts an arc in two point and subtended angle  format (startpoint,
    endpoint, theta (positive for ccw, negative for cw)) into kiva format
    (x, y, radius, start_angle, end_angle, cw)
    """

    chord = p2-p1
    chordlen = sqrt(dot(chord, chord))
    radius = abs(chordlen/(2*sin(theta/2)))
    altitude = sqrt(pow(radius, 2) - pow(chordlen/2, 2))
    if theta > pi or theta < 0:
        altitude = -altitude
    chordmidpoint = (p1+p2)/2
    rotate90 = array(((0.0, -1.0),
                      (1.0, 0.0)))
    centerpoint = dot(rotate90, (chord/chordlen))*altitude + chordmidpoint

    start_angle = atan2(*(p1 - centerpoint)[::-1])
    end_angle = start_angle + theta
    if theta < 0:
        start_angle, end_angle, = end_angle, start_angle
    cw = False
    radius = abs(radius)
    return (centerpoint[0], centerpoint[1], radius, start_angle, end_angle, cw)


def arc_to_tangent_points(start, p1, p2, radius):
    """ Given a starting point, two endpoints of a line segment, and a radius,
        calculate the tangent points for arc_to().
    """
    def normalize_vector(x, y):
        """ Given a vector, return its unit length representation.
        """
        length = sqrt(x**2+y**2)
        if length <= 1e-6:
            return (0.0, 0.0)
        return (x/length, y/length)

    # calculate the angle between the two line segments
    v1 = normalize_vector(start[0]-p1[0], start[1]-p1[1])
    v2 = normalize_vector(p2[0]-p1[0], p2[1]-p1[1])
    angle = acos(v1[0]*v2[0]+v1[1]*v2[1])

    # punt if the half angle is zero or a multiple of pi
    sin_half_angle = sin(angle/2.0)
    if sin_half_angle == 0.0:
        return (p1, p2)

    # calculate the distance from p1 to the center of the arc
    dist_to_center = radius / sin_half_angle
    # calculate the distance from p1 to each tangent point
    dist_to_tangent = sqrt(dist_to_center**2-radius**2)

    # calculate the tangent points
    t1 = (p1[0]+v1[0]*dist_to_tangent, p1[1]+v1[1]*dist_to_tangent)
    t2 = (p1[0]+v2[0]*dist_to_tangent, p1[1]+v2[1]*dist_to_tangent)

    return (t1, t2)
