8.3. Calcul géométrique en 2D/3D#

Marc BUFFAT , Université Claude Bernard Lyon 1

%matplotlib inline
# bibliotheques de base
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'serif'
rcParams['font.size'] = 14

8.3.1. Objectif#

8.3.1.1. Base d’un module de CAO objet#

On se propose d’écrire des fonctions Python pour manipuler des éléments 2D (triangle, rectangle, cercle, ellipse, polygones, …).

Pour cela on va créer une petite bibliothèque en Python avec des classes.

8.3.2. Analyse#

  • élèments de base

    • données

    • méthodes

8.3.3. Algorithmes#

  - coordonnées barycentriques
  - surface, intersection

8.3.4. Calcul géométrique en 2D#

8.3.4.1. classe de base Point#

Créer une classe de base (Point) dans l’espace cartésion en 2D permettant de définir des points par leurs coordonnées (X,Y). Écrire des méthodes utiles par la suite (par exemple permettant de calculer la distance entre deux points, de l’afficher dans un plan, etc.).

8.3.4.2. classe générique Polygone#

définition

class Point:
    """classe de Point en 2D"""
    def __init__(self, x, y):
        """creation d'un point a partir de ces coordonnees x et y"""
        self.x = x
        self.y = y
        return
    def __str__(self):
        chaine = "point x={:5.2f} y={:5.2f}".format(self.x,self.y)
        return chaine
    def translation(self, dx, dy):
        self.x = self.x + dx
        self.y = self.y + dy
        return
    def plot(self):
        plt.plot([self.x],[self.y],'o',markersize=12)
        return
# calcul distance entre 2 pts
def distance(A,B):
    d = np.sqrt((B.x - A.x)**2 + (B.y - A.y)**2)
    return d
# test 
P = Point(13,14)
print(P)
P.translation(-5,-8)
print(P)
Q = Point(10,9)
print(distance(P,Q))
# tracer
P.plot()
Q.plot()
point x=13.00 y=14.00
point x= 8.00 y= 6.00
3.605551275463989
../../_images/0e383505e02c29c2f6da27baf775912bbb8dd4a9873f010b30c06d9c9ef233bc.png
# Polygone
class Polygone:
    def __init__(self, Lpts):
        self.Lpts = Lpts
        return
    def __str__(self):
        chaine = "polygone: {} ".format(len(self.Lpts))
        for P in self.Lpts:
            chaine = chaine + " , " +str(P)
        return chaine
    def translation(self, dx, dy):
        for P in self.Lpts:
            P.translation(dx,dy)
        return
    def plot(self):
        for P in self.Lpts:
            P.plot()
        X = []
        Y = []
        for P in self.Lpts:
            X.append(P.x)
            Y.append(P.y)
        X.append(X[0])
        Y.append(Y[0])
        plt.plot(X,Y)
        return
A = Point(0,0)
B = Point(1,0)
C = Point(0,1)
poly1 = Polygone([A,B,C])
print(poly1)
poly1.translation(2,0)
print(poly1)
# tracer
poly1.plot()
polygone: 3  , point x= 0.00 y= 0.00 , point x= 1.00 y= 0.00 , point x= 0.00 y= 1.00
polygone: 3  , point x= 2.00 y= 0.00 , point x= 3.00 y= 0.00 , point x= 2.00 y= 1.00
../../_images/d96e4390df5ce9f55e3d8093c74134374ac8c74f716c68c3137197347e75fbbb.png
class Triangle(Polygone):
    def __init__(self,A,B,C):
        self.Lpts = [A,B,C]
        return
T1 = Triangle(A,B,C)
print(T1)
T1.translation(0,1)
print(T1)
polygone: 3  , point x= 2.00 y= 0.00 , point x= 3.00 y= 0.00 , point x= 2.00 y= 1.00
polygone: 3  , point x= 2.00 y= 1.00 , point x= 3.00 y= 1.00 , point x= 2.00 y= 2.00
type(T1),type(poly1)
(__main__.Triangle, __main__.Polygone)

8.3.4.3. cas particulier de Triangle et Quadrangle#

Dans un premier temps, pour les éléments surfaciques de type triangle et quadrangle, écrire les fonctions qui calculent :

  1. la surface

  2. le périmètre

Chaque élément est défini par les coordonnées de ses points, donnés dans l’ordre trigonométrique. Montrez que ces fonctions utilisent des fonctions qui calculent :

  1. la longueur d’un segment

  2. la norme du produit vectoriel de 2 vecteurs

8.3.4.4. Généralisation: classe Figure#

  1. Créer une classe générique de base (figure), dont sera issue la sous-classe polygone. Créer les sous-classes ellipse et cercle avec les méthodes associées. Valider.

  2. Généraliser les algorithmes de calcul de surface au cas d’un polygone plan quelconque. Valider.

n.b. : on supposera que le polygone est donné par une liste de noeuds orientés dans le sens trigonométrique, et on note \((U,V)\) le repère dans le plan du polygone.

pour un polygone, on va calculer la somme des aires « signées » des trapèzes formés par deux des points des segments (p1, p2) du polygone et les projections de ces deux points sur l’axe des U. Le signe sera celui du produit scalaire \((P1\wedge P2) V\)

8.3.5. Implémentation#

class Point:
    """ classe de Point dans le plan """
    def __init__(self,x,y):
        self.x=x
        self.y=y
        return
    def __str__(self):
        s="(%g,%g)"%(self.x,self.y)
        return s
    def plot(self):
        """ trace d'un point """
        plt.plot(self.x,self.y,'o',markersize=10)
        return
    
# distance entre 2 points
def distance(P1,P2):
    """ calcul distance entre 2 points"""
    d=np.sqrt((P1.x-P2.x)**2+(P1.y-P2.y)**2)
    return d
class Polygone:
    """ Classe figure geometrique a partir de Points"""
    def __init__(self,L):
        """ constructeur a partir d'une liste de points """
        self.Pts=L
        return
    def __str__(self):
        s="figure "
        for P in self.Pts:
            s=s+": "+str(P)
        return s
    def plot(self):
        X=[p.x for p in self.Pts]
        Y=[p.y for p in self.Pts]
        X.append(X[0])
        Y.append(Y[0])
        plt.plot(X,Y,'-',lw=2)
        for P in self.Pts:
            P.plot()
        return
    def perimetre(self):
        np=len(self.Pts)
        dist=0.0;
        for i in range(np-1):
            dist += distance(self.Pts[i],self.Pts[i-1])
        dist += distance(self.Pts[-1],self.Pts[0]);
        return dist
    def translate(self,x0,y0):
        for P in self.Pts:
            P.x += x0
            P.y += y0
        return
    def rotate(self,x0,y0,theta):
        """ rotation avec angle en degre """
        angle=theta*pi/180.0;
        for P in self.Pts:
            x1 = x0 + (P.x-x0)*np.cos(angle)-(P.y-y0)*np.sin(angle)
            y1 = y0 + (P.x-x0)*np.sin(angle)+(P.y-y0)*np.cos(angle)
            P.x = x1
            P.y = y1
        return
# classe heritee triangle
class Triangle(Polygone):
    """Classe Triangle"""
    def __init__(self,P1,P2,P3):
        self.Pts=[P1,P2,P3]
        return
    def plot(self):
        X=[p.x for p in self.Pts]
        Y=[p.y for p in self.Pts]
        plt.fill(X,Y,'b')
        return

8.3.6. Validation#

# test
A=Point(0.,0.);
B=Point(1.,0.);
C=Point(1.,1.);
print("A:",A)
P=Polygone([A,B,C]);
T=Triangle(A,B,C)
#T=copy.deepcopy(Triangle(A,B,C))
print("P:",P)
print("perimetre ",P.perimetre())
P.translate(1,-2)
print("P:",P)
print("perimetre ",P.perimetre())
T.translate(-1,2)
print(T)
A: (0,0)
P: figure : (0,0): (1,0): (1,1)
perimetre  3.82842712474619
P: figure : (1,-2): (2,-2): (2,-1)
perimetre  3.82842712474619
figure : (0,0): (1,0): (1,1)
plt.figure(figsize=(12,10))
P.plot()
A.plot()
B.plot()
plt.axis('equal')
plt.xlim((-3,3.))
plt.ylim((-3,3.))

T.plot()
../../_images/e763f6b6dffdce1fbfd6f7b6967c821980dd4aa5b2fb75dc1abb1ebf66229206.png

8.3.7. FIN de la leçon#