"""
module : mathweb-geometrie.py
auteur : Stéphane Pasquet
site : https://mathweb.fr
date : 21/12/2020
"""

"""
Point
"""

# objet "Point"

class Point:
    def __init__(self,abscisse,ordonnee):
        self.x = abscisse
        self.y = ordonnee
        
    def __eq__(self,other):
        if self.x == other.x and self.y == other.y: return True
        else: return False
        
    def __hash__(self):
        return hash(self.x) ^ hash(self.y)

# distance entre deux points

def distance(P1,P2):
    if isinstance(P1,Point) and isinstance(P2,Point):
        return ((P1.x-P2.x)**2 + (P1.y-P2.y)**2)**0.5
    else:
        return "Les deux arguments doivent être de la classe 'Point'."

"""
Vecteur
"""

class Vecteur:
    def __init__(self,P1,P2):
        self.x = P2.x - P1.x
        self.y = P2.y - P1.y
        self.norme = (self.x**2 + self.y**2)**0.5
        
    def __add__(self,other):
        return Vecteur(Point(0,0) , Point(self.x + other.x , self.y + other.y) )
    
    def __sub__(self,other):
        return Vecteur(Point(0,0) , Point(self.x - other.x , self.y - other.y) )
    
    def __mul__(self,other):
        return self.x*other.x + self.y*other.y
    
    def __str__(self):
        return '({} ; {})'.format(self.coord()[0],self.coord()[1])
    
    def coord(self):
        return (self.x,self.y)
    
    def is_orth(self,other):
        if self*other == 0:
            return True
        else:
            return False
        
    def is_col(self,other):
        if self.x*other.y == self.y*other.x:
            return True
        else:
            return False

"""
Droite
"""

class Droite:
    def __init__(self,P1,P2):
        if P2.x != P1.x:
            self.coef = (P2.y - P1.y) / (P2.x - P1.x)
            self.ord = P1.y - self.coef*P1.x
        else:
            self.coef = None
            self.abscisse = P1.x
        
    def __str__(self):
        if self.ord < 0:
            end = ' - {}' . format(abs(self.ord))
        elif self.ord > 0:
            end = ' + {}' . format(self.ord)
        else:
            end = ''
        return 'y = {}x'.format(self.coef) + end
    
    def __eq__(self,other):
        if self.coef == other.coef and self.ord == other.ord:
            return True
        else:
            return False
        
    def __hash__(self):
        return hash(self.coef) ^ hash(self.ord)
        
    def is_parallel(self,other,strict=False):
        if self.coef != other.coef: return False
        else: # si les deux coef sont égaux
            if self == other:
                if strict: return False
                else: return True        
            else:
                return True
        
    def is_perp(self,other):
        if self.coef * other.coef == -1:
            return True
        else:
            return False
        
    def intersectDC(self, cercle):
        from sympy import Symbol, solve
        x = Symbol('x')
        y = Symbol('y')
        solutions = []
        if self.coef != None:
            self.a = self.coef
            self.b = -1
            self.c = self.ord
            temp_sol_x = solve( (x-cercle.centre.x)**2 + (-self.c/self.b-(self.a/self.b)*x-cercle.centre.y)**2-cercle.rayon**2)
            # on construit la liste des solutions réelles
            sol_x = []
            for sol in temp_sol_x:
                if sol.is_real != False:
                    sol_x.append(sol)
            #--->
            if len(sol_x) != 0:
                for sol in sol_x:
                    solutions.append( (sol , (-self.c-self.a*sol)/self.b) )
                    
        else: # si la droite est verticale
            temp_sol_y = solve( (self.abscisse-cercle.centre.x)**2 + (y-cercle.centre.y)**2-cercle.rayon**2 , y )
            for sol in temp_sol_y:
                solutions.append((self.abscisse,sol))
        
        return solutions
            
    
"""
Cercle
"""

class Cercle:
    def __init__(self,centre,rayon):
        self.centre = centre
        self.rayon = rayon
        
    def __str__(self):
        if self.centre.x < 0:
            rx = '(x + {})²' . format( abs(self.centre.x) )
        elif self.centre.x > 0:
            rx = '(x - {})²' . format( self.centre.x )
        else:
            rx = 'x²'
            
        if self.centre.y < 0:
            ry = '(y + {})²' . format( abs(self.centre.y) )
        elif self.centre.y > 0:
            ry = '(y - {})²' . format( self.centre.y )
        else:
            ry = 'y²'
            
        return rx + ' + ' + ry + ' = {}'.format(self.rayon**2)
        
    def __eq__(self,other):
        if self.centre == other.centre and self.rayon == other.rayon:
            return True
        else:
            return False
        
    def __hash__(self):
        return hash(self.centre.x * self.centre.y) ^ hash(self.rayon)
    
    def is_tgt(self,other):
        d = Vecteur(self.centre , other.centre).norme # distance entre les deux centres
        if self.rayon + other.rayon == d:
            return True
        else:
            return False
        
    def intersectCC(self,other):
        from sympy import Symbol, solve
        x = Symbol('x')
        solutions = [ ] # liste des solutions (coordonnées)
        if self.centre.y != other.centre.y:
            temp_sol_x = solve( (x-self.centre.x)**2 + ( (self.centre.x - other.centre.x)*x/(-self.centre.y+other.centre.y)+(other.centre.x**2+other.centre.y**2-other.rayon**2-self.centre.x**2-self.centre.y**2+self.rayon**2)/(2*(other.centre.y-self.centre.y))-self.centre.y)**2-self.rayon**2 )
            # on construit la liste des solutions réelles
            for sol in temp_sol_x:
                if sol.is_real != False:
                    solutions.append( (sol , (self.centre.x-other.centre.x)*sol/(other.centre.y-self.centre.y)+(other.centre.x**2+other.centre.y**2-other.rayon**2-self.centre.x**2-self.centre.y**2+self.rayon**2)/(2*(other.centre.y-self.centre.y)) ) )
        
        else:
            sol_x = solve( (x-self.centre.x)**2 - (x-other.centre.x)**2 - self.rayon**2 + other.rayon**2 )
            if len(sol_x) != 0:
                if self.rayon**2 - ( sol_x[0]-self.centre.x )**2 >= 0:
                    solutions.append( ( sol_x[0] , ( self.rayon**2 - ( sol_x[0]-self.centre.x )**2 )**0.5 + self.centre.y ) )
                    if ( self.rayon**2 - ( sol_x[0]-self.centre.x )**2 )**0.5 + self.centre.y != -( self.rayon**2 - ( sol_x[0]-self.centre.x )**2 )**0.5 + self.centre.y:
                        solutions.append( ( sol_x[0] , -( self.rayon**2 - ( sol_x[0]-self.centre.x )**2 )**0.5 + self.centre.y ) )
        
        return solutions
    
"""
Intersections
"""

def inter(obj1, obj2):
    if ( (isinstance(obj1,Droite) and isinstance(obj2,Droite)) or (isinstance(obj1,Cercle) and isinstance(obj2,Cercle)) ) and obj1 == obj2:
        return 'Objets identiques'
    else:
        if isinstance(obj1,Droite) and isinstance(obj2,Droite):
            if obj1.is_parallel(obj2,strict=True):
                return 'Les deux droites sont strictement parallèles'
            else:
                abscisse = (obj2.ord - obj1.ord)/(obj1.coef - obj2.coef)
                ordonnee = obj1.coef * abscisse + obj1.ord
                return (abscisse,ordonnee)
        elif isinstance(obj1,Cercle) and isinstance(obj2,Cercle):
            if obj1.centre == obj2.centre:
                return [ ] # deux cercles de même centre mais de rayon différents
            else:
                return obj1.intersectCC(obj2)
        elif isinstance(obj1,Droite) and isinstance(obj2,Cercle):
            return obj1.intersectDC(obj2)
        elif isinstance(obj1,Cercle) and isinstance(obj2,Droite):
            return obj2.intersectDC(obj1)
 
"""
"""

A = Point(-5,2)
B = Point(2,3)
C = Point(5,-5)
C1 = Cercle(A,3)
C2 = Cercle(B,5)
C3 = Cercle(C,1)
D1 = Droite(A,B)
print('Intersection de C1 et C2')
print( inter(C1,C2) )
print('Intersection de C1 et C3')
print( inter(C1,C3) )
print('Intersection de C1 et D1')
print( inter(D1,C1) )
print('Intersection de C2 et D1')
print( inter(D1,C2) )
print('Intersection de C3 et D1')
print( inter(D1,C3) )

