import math

# Global constants
fc_pi = math.pi
fc_piover2 = math.pi / 2
fc_2pi = 2 * math.pi
Geom_precision = 1e-7


def direction_radian(x1, y1, x2, y2):
    """

    NOM direction_radian: direction trigonometrique en Radians de deux points

    DESCRIPTION

    Renvoie, en radians, la valeur de la direction (trigonometrique) formee par 2 points

    SYNOPSIS
    VOIR EGALEMENT
    DIAGNOSTICS
    """
    # Declaration of variable as used in the C code
    if math.fabs(x2 - x1) < Geom_precision:
        if y2 < y1:
            dir = 1.5 * fc_pi
        elif y1 < y2:
            dir = fc_piover2
        else:
            dir = 0.0
    else:
        dir = math.atan((y2 - y1) / (x2 - x1))
        if x2 < x1:
            dir = dir + fc_pi
        if dir < 0.0:
            dir = dir + fc_2pi
    return dir


def trigonometric_angle(ang1, ang2):
    """

    NOM trigonometric_angle: Angle trigo de la direction definie par ang1
    (direction trigo) a la direction definie par ang2 (direction trigo) (Radians)

    DESCRIPTION

    Renvoie, en radians, la valeur de l'angle trigo de la direction
    definie par ang1 (direction trigo) a la direction definie par ang2
    (direction trigo)

    SYNOPSIS
    VOIR EGALEMENT
    DIAGNOSTICS
    """
    angle = ang2 - ang1
    if angle >= fc_2pi:
        angle = angle - fc_2pi
    if angle < 0.0:
        angle = angle + fc_2pi
    return angle


def gisement_radian(x1, y1, x2, y2):
    """

    NOM gisement_radian: gisement entre 2 points (Radians)

    DESCRIPTION

    Renvoie la valeur du gisement en radians entre 2 points

    SYNOPSIS
    VOIR EGALEMENT
    DIAGNOSTICS
    """
    gis = math.atan2(x2 - x1, y2 - y1)
    if gis < 0.0:
        gis = gis + fc_2pi
    return gis


def gisement_grade(x1, y1, x2, y2):
    """

    NOM gisement_grade: gisement entre 2 points (Grades)

    DESCRIPTION

    Renvoie la valeur du gisement en grades entre 2 points

    SYNOPSIS
    VOIR EGALEMENT
    DIAGNOSTICS
    """
    gis = gisement_radian(x1, y1, x2, y2) / fc_pi * 200.0
    return gis


def sharp_angle_between_gisements_radian(gis1, gis2):
    """

    NOM sharp_angle_between_gisements_radian: Renvoie l'angle topo "aigu" entre 2 gisements
                                    -PI < angle <= PI

    DESCRIPTION

    SYNOPSIS
    VOIR EGALEMENT
    DIAGNOSTICS
    """
    angle = gis2 - gis1
    while angle > fc_pi:
        angle -= 2.0 * fc_pi
    while angle <= -fc_pi:
        angle += 2.0 * fc_pi
    return angle


def sharp_angle_radian_between_points(x1, y1, x2, y2, x3, y3):
    """
    NOM sharp_angle_radian_between_points: Angle topo en radians de la direction 1-2 vers la
                                 direction 1-3 (-PI < angle <= PI)

    DESCRIPTION

    Renvoie la valeur de l'angle topo en radians de la direction 1-2 vers la
    direction 1-3

    SYNOPSIS
    VOIR EGALEMENT
    DIAGNOSTICS
    """
    gis1 = math.atan2(x2 - x1, y2 - y1)
    gis2 = math.atan2(x3 - x1, y3 - y1)
    angle = sharp_angle_between_gisements_radian(gis1, gis2)
    return angle


if __name__ == "__main__":
    # Example test calls to verify the functionality of the functions
    print("direction_radian:", direction_radian(0, 0, 1, 1))
    print("trigonometric_angle:", trigonometric_angle(0, 3 * math.pi / 2))
    print("gisement_radian:", gisement_radian(0, 0, 1, 1))
    print("gisement_grade:", gisement_grade(0, 0, 1, 1))
    print(
        "sharp_angle_between_gisements_radian:",
        sharp_angle_between_gisements_radian(0.5, 2.0),
    )
    print(
        "sharp_angle_radian_between_points:",
        sharp_angle_radian_between_points(0, 0, 1, 0, 0, 1),
    )
