Package py3d
Module py3D, pour gérer la géométrie 3D en python
Expand source code
"""Module py3D, pour gérer la géométrie 3D en python
"""
import sys, os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from droites import *
from plans import *
from points import *
from repere import *
from utils import *
from vecteurs import *
from calculs import *
__all__ = ("Droite", "axe_x", "axe_y", "axe_z", "parallelles", "secantes", "orthogonales",
"Plan", "plan_xy", "plan_yz", "plan_xz",
"Point", "origine", "distance", "est_meme_point", "alignes",
"Repere3D",
"MIN_DELTA", "CHIFFRES_SIGNIFICATIFS",
"Vecteur", "vecteur_unitaire_x", "vecteur_unitaire_y", "vecteur_unitaire_z", "vecteur_nul", "collineaires", "orthogonaux",
"intersection", "intersection_plan_plan", "intersection_droite_plan", "intersection_droite_droite")
Sub-modules
py3d.calculs
-
Module calculs, contient des fonctions permettant de calculer les intersections entre divers objets
py3d.droites
-
Module droites, contient la classe Droite et des fonctions annexes …
py3d.plans
-
Module plans, contient la classe Plan et des fonctions annexes …
py3d.points
-
Module points, contient la classe Point et des fonctions annexes …
py3d.repere
-
Module repere, contient le nécessaire pour l'affichage dans un repère 3D
py3d.utils
-
Module utils : contient des variables globales (WIP) …
py3d.vecteurs
-
Module vecteurs, contient la classe Vecteur et des fonctions annexes …
Functions
def alignes(pointA, pointB, *args)
-
Renvoie True si les points sont alignés, False sinon
Args
Returns
bool
- Points tous alignés ?
Raises
TypeError
- Si les objets donnés ne sont pas tous des points
Expand source code
def alignes(pointA, pointB, *args): """Renvoie True si les points sont alignés, False sinon Args: pointA (Point): Point A pointB (Point): Point B *args: Autres points Returns: bool: Points tous alignés ? Raises: TypeError: Si les objets donnés ne sont pas tous des points """ if isinstance(pointA, Point) and isinstance(pointB, Point): for pointX in args: if isinstance(pointX, Point): if ((pointX.y - pointB.y)*(pointB.x - pointA.x) != (pointB.y - pointA.y)*(pointX.x - pointB.x)): return False else: typeA = pointA.__class__.__name__ typeB = pointX.__class__.__name__ raise TypeError(f"Impossible de déterminer la collinéarité de points entre [{typeA}] et [{typeB}]") return True else: typeA = pointA.__class__.__name__ typeB = pointB.__class__.__name__ raise TypeError(f"Impossible de déterminer la colinéarité entre [{typeA}] et [{typeB}]")
def collineaires(u, *args)
-
Renvoie True si les vecteurs donnés sont collinéaires, False sinon
Args
u
:Vecteur
- Vecteur de référence
*args
- Autres vecteurs
Returns
bool
- Tous les vecteurs collinéaires ?
Raises
TypeError
- Si les objets donnés ne sont pas tous des vecteurs
Expand source code
def collineaires(u, *args): """Renvoie True si les vecteurs donnés sont collinéaires, False sinon Args: u (Vecteur): Vecteur de référence *args: Autres vecteurs Returns: bool: Tous les vecteurs collinéaires ? Raises: TypeError: Si les objets donnés ne sont pas tous des vecteurs """ if isinstance(u, Vecteur): for v in args: if isinstance(v, Vecteur): if abs(abs(u.scalaire(v)) - u.norme() * v.norme()) >= 1/10*10: return False else: typeA = u.__class__.__name__ typeB = v.__class__.__name__ raise TypeError(f"Impossible de déterminer la colinéarité entre [{typeA}] et [{typeB}]") return True else: typeA = u.__class__.__name__ typeB = v.__class__.__name__ raise TypeError(f"Impossible de déterminer la colinéarité entre [{typeA}] et [{typeB}]")
def distance(pointA, pointB)
-
Donne la distance entre deux points
Args
Returns
float
- Distance entre A et B
Raises
TypeError
- Si A ou B n'est pas un point
Expand source code
def distance(pointA, pointB): """Donne la distance entre deux points Args: pointA (Point): Point A pointB (Point): Point B Returns: float: Distance entre A et B Raises: TypeError: Si A ou B n'est pas un point """ if isinstance(pointA, Point) and isinstance(pointB, Point): return sqrt((pointB.x - pointA.x)**2 + (pointB.y - pointA.y)**2 + (pointB.z - pointA.z)**2) else: typeA = pointA.__class__.__name__ typeB = pointB.__class__.__name__ raise TypeError(f"Impossible de calculer la distance entre un [{typeA}] et [{typeB}]")
def est_meme_point(pointA, pointB)
-
Renvoie True si les deux points sont au même endroit, False sinon
Args
Returns
bool
- A et B au même endroit ?
Expand source code
def est_meme_point(pointA, pointB): """Renvoie True si les deux points sont au même endroit, False sinon Args: pointA (Point): Point A pointB (Point): Point B Returns: bool: A et B au même endroit ? """ return distance(pointA, pointB) == 0
def intersection(ObjetA, ObjetB)
-
Sert de fonction tampon pour renvoyer l'intersection entre A et B
Voir les fonctions intersection_droite_droite(), intersection_plan_plan() et intersection_droite_plan()
Expand source code
def intersection(ObjetA, ObjetB): """Sert de fonction tampon pour renvoyer l'intersection entre A et B Voir les fonctions intersection_droite_droite(), intersection_plan_plan() et intersection_droite_plan() """ if isinstance(ObjetA, droites.Droite): if isinstance(ObjetB, droites.Droite): if droites.secantes(ObjetA, ObjetB): return intersection_droite_droite(ObjetA, ObjetB) else: return None elif isinstance(ObjetB, plans.Plan): if droites.secante_plan(ObjetA, ObjetB): return intersection_droite_plan(ObjetA, ObjetB) else: return None else: typeA = ObjetA.__class__.__name__ typeB = ObjetB.__class__.__name__ raise TypeError(f"Impossible de déterminer l'intersection entre [{typeA}] et [{typeB}]") elif isinstance(ObjetA, plans.Plan): if isinstance(ObjetB, droites.Droite): if droites.secante_plan(ObjetB, ObjetA): return intersection_droite_plan(ObjetB, ObjetA) else: return None elif isinstance(ObjetB, plans.Plan): if plans.secants(ObjetA, ObjetB): return intersection_plan_plan(ObjetA, ObjetB) else: return None else: return None
def intersection_droite_droite(droiteA, droiteB)
-
Renvoie le point d'intersection entre les droites si elles sont sécantes None sinon
Args
Returns
Point
- Point d'intersection entre A et B
Utilisée via la fonction intersection()
Expand source code
def intersection_droite_droite(droiteA, droiteB): """Renvoie le point d'intersection entre les droites si elles sont sécantes None sinon Args: droiteA (Droite): Droite A droiteB (Droite): Droite B Returns: Point: Point d'intersection entre A et B Utilisée via la fonction intersection() """ v = droiteA.vecteur v2 = droiteB.vecteur p = droiteA.point p2 = droiteB.point v3 = vecteurs.Vecteur(p, p2).produit_vectoriel(v2) v4 = v.produit_vectoriel(v2) scalaire = v4.scalaire(v4) if scalaire == 0: return None alpha = v3.scalaire(v4) / scalaire point = points.Point(droiteA.point.x + alpha * droiteA.vecteur.x, droiteA.point.y + alpha * droiteA.vecteur.y, droiteA.point.z + alpha * droiteA.vecteur.z) return point
def intersection_droite_plan(droite, plan)
-
Renvoie le point d'intersection entre la droite et le plan si ils sont sécants None sinon
Args
Returns
Point
- Point d'intersection entre la droite et le plan
Utilisée via la fonction intersection()
Expand source code
def intersection_droite_plan(droite, plan): """Renvoie le point d'intersection entre la droite et le plan si ils sont sécants None sinon Args: droite (Droite): Droite plan (Plan): Plan Returns: Point: Point d'intersection entre la droite et le plan Utilisée via la fonction intersection() """ p = droite.point v = droite.vecteur dot1 = plan.vecteur_n.scalaire(vecteurs.Vecteur(p.x, p.y, p.z)) dot2 = plan.vecteur_n.scalaire(v) if dot2 == 0: return None d = plan.cartesienne()[1][-1] t = -(dot1 - d) / dot2 return points.Point(p.x + (v.x*t), p.y + (v.y*t), p.z + (v.z*t))
def intersection_plan_plan(planA, planB)
-
Renvoie la droite d'intersection entre les plans si ils sont sécantes None sinon
Args
Returns
Droite
- Droite d'intersection entre A et B
Utilisée via la fonction intersection()
Expand source code
def intersection_plan_plan(planA, planB): """Renvoie la droite d'intersection entre les plans si ils sont sécantes None sinon Args: planA (Plan): Plan A planA (Plan): Plan B Returns: Droite: Droite d'intersection entre A et B Utilisée via la fonction intersection() """ equa_a = planA.cartesienne()[1] equa_b = planB.cartesienne()[1] vec_a = planA.vecteur_n vec_b = planB.vecteur_n vec_d = vec_a.produit_vectoriel(vec_b) if abs(vec_d.x) > MIN_DELTA: #X non nul -> on prend x = 0 x = 0 y, z = resoudre_cramer(equa_a, equa_b) elif abs(vec_d.y) > MIN_DELTA: #Y non nul -> on prend y = 0 y = 0 x, z = resoudre_cramer(equa_a, equa_b) else: #Z non nul -> on prend z = 0 z = 0 x, y = resoudre_cramer(equa_a, equa_b) point = points.Point(x, y, z) d = droites.Droite(point, vec_d) return d
def orthogonales(droite1, droite2)
-
Renvoie True si les droites données sont orthogonales, False sinon
Args
Returns
bool
- Droites orthogonales ?
Raises
TypeError
- Si les objets donnés ne sont pas tous des droites
Expand source code
def orthogonales(droite1, droite2): """Renvoie True si les droites données sont orthogonales, False sinon Args: droite1 (Droite): Droite 1 droite2 (Droite): Droite 2 Returns: bool: Droites orthogonales ? Raises: TypeError: Si les objets donnés ne sont pas tous des droites """ if isinstance(droite1, Droite): if isinstance(droite2, Droite): if secantes(droite1, droite2): if vecteurs.orthogonaux(droite1.vecteur, droite2.vecteur): return True return False else: typeA = droite1.__class__.__name__ typeB = droite2.__class__.__name__ raise TypeError(f"Impossible de déterminer l'intersection entre [{typeA}] et [{typeB}]") else: typeA = droite1.__class__.__name__ typeB = droite2.__class__.__name__ raise TypeError(f"Impossible de déterminer l'intersection entre [{typeA}] et [{typeB}]")
def orthogonaux(u, v)
-
Renvoie True si les vecteurs donnés sont orthogonaux, False sinon
Args
Returns
bool
- Tous les vecteurs orthogonaux ?
Raises
TypeError
- Si les objets donnés ne sont pas tous des vecteurs
Expand source code
def orthogonaux(u, v): """Renvoie True si les vecteurs donnés sont orthogonaux, False sinon Args: u (Vecteur): Vecteur de référence v (Vecteur): Autre vecteur Returns: bool: Tous les vecteurs orthogonaux ? Raises: TypeError: Si les objets donnés ne sont pas tous des vecteurs """ if isinstance(u, Vecteur) and isinstance(v, Vecteur): if u.scalaire(v) == 0: return True return False else: typeA = u.__class__.__name__ typeB = v.__class__.__name__ raise TypeError(f"Impossible de déterminer l'orthogonalité entre [{typeA}] et [{typeB}]")
def parallelles(d, *args)
-
Renvoie True si les droites données sont parallèles, False sinon
Args
d
:Droite
- Droite de référence
*args
- Autres droites
Returns
bool
- Droites toutes parallèles ?
Raises
TypeError
- Si les objets donnés ne sont pas tous des droites
Expand source code
def parallelles(d, *args): """Renvoie True si les droites données sont parallèles, False sinon Args: d (Droite): Droite de référence *args: Autres droites Returns: bool: Droites toutes parallèles ? Raises: TypeError: Si les objets donnés ne sont pas tous des droites """ if isinstance(d, Droite): for d2 in args: if isinstance(d2, Droite): if not(vecteurs.collineaires(d.vecteur, d2.vecteur)): return False else: typeA = u.__class__.__name__ typeB = v.__class__.__name__ raise TypeError(f"Impossible de déterminer le parallélisme entre [{typeA}] et [{typeB}]") return True else: typeA = u.__class__.__name__ v = args[0] typeB = v.__class__.__name__ raise TypeError(f"Impossible de déterminer le parallélisme entre [{typeA}] et [{typeB}]")
def secantes(d, *args)
-
Renvoie True si les droites données sont sécantes, False sinon
Args
d
:Droite
- Droite de référence
*args
- Autres droites
Returns
bool
- Droites toutes sécantes ?
Raises
TypeError
- Si les objets donnés ne sont pas tous des droites
Expand source code
def secantes(d, *args): """Renvoie True si les droites données sont sécantes, False sinon Args: d (Droite): Droite de référence *args: Autres droites Returns: bool: Droites toutes sécantes ? Raises: TypeError: Si les objets donnés ne sont pas tous des droites """ if isinstance(d, Droite): for d2 in args: if isinstance(d2, Droite): produit = d.vecteur.produit_vectoriel(d2.vecteur) vect_deplacement = vecteurs.Vecteur(d.point, d2.point) if produit.scalaire(vect_deplacement) != 0: return False else: typeA = d.__class__.__name__ typeB = d2.__class__.__name__ raise TypeError(f"Impossible de déterminer l'intersection entre [{typeA}] et [{typeB}]") return True else: typeA = d.__class__.__name__ d2 = args[0] typeB = d2.__class__.__name__ raise TypeError(f"Impossible de déterminer l'intersection entre [{typeA}] et [{typeB}]")
Classes
class Droite (*args)
-
Classe représentant une droite de l'espace
Attributes
Initialisation de la droite
- Deux points - Un point + un vecteur
Args
*args
- Arguments de définition de la droite
Raises
TypeError
- Les types passés sont incorrects
ValueError
- Les deux points son identiques ou le vecteur directeur est nul
Expand source code
class Droite: """Classe représentant une droite de l'espace Attributes: point (points.Point): Un point appartenant à la droite vecteur (vecteurs.Vecteur): Vecteur directeur de la droite """ def __init__(self, *args): """Initialisation de la droite - Deux points - Un point + un vecteur Args: *args: Arguments de définition de la droite Raises: TypeError: Les types passés sont incorrects ValueError: Les deux points son identiques ou le vecteur directeur est nul """ self.point = None self.vecteur = None if len(args) == 2: a, b = args if isinstance(a, points.Point) and isinstance(b, points.Point): if not points.est_meme_point(a, b): u = vecteurs.Vecteur(a, b) self.vecteur = u self.point = a else: raise ValueError("Les deux points ne doivent pas être identiques") elif isinstance(a, points.Point) and isinstance(b, vecteurs.Vecteur): if not b.est_nul(): self.point = a self.vecteur = b else: raise ValueError("Le vecteur directeur ne doit pas être nul") else: raise TypeError(f"Une droite est créée à partir de deux points, ou d'un point et d'un vecteur") else: raise TypeError(f"Une droite est créée à partir de deux points, ou d'un point et d'un vecteur") def est_sur_droite(self, point): """Renvoie True si le point est sur la droite, False sinon Args: point (points.Point): Point quelconque Returns: bool: Point sur la droite ? Raises: TypeError: Si l'objet donné n'est pas un point """ if isinstance(point, point.Point): pointA = self.point pointB = points.Point(pointA.x + self.vecteur.x, pointA.y + self.vecteur.y, pointA.z + self.vecteur.z) return bool(points.alignes(pointA, pointB, point)) type_ = point.__class__.__name__ raise TypeError(f"Impossible de déterminer l'appartenance entre droite et [{type_}]") def parametrique(self): """Renvoie l'équation paramétrique de la droite, et les coefficients dans un tuple Returns: tuple: - Equation paramétrique (str) - Tuple avec les coefficients xp, yp, zp, xu, yu, zu pour \\begin{equation} x= xp + x\\overrightarrow{u} \\end{equation} \\begin{equation} y= y + y\\overrightarrow{u} \\end{equation} \\begin{equation} z= zp + z\\overrightarrow{u} \\end{equation} """ xp = Fraction(str(self.point.x)) yp = Fraction(str(self.point.y)) zp = Fraction(str(self.point.z)) xu = Fraction(str(self.vecteur.x)) yu = Fraction(str(self.vecteur.y)) zu = Fraction(str(self.vecteur.z)) signe_xu = "+ " if xu >= 0 else "" signe_yu = "+ " if yu >= 0 else "" signe_zu = "+ " if zu >= 0 else "" str_parametrique = f"x = {xp} {signe_xu}{xu}t\ny = {yp} {signe_yu}{yu}t\nz = {zp} {signe_zu}{zu}t" return (str_parametrique, (xp, yp, zp, xu, yu, zu)) def __contains__(self, point): return self.est_sur_droite(point) def __str__(self): return self.paramétrique[0] def __repr__(self): return self.paramétrique[0]
Methods
def est_sur_droite(self, point)
-
Renvoie True si le point est sur la droite, False sinon
Args
point
:Point
- Point quelconque
Returns
bool
- Point sur la droite ?
Raises
TypeError
- Si l'objet donné n'est pas un point
Expand source code
def est_sur_droite(self, point): """Renvoie True si le point est sur la droite, False sinon Args: point (points.Point): Point quelconque Returns: bool: Point sur la droite ? Raises: TypeError: Si l'objet donné n'est pas un point """ if isinstance(point, point.Point): pointA = self.point pointB = points.Point(pointA.x + self.vecteur.x, pointA.y + self.vecteur.y, pointA.z + self.vecteur.z) return bool(points.alignes(pointA, pointB, point)) type_ = point.__class__.__name__ raise TypeError(f"Impossible de déterminer l'appartenance entre droite et [{type_}]")
def parametrique(self)
-
Renvoie l'équation paramétrique de la droite, et les coefficients dans un tuple
Returns: tuple: - Equation paramétrique (str) - Tuple avec les coefficients xp, yp, zp, xu, yu, zu pour
\begin{equation} x= xp + x\overrightarrow{u} \end{equation}
\begin{equation} y= y + y\overrightarrow{u} \end{equation}
\begin{equation} z= zp + z\overrightarrow{u} \end{equation}
Expand source code
def parametrique(self): """Renvoie l'équation paramétrique de la droite, et les coefficients dans un tuple Returns: tuple: - Equation paramétrique (str) - Tuple avec les coefficients xp, yp, zp, xu, yu, zu pour \\begin{equation} x= xp + x\\overrightarrow{u} \\end{equation} \\begin{equation} y= y + y\\overrightarrow{u} \\end{equation} \\begin{equation} z= zp + z\\overrightarrow{u} \\end{equation} """ xp = Fraction(str(self.point.x)) yp = Fraction(str(self.point.y)) zp = Fraction(str(self.point.z)) xu = Fraction(str(self.vecteur.x)) yu = Fraction(str(self.vecteur.y)) zu = Fraction(str(self.vecteur.z)) signe_xu = "+ " if xu >= 0 else "" signe_yu = "+ " if yu >= 0 else "" signe_zu = "+ " if zu >= 0 else "" str_parametrique = f"x = {xp} {signe_xu}{xu}t\ny = {yp} {signe_yu}{yu}t\nz = {zp} {signe_zu}{zu}t" return (str_parametrique, (xp, yp, zp, xu, yu, zu))
class Plan (*args)
-
Classe représentant un plan de l'espace
Attributes
Initialisation du plan :
- Un point + un vecteur normal - Deux droites - Un point + deux vecteurs non colinéaires - Trois points
Args
*args
- Arguments de définition du plan
Raises
TypeError
- Les types passés sont incorrects
ValueError
- Le vecteur normal est nul, les deux vecteurs sont colinéaires ou les trois points sont alignés
Expand source code
class Plan: """Classe représentant un plan de l'espace Attributes: point (points.Point): Point d'origine du plan vecteur_n (vecteurs.Vecteur): Vecteur normal au plan """ def __init__(self, *args): """Initialisation du plan : - Un point + un vecteur normal - Deux droites - Un point + deux vecteurs non colinéaires - Trois points Args: *args: Arguments de définition du plan Raises: TypeError: Les types passés sont incorrects ValueError: Le vecteur normal est nul, les deux vecteurs sont colinéaires ou les trois points sont alignés """ import points if len(args) == 2: a, b = args #Point + Vecteur Normal if isinstance(a, points.Point) and isinstance(b, vecteurs.Vecteur): if not b.est_nul(): self.point = a self.vecteur_n = b else: raise ValueError("Le vecteur normal d'un plan ne peut pas être nul") #Deux droites elif isinstance(a, droites.Droite) and isinstance(b, droites.Droite): self.point = calculs.intersection(a, b) self.vecteur_n = a.vecteur.produit_vectoriel(b.vecteur) else: typeA = a.__class__.__name__ typeB = b.__class__.__name__ raise TypeError(f"Impossible de créer un plan à partir de [{typeA}] et [{typeB}]") elif len(args) == 3: a, b ,c = args #Point + Deux vecteurs if isinstance(a, points.Point) and (b, vecteurs.Vecteur) and isinstance(c, vecteurs.Vecteur): if not(b.est_nul() or c.est_nul()): if not vecteurs.collineaires(b, c): self.vecteur_n = b.produit_vectoriel(c) self.point = a else: raise ValueError("Deux vecteurs collinéaires ne peuvent pas engendrer un plan") else: raise ValueError("Impossible de générer un plan à partir d'un vecteur nul") #Trois points elif all(isinstance(x, points.Point) for x in args): ab = vecteurs.Vecteur(a, b) ac = vecteurs.Vecteur(b, c) if not(ab.est_nul() or ac.est_nul()): if not vecteurs.collineaires(ab, ac): self.vecteur_n = ab.produit_vectoriel(ac) self.point = a else: raise ValueError("Trois points alignés ne peuvent pas engendrer un plan") else: raise ValueError("Impossible de générer un plan : les points ne sont pas distincts") else: typeA = a.__class__.__name__ typeB = b.__class__.__name__ typeC = c.__class__.__name__ raise TypeError(f"Impossible de créer un plan à partir de [{typeA}], [{typeB}] et [{typeC}]") elif len(args) == 4: pass a, b, c, d = args #Equation cartesienne if all(isinstance(x, int) or isinstance(x, float) for x in args): if not(a == 0 and b == 0 and c == 0): self.vecteur_n = vecteurs.Vecteur(a, b, c) if c != 0: self.point = points.Point(0, 0, -d/c) elif b != 0: self.point = points.Point(0, -d/b, 0) elif a != 0: self.point = points.Point(-d/a, 0, 0) else: raise ValueError("Impossible de générer un plan à partir d'un vecteur nul") else: raise TypeError("Les paramètres de l'équation cartésienne doivent être des chiffres") def cartesienne(self): """Renvoie l'équation cartésienne du plan, et les coefficients dans un tuple Returns: tuple: - Equation cartésienne (str) - Tuple avec les coefficients a b c d pour `ax + by + cz + d = 0` """ a = self.vecteur_n.x b = self.vecteur_n.y c = self.vecteur_n.z signe_b = "+ " if b >= 0 else "" signe_c = "+ " if c >= 0 else "" total_p = a * self.point.x + b * self.point.y + c * self.point.z d = -total_p signe_d = "+ " if d >= 0 else "" str_equation = f"{a}x {signe_b}{b}y {signe_c}{c}z {signe_d}{d} = 0" return (str_equation, (a, b, c, d)) def vecteur_normal(self): """Renvoie le vecteur normal au plan Returns: vecteurs.Vecteur: Vecteur normal """ return self.vecteur_n def __contains__(self, point): if isinstance(point, points.Point): projete = point.projete_orthogonal(self) return points.est_meme_point(point, projete) def __str__(self): return self.cartesienne()[0] def __repr__(self): return self.cartesienne()[0]
Methods
def cartesienne(self)
-
Renvoie l'équation cartésienne du plan, et les coefficients dans un tuple
Returns
tuple:
-
Equation cartésienne (str)
-
Tuple avec les coefficients a b c d pour
ax + by + cz + d = 0
Expand source code
def cartesienne(self): """Renvoie l'équation cartésienne du plan, et les coefficients dans un tuple Returns: tuple: - Equation cartésienne (str) - Tuple avec les coefficients a b c d pour `ax + by + cz + d = 0` """ a = self.vecteur_n.x b = self.vecteur_n.y c = self.vecteur_n.z signe_b = "+ " if b >= 0 else "" signe_c = "+ " if c >= 0 else "" total_p = a * self.point.x + b * self.point.y + c * self.point.z d = -total_p signe_d = "+ " if d >= 0 else "" str_equation = f"{a}x {signe_b}{b}y {signe_c}{c}z {signe_d}{d} = 0" return (str_equation, (a, b, c, d))
-
def vecteur_normal(self)
-
Expand source code
def vecteur_normal(self): """Renvoie le vecteur normal au plan Returns: vecteurs.Vecteur: Vecteur normal """ return self.vecteur_n
class Point (x=0, y=0, z=0)
-
Classe représentant un point de l'espace
Attributes
x
:float
- Coordonnée X
y
:float
- Coordonnée Y
z
:float
- Coordonnée Z
Initialisation du point
Args
x
:float
- Coordonnée X
y
:float
- Coordonnée Y
z
:float
- Coordonnée Z
Expand source code
class Point(): """Classe représentant un point de l'espace Attributes: x (float): Coordonnée X y (float): Coordonnée Y z (float): Coordonnée Z """ def __init__(self, x=0 , y=0, z=0): """Initialisation du point Args: x (float): Coordonnée X y (float): Coordonnée Y z (float): Coordonnée Z """ self.x = x self.y = y self.z = z def distance_origine(self): """Donne la distance à l'origine Returns: float: Distance entre le point et l'origine """ return (distance(self, Point(0, 0, 0))) def projete_orthogonal(self, *args): """Donne le projeté orthogonal du point sur une droite ou un plan Returns: Point: Projeté orthogonal """ if args[0] != None: if isinstance(args[0], droites.Droite): droite = args[0] vec = droite.vecteur a = droite.point b = Point( droite.point.x + droite.vecteur.x, droite.point.y + droite.vecteur.y, droite.point.z + droite.vecteur.z) ab = vecteurs.Vecteur(a, b) ap = vecteurs.Vecteur(a, self) modif_vecteur = (ap.scalaire(ab) / ab.scalaire(ab)) * ab return Point(a.x + modif_vecteur.x, a.y + modif_vecteur.y, a.z + modif_vecteur.z) import plans if isinstance(args[0], plans.Plan): plan = args[0] vec = vecteurs.Vecteur(plan.point, self) distance = plan.vecteur_n.scalaire(vec) difference = distance * plan.vecteur_n return Point(self.x - difference.x, self.y - difference.y, self.z - difference.z) else: raise TypeError(f"On ne peut projeter un point que sur une droite ou un plan") else: raise TypeError(f"Il faut un objet sur lequel projeter le point") def __str__(self): return f'Point({self.x}, {self.y}, {self.z})' def __repr__(self): return f'Point({self.x}, {self.y}, {self.z})'
Methods
def distance_origine(self)
-
Donne la distance à l'origine
Returns
float
- Distance entre le point et l'origine
Expand source code
def distance_origine(self): """Donne la distance à l'origine Returns: float: Distance entre le point et l'origine """ return (distance(self, Point(0, 0, 0)))
def projete_orthogonal(self, *args)
-
Expand source code
def projete_orthogonal(self, *args): """Donne le projeté orthogonal du point sur une droite ou un plan Returns: Point: Projeté orthogonal """ if args[0] != None: if isinstance(args[0], droites.Droite): droite = args[0] vec = droite.vecteur a = droite.point b = Point( droite.point.x + droite.vecteur.x, droite.point.y + droite.vecteur.y, droite.point.z + droite.vecteur.z) ab = vecteurs.Vecteur(a, b) ap = vecteurs.Vecteur(a, self) modif_vecteur = (ap.scalaire(ab) / ab.scalaire(ab)) * ab return Point(a.x + modif_vecteur.x, a.y + modif_vecteur.y, a.z + modif_vecteur.z) import plans if isinstance(args[0], plans.Plan): plan = args[0] vec = vecteurs.Vecteur(plan.point, self) distance = plan.vecteur_n.scalaire(vec) difference = distance * plan.vecteur_n return Point(self.x - difference.x, self.y - difference.y, self.z - difference.z) else: raise TypeError(f"On ne peut projeter un point que sur une droite ou un plan") else: raise TypeError(f"Il faut un objet sur lequel projeter le point")
class Repere3D
-
Classe Repere3D, représente le repère 3D
Initialisation du repère
Expand source code
class Repere3D: """Classe Repere3D, représente le repère 3D """ def __init__(self): """Initialisation du repère """ #Création du graphique self.fig = plt.figure() self.ax = self.fig.gca(projection='3d') def ajouter(self, objet, couleur=None, longueur=10, label="", grille=0): """Ajoute un objet dans le repère Args: objet : Objet (Point / Droite / Plan) à ajouter couleur (str, optionnel): Couleur à utiliser (en anglais) longueur (int, optionnel): Longueur totale sur chaque axe (pour les droites) label (str, optionnel): Label à attribuer à l'objet grille (int, optionnel): Mode "grillage", avec {grille} lignes et {grille} colonnes (pour les plans) """ longueur *= 5 if isinstance(objet, points.Point): if label == "": if couleur == None: self.ax.scatter(objet.x, objet.y, objet.z, marker="o") else: self.ax.scatter(objet.x, objet.y, objet.z, marker="o", couleur=couleur) else: if couleur == None: self.ax.scatter(objet.x, objet.y, objet.z, marker="o", label=label) else: self.ax.scatter(objet.x, objet.y, objet.z, marker="o", label=label, couleur=couleur) elif isinstance(objet, droites.Droite): #Droites en bleu par défaut couleur = "blue" if couleur == None else couleur x = [-(objet.point.x + objet.vecteur.x * longueur), objet.point.x + objet.vecteur.x * longueur] y = [-(objet.point.y + objet.vecteur.y * longueur), objet.point.y + objet.vecteur.y * longueur] z = [-(objet.point.z + objet.vecteur.z * longueur), objet.point.z + objet.vecteur.z * longueur] if label == "": self.ax.plot(x, y, z, couleur) else: self.ax.plot(x, y, z, couleur, label=label) elif isinstance(objet, plans.Plan): #Plans en orange par défaut couleur = "orange" if couleur == None else couleur longueur = int(longueur / 5) a, b, c, d = objet.cartesienne()[1] if c != 0: x = np.linspace(-longueur/2, longueur/2, longueur*10) y = np.linspace(-longueur/2, longueur/2, longueur*10) X, Y = np.meshgrid(x, y) Z = (d - a*X - b*Y) / c elif b != 0: x = np.linspace(-longueur/2, longueur/2, longueur*10) z = np.linspace(-longueur/2, longueur/2, longueur*10) X, Z = np.meshgrid(x, z) Y = (d - a*X - c*Z) / b else: y = np.linspace(-longueur/2, longueur/2, longueur*10) z = np.linspace(-longueur/2, longueur/2, longueur*10) Y, Z = np.meshgrid(y, z) X = (d - b*Y - c*Z) / a if grille != 0: #Mode grillage self.ax.plot_wireframe(X, Y, Z, color=couleur, alpha=0.6, rcount=grille, ccount=grille) else: self.ax.plot_surface(X, Y, Z, color=couleur, alpha=0.6) elif isinstance(objet, vecteurs.Vecteur): pass def dessiner_axes(self): """Ajoute les axes au repère """ #Ajout des axes self.ax.set_xlabel("Axe X") self.ax.set_ylabel("Axe Y") self.ax.set_zlabel("Axe Z") axe_x = droites.axe_x axe_y = droites.axe_y axe_z = droites.axe_z plt.quiver(axe_x.point.x, axe_x.point.y, axe_x.point.z, axe_x.vecteur.x, axe_x.vecteur.y, axe_x.vecteur.z, color="red") plt.quiver(axe_y.point.x, axe_y.point.y, axe_y.point.z, axe_y.vecteur.x, axe_y.vecteur.y, axe_y.vecteur.z, color="green") plt.quiver(axe_z.point.x, axe_z.point.y, axe_z.point.z, axe_z.vecteur.x, axe_z.vecteur.y, axe_z.vecteur.z, color="blue") def dessiner_origine(self): """Ajoute l'origine au repère """ #Origine en rouge self.ax.scatter(0, 0, 0, color="black", label="Origine") def corriger_min_axes(self): xlims = self.ax.get_xlim3d() ylims = self.ax.get_ylim3d() zlims = self.ax.get_zlim3d() if xlims[1] - xlims[0] <= 1: self.ax.set_xlim(-5, 5) if ylims[1] - ylims[0] <= 1: self.ax.set_ylim(-5, 5) if zlims[1] - zlims[0] <= 1: self.ax.set_zlim(-5, 5) def afficher(self): """Affiche le repère et la légende """ self.dessiner_axes() self.dessiner_origine() self.corriger_min_axes() self.ax.legend(framealpha=0.2) plt.show()
Methods
def afficher(self)
-
Affiche le repère et la légende
Expand source code
def afficher(self): """Affiche le repère et la légende """ self.dessiner_axes() self.dessiner_origine() self.corriger_min_axes() self.ax.legend(framealpha=0.2) plt.show()
def ajouter(self, objet, couleur=None, longueur=10, label='', grille=0)
-
Ajoute un objet dans le repère
Args
- objet : Objet (Point / Droite / Plan) à ajouter
couleur
:str, optionnel
- Couleur à utiliser (en anglais)
longueur
:int, optionnel
- Longueur totale sur chaque axe (pour les droites)
label
:str, optionnel
- Label à attribuer à l'objet
grille
:int, optionnel
- Mode "grillage", avec {grille} lignes et {grille} colonnes (pour les plans)
Expand source code
def ajouter(self, objet, couleur=None, longueur=10, label="", grille=0): """Ajoute un objet dans le repère Args: objet : Objet (Point / Droite / Plan) à ajouter couleur (str, optionnel): Couleur à utiliser (en anglais) longueur (int, optionnel): Longueur totale sur chaque axe (pour les droites) label (str, optionnel): Label à attribuer à l'objet grille (int, optionnel): Mode "grillage", avec {grille} lignes et {grille} colonnes (pour les plans) """ longueur *= 5 if isinstance(objet, points.Point): if label == "": if couleur == None: self.ax.scatter(objet.x, objet.y, objet.z, marker="o") else: self.ax.scatter(objet.x, objet.y, objet.z, marker="o", couleur=couleur) else: if couleur == None: self.ax.scatter(objet.x, objet.y, objet.z, marker="o", label=label) else: self.ax.scatter(objet.x, objet.y, objet.z, marker="o", label=label, couleur=couleur) elif isinstance(objet, droites.Droite): #Droites en bleu par défaut couleur = "blue" if couleur == None else couleur x = [-(objet.point.x + objet.vecteur.x * longueur), objet.point.x + objet.vecteur.x * longueur] y = [-(objet.point.y + objet.vecteur.y * longueur), objet.point.y + objet.vecteur.y * longueur] z = [-(objet.point.z + objet.vecteur.z * longueur), objet.point.z + objet.vecteur.z * longueur] if label == "": self.ax.plot(x, y, z, couleur) else: self.ax.plot(x, y, z, couleur, label=label) elif isinstance(objet, plans.Plan): #Plans en orange par défaut couleur = "orange" if couleur == None else couleur longueur = int(longueur / 5) a, b, c, d = objet.cartesienne()[1] if c != 0: x = np.linspace(-longueur/2, longueur/2, longueur*10) y = np.linspace(-longueur/2, longueur/2, longueur*10) X, Y = np.meshgrid(x, y) Z = (d - a*X - b*Y) / c elif b != 0: x = np.linspace(-longueur/2, longueur/2, longueur*10) z = np.linspace(-longueur/2, longueur/2, longueur*10) X, Z = np.meshgrid(x, z) Y = (d - a*X - c*Z) / b else: y = np.linspace(-longueur/2, longueur/2, longueur*10) z = np.linspace(-longueur/2, longueur/2, longueur*10) Y, Z = np.meshgrid(y, z) X = (d - b*Y - c*Z) / a if grille != 0: #Mode grillage self.ax.plot_wireframe(X, Y, Z, color=couleur, alpha=0.6, rcount=grille, ccount=grille) else: self.ax.plot_surface(X, Y, Z, color=couleur, alpha=0.6) elif isinstance(objet, vecteurs.Vecteur): pass
def corriger_min_axes(self)
-
Expand source code
def corriger_min_axes(self): xlims = self.ax.get_xlim3d() ylims = self.ax.get_ylim3d() zlims = self.ax.get_zlim3d() if xlims[1] - xlims[0] <= 1: self.ax.set_xlim(-5, 5) if ylims[1] - ylims[0] <= 1: self.ax.set_ylim(-5, 5) if zlims[1] - zlims[0] <= 1: self.ax.set_zlim(-5, 5)
def dessiner_axes(self)
-
Ajoute les axes au repère
Expand source code
def dessiner_axes(self): """Ajoute les axes au repère """ #Ajout des axes self.ax.set_xlabel("Axe X") self.ax.set_ylabel("Axe Y") self.ax.set_zlabel("Axe Z") axe_x = droites.axe_x axe_y = droites.axe_y axe_z = droites.axe_z plt.quiver(axe_x.point.x, axe_x.point.y, axe_x.point.z, axe_x.vecteur.x, axe_x.vecteur.y, axe_x.vecteur.z, color="red") plt.quiver(axe_y.point.x, axe_y.point.y, axe_y.point.z, axe_y.vecteur.x, axe_y.vecteur.y, axe_y.vecteur.z, color="green") plt.quiver(axe_z.point.x, axe_z.point.y, axe_z.point.z, axe_z.vecteur.x, axe_z.vecteur.y, axe_z.vecteur.z, color="blue")
def dessiner_origine(self)
-
Ajoute l'origine au repère
Expand source code
def dessiner_origine(self): """Ajoute l'origine au repère """ #Origine en rouge self.ax.scatter(0, 0, 0, color="black", label="Origine")
class Vecteur (*args)
-
Classe représentant un vecteur de l'espace
Attributes
x
:float
- Coordonnée x
y
:float
- Coordonnée y
z
:float
- Coordonnée z
Initialisation du vecteur
- Deux points - Trois coordonnées
Args
*args
- Arguments de définition du vecteur
Raises
TypeError
- Si les types donnés sont incorrectes
ValueError
- Si le nombre de paramètres ne correspond pas
Expand source code
class Vecteur(): """Classe représentant un vecteur de l'espace Attributes: x (float): Coordonnée x y (float): Coordonnée y z (float): Coordonnée z """ def __init__(self, *args): """Initialisation du vecteur - Deux points - Trois coordonnées Args: *args: Arguments de définition du vecteur Raises: TypeError: Si les types donnés sont incorrectes ValueError: Si le nombre de paramètres ne correspond pas """ if len(args) == 2: a, b = args if isinstance(a, points.Point) and isinstance(b, points.Point): self.x = b.x - a.x self.y = b.y - a.y self.z = b.z - a.z elif all(isinstance(coord, int) or isinstance(coord, float) for coord in args): a, b = args self.x = a self.y = b self.z = 0 else: typeA = a.__class__.__name__ typeB = b.__class__.__name__ raise TypeError(f"Impossible de créer un vecteur à partir de [{typeA}] et [{typeB}]") elif len(args) == 3: if all(isinstance(coord, int) or isinstance(coord, float) for coord in args): x, y ,z = args self.x = x self.y = y self.z = z else: raise TypeError("Les coordonnées d'un vecteur doivent être des nombres") else: raise ValueError("Un vecteur est créé à partir de deux points ou de coordonnées") def scalaire(self, vecteurB): """Renvoie le produit scalaire entre le vecteur et vecteurB Args: vecteurB (Vecteur): Vecteur à comparer Returns: float: Résultat du produit scalaire Raises: TypeError: Si vecteurB n'est pas un vecteur """ if isinstance(vecteurB, Vecteur): return self.x * vecteurB.x + self.y * vecteurB.y + self.z * vecteurB.z else: type_ = vecteurB.__class__.__name__ raise TypeError(f"Impossible de faire le produit scalaire entre [Vecteur] et [{type_}]") def produit_vectoriel(self, vecteurB): """Renvoie le produit vectoriel entre le vecteur et vecteurB Args: vecteurB (Vecteur): Vecteur à comparer Returns: float: Résultat du produit vectoriel Raises: TypeError: Si vecteurB n'est pas un vecteur """ x = (self.y * vecteurB.z) - (self.z * vecteurB.y) y = (self.z * vecteurB.x) - (self.x * vecteurB.z) z = (self.x * vecteurB.y) - (self.y * vecteurB.x) return Vecteur(x, y, z) def norme(self): """Donne la norme du vecteur Returns: float: Norme du vecteur """ return sqrt((self.x)**2 + (self.y)**2 + (self.z)**2) def absolue(self): """Donne la valeur absolue du vecteur Returns: float: Valeur absolue du vecteur """ return Vecteur(abs(self.x), abs(self.z), abs(self.z)) def normalise(self): """Donne la forme normalisée du vecteur Returns: Vecteur: Forme normalisée du vecteur """ return self * float(1 / self.norme()) def normal(self, *p): """Donne un vecteur normal à ce vecteur Returns: Vecteur: Vecteur normal Raises: NotImplementedError: Si le vecteur actuel n'a aucune coordonnée nulle """ if self.z == 0: return Vecteur(self.y, -self.x, 0) elif self.y == 0: return Vecteur(-self.z, 0, self.x) elif self.x == 0: return Vecteur(0, self.z, -self.y) else: p = p[0] if isinstance(p, points.Point): a = points.origine b = points.Point(self.x, self.y, self.z) projete = p.projete_orthogonal(droites.Droite(a, b)) return Vecteur(projete, p) else: raise TypeError("Il faut un point pour calculer un vecteur normal en 3D") def get_coordonnes(self): """Donne les coordonnées du vecteur dans un tuple Returns: tuple: Coordonnées (x, y, z) """ return (self.x, self.y, self.z) def est_nul(self): """Renvoie True si le vecteur est nul, False sinon Returns: bool: Vecteur nul ? """ return self.x == 0 and self.y == 0 and self.z == 0 def __add__(self, vecteurB): if isinstance(vecteurB, Vecteur): return Vecteur(self.x + vecteurB.x, self.y + vecteurB.y, self.z + vecteurB.z) else: type_ = vecteurB.__class__.__name__ raise TypeError(f"Impossible d'additioner [Vecteur] et [{type_}]") def __radd__(self, vecteurB): if vecteurB == 0: return self else: return self.__add__(vecteurB) def __neg__(self): return Vecteur(-self.x, -self.y, -self.z) def __sub__(self, vecteurB): return self.__add__(-vecteurB) def __rsub__(self, vecteurB): return self.__radd__(-vecteurB) def __mul__(self, valeur): if isinstance(valeur, int) or isinstance(valeur, float): return Vecteur(self.x * valeur, self.y * valeur, self.z * valeur) else: type_ = valeur.__class__.__name__ raise TypeError(f"Impossible de multiplier [Vecteur] et [{type_}]") def __rmul__(self, valeur): return self.__mul__(valeur) def __str__(self): return f"Vecteur ({self.x}, {self.y}, {self.z})" def __eq__(self, v): if isinstance(v, Vecteur): return self.x == v.x and self.y == v.y and self.z == v.z else: type_ = v.__class__.__name__ raise TypeError(f"Impossible de comparer [Vecteur] et [{type_}]")
Methods
def absolue(self)
-
Donne la valeur absolue du vecteur
Returns
float
- Valeur absolue du vecteur
Expand source code
def absolue(self): """Donne la valeur absolue du vecteur Returns: float: Valeur absolue du vecteur """ return Vecteur(abs(self.x), abs(self.z), abs(self.z))
def est_nul(self)
-
Renvoie True si le vecteur est nul, False sinon
Returns
bool
- Vecteur nul ?
Expand source code
def est_nul(self): """Renvoie True si le vecteur est nul, False sinon Returns: bool: Vecteur nul ? """ return self.x == 0 and self.y == 0 and self.z == 0
def get_coordonnes(self)
-
Donne les coordonnées du vecteur dans un tuple
Returns
tuple
- Coordonnées (x, y, z)
Expand source code
def get_coordonnes(self): """Donne les coordonnées du vecteur dans un tuple Returns: tuple: Coordonnées (x, y, z) """ return (self.x, self.y, self.z)
def normal(self, *p)
-
Donne un vecteur normal à ce vecteur
Returns
Vecteur
- Vecteur normal
Raises
NotImplementedError
- Si le vecteur actuel n'a aucune coordonnée nulle
Expand source code
def normal(self, *p): """Donne un vecteur normal à ce vecteur Returns: Vecteur: Vecteur normal Raises: NotImplementedError: Si le vecteur actuel n'a aucune coordonnée nulle """ if self.z == 0: return Vecteur(self.y, -self.x, 0) elif self.y == 0: return Vecteur(-self.z, 0, self.x) elif self.x == 0: return Vecteur(0, self.z, -self.y) else: p = p[0] if isinstance(p, points.Point): a = points.origine b = points.Point(self.x, self.y, self.z) projete = p.projete_orthogonal(droites.Droite(a, b)) return Vecteur(projete, p) else: raise TypeError("Il faut un point pour calculer un vecteur normal en 3D")
def normalise(self)
-
Expand source code
def normalise(self): """Donne la forme normalisée du vecteur Returns: Vecteur: Forme normalisée du vecteur """ return self * float(1 / self.norme())
def norme(self)
-
Donne la norme du vecteur
Returns
float
- Norme du vecteur
Expand source code
def norme(self): """Donne la norme du vecteur Returns: float: Norme du vecteur """ return sqrt((self.x)**2 + (self.y)**2 + (self.z)**2)
def produit_vectoriel(self, vecteurB)
-
Renvoie le produit vectoriel entre le vecteur et vecteurB
Args
vecteurB
:Vecteur
- Vecteur à comparer
Returns
float
- Résultat du produit vectoriel
Raises
TypeError
- Si vecteurB n'est pas un vecteur
Expand source code
def produit_vectoriel(self, vecteurB): """Renvoie le produit vectoriel entre le vecteur et vecteurB Args: vecteurB (Vecteur): Vecteur à comparer Returns: float: Résultat du produit vectoriel Raises: TypeError: Si vecteurB n'est pas un vecteur """ x = (self.y * vecteurB.z) - (self.z * vecteurB.y) y = (self.z * vecteurB.x) - (self.x * vecteurB.z) z = (self.x * vecteurB.y) - (self.y * vecteurB.x) return Vecteur(x, y, z)
def scalaire(self, vecteurB)
-
Renvoie le produit scalaire entre le vecteur et vecteurB
Args
vecteurB
:Vecteur
- Vecteur à comparer
Returns
float
- Résultat du produit scalaire
Raises
TypeError
- Si vecteurB n'est pas un vecteur
Expand source code
def scalaire(self, vecteurB): """Renvoie le produit scalaire entre le vecteur et vecteurB Args: vecteurB (Vecteur): Vecteur à comparer Returns: float: Résultat du produit scalaire Raises: TypeError: Si vecteurB n'est pas un vecteur """ if isinstance(vecteurB, Vecteur): return self.x * vecteurB.x + self.y * vecteurB.y + self.z * vecteurB.z else: type_ = vecteurB.__class__.__name__ raise TypeError(f"Impossible de faire le produit scalaire entre [Vecteur] et [{type_}]")