from math import floor, sqrt


def transform_mp_to_abc(m, p):
    """transforme une équation de la forme y = mx + p to ax + by = c

    :returns: 3-uple of a, b, c

    """
    return -m, 1, p


def transform_abc_to_mp(a, b, c):
    """transforme une équation de la forme to ax + by = c to y = mx + p

    :returns: tuple of m, x

    """
    return -a/b, c


def droite(p1: tuple, p2: tuple) -> tuple:
    """retourne un 3-uple d'une droite selon ax+by=c

    :p1: tuple du point 1
    :p2: tuple du point 2
    :returns: 3-uple (a,b,c) tq ax+by=c

    """
    x1, y1 = p1
    x2, y2 = p2
    if p1 == p2:
        return
    if x2-x1 == 0:
        return 1, 0, 0
    a = -(y2-y1)/(x2-x1)
    c = a*x1
    b = (-a*x2 + c) / y2
    return a, b, c


def appartient(d, p):
    """
    :d: equation d'une droite
    :p: point
    :returns: true si point est dans droite

    """
    a, b, c = d
    x, y = p
    return a*x + b*y == c


def paralleles(d1, d2):
    """
    :d1: droite 1
    :d2: droite 2
    :returns: true si d1 et d2 sont paralleles sinon false

    """
    a1, b1, c1 = d1
    a2, b2, c2 = d2

    return a1/b1 ==  a2/b2


def intersection(d1, d2):
    """Trouve le point d'intersection

    :d1: droite 1
    :d2: droite 2
    :returns: retourne le point d'intersection sinon None

    """
    a1, b1, c1 = d1
    a2, b2, c2 = d2

    if paralleles(d1, d2):
        return  # paralleles donc pas d'intersection

    y = (c2*a1 - a2*c1) / (-a2*b1 + b2*a1)
    x = (c1 - b1*y)/ a1

    return x, y


def droite_normale(d, p):
    """trouve la normale dune droite passant par un point.

    :d: droite
    :p: point
    :returns: retourne la normale de la droite passant par le point

    """
    a, b, c = d
    x, y = p

    m, p = transform_abc_to_mp(a, b, c)
    return transform_mp_to_abc(-1/m, y-(-1/m)*x)


def symetrie_orthogonale(d, p):
    """ retourne la symétrie orthogonale par le point p de la droite d
    :returns: symétrie orthogonale

    """
    a, b, c = d
    x, y = p
    ap, bp, cp = droite_normale(d, p) # perpendiculaire passant par le point
    xi, yi = intersection((a, b, c), (ap, bp, cp))
    return round((2*xi - x)*10)/10, round((2*yi - y)*10)/10


def distance_droite_point(d, p):
    """ donne la distance entre une droite et un point
    :returns: distance la plus courte entre le point et la droite

    """
    a, b, c = d
    x, y = p
    ap, bp, cp = droite_normale(d,p) # perpendiculaire passant par le point
    xi, yi = intersection((a,b,c), (ap, bp, cp))
    return sqrt((xi-x)**2 + (yi-y)**2)

