Introduction aux classes

Ce notebook part d’une classe représentant un point en deux dimensions pour aller jusqu’au calcul de la surface d’un polygone quel qu’il soit. La plupart des réponses ont été guidées par LeChat.

[2]:
class Point2D:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point2D({self.x}, {self.y})"

    def __eq__(self, other):
        if isinstance(other, Point2D):
            return self.x == other.x and self.y == other.y
        return False

    def distance_to(self, other):
        """Calcule la distance entre deux points."""
        return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5

    @staticmethod
    def intersection_point(p1, p2, p3, p4):
        """Retourne le point d'intersection des segments p1p2 et p3p4, ou None si pas d'intersection."""
        # Calcul des coefficients des droites
        a1 = p2.y - p1.y
        b1 = p1.x - p2.x
        c1 = a1 * p1.x + b1 * p1.y

        a2 = p4.y - p3.y
        b2 = p3.x - p4.x
        c2 = a2 * p3.x + b2 * p3.y

        det = a1 * b2 - a2 * b1
        if det == 0:
            return None  # Droites parallèles

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

        # Vérifie que le point est bien sur les deux segments
        if (
            min(p1.x, p2.x) <= x <= max(p1.x, p2.x)
            and min(p1.y, p2.y) <= y <= max(p1.y, p2.y)
            and min(p3.x, p4.x) <= x <= max(p3.x, p4.x)
            and min(p3.y, p4.y) <= y <= max(p3.y, p4.y)
        ):
            return Point2D(x, y)
        return None
[3]:
p1 = Point2D(3, 4)
p2 = Point2D(6, 8)
print(p1)  # Affiche : Point2D(3, 4)
print(p1.distance_to(p2))
Point2D(3, 4)
5.0
[18]:
import matplotlib.pyplot as plt


class Polygone:
    def __init__(self, points=None):
        if points is None:
            self.points = []
        else:
            self.points = list(points)

    def __repr__(self):
        return f"Polygone({self.points})"

    def ajouter_point(self, point):
        """Ajoute un point au polygone."""
        self.points.append(point)

    def perimetre(self):
        """Calcule le périmètre du polygone."""
        if len(self.points) < 2:
            return 0.0
        perimetre = 0.0
        for i in range(len(self.points)):
            p1 = self.points[i]
            p2 = self.points[(i + 1) % len(self.points)]
            perimetre += p1.distance_to(p2)
        return perimetre

    def aire(self):
        """Calcule l'aire du polygone en utilisant la formule du shoelace."""
        if len(self.points) < 3:
            return 0.0
        aire = 0.0
        n = len(self.points)
        for i in range(n):
            x_i, y_i = self.points[i].x, self.points[i].y
            x_j, y_j = self.points[(i + 1) % n].x, self.points[(i + 1) % n].y
            aire += (x_i * y_j) - (x_j * y_i)
        return abs(aire) / 2.0

    def tracer(self, titre="Polygone", couleur="blue"):
        """Trace le polygone dans un notebook avec les indices des points."""
        if len(self.points) < 2:
            print("Pas assez de points pour tracer.")
            return

        x = [p.x for p in self.points]
        y = [p.y for p in self.points]

        # On ferme le polygone en ajoutant le premier point à la fin
        x.append(self.points[0].x)
        y.append(self.points[0].y)

        plt.figure()
        plt.plot(x, y, marker="o", color=couleur)

        # Ajout des indices des points
        for i, (xi, yi) in enumerate(zip(x[:-1], y[:-1])):
            plt.text(xi, yi, f" {i}", color="red", fontsize=12)

        plt.title(titre)
        plt.xlabel("X")
        plt.ylabel("Y")
        plt.grid(True)
        plt.axis("equal")
        plt.show()

    def premier_point_intersection_segments(self):
        """Retourne les coordonnées du premier point d'intersection entre deux segments,
        ainsi que les indices des premières extrémités de chacun des segments.
        Retourne (None, None, None) si pas d'intersection."""
        n = len(self.points)
        for i in range(n):
            for j in range(i + 1, n):
                p1 = self.points[i]
                p2 = self.points[(i + 1) % n]
                p3 = self.points[j]
                p4 = self.points[(j + 1) % n]
                pt_inter = Point2D.intersection_point(p1, p2, p3, p4)
                if pt_inter is not None:
                    return pt_inter, i, j
        return None, None, None

    def inserer_point_intersection(self, i, j, point):
        """Insère le point d'intersection après i et après j dans la liste des points.
        Attention : cela modifie la liste des points du polygone.
        """
        if i >= len(self.points) or j >= len(self.points):
            raise ValueError("Indices invalides")
        # On insère d'abord après le plus grand indice pour ne pas décaler l'autre
        if i > j:
            self.points.insert(j + 1, point)
            self.points.insert(i + 2, point)  # +2 car la liste a déjà grandi
        else:
            self.points.insert(i + 1, point)
            self.points.insert(j + 2, point)  # +2 car la liste a déjà grandi
[19]:
p1 = Point2D(0, 0)
p2 = Point2D(4, 0)
p3 = Point2D(4, 3)
p4 = Point2D(0, 3)

poly = Polygone([p1, p2, p3, p4])
print(
    poly
)  # Affiche : Polygone([Point2D(0, 0), Point2D(4, 0), Point2D(4, 3), Point2D(0, 3)])
print(poly.perimetre())  # Affiche : 14.0
Polygone([Point2D(0, 0), Point2D(4, 0), Point2D(4, 3), Point2D(0, 3)])
14.0
[20]:
p1 = Point2D(0, 0)
p2 = Point2D(4, 0)
p3 = Point2D(4, 3)
p4 = Point2D(0, 3)

poly = Polygone([p1, p2, p3, p4])
print(poly.aire())  # Affiche : 12.0
12.0
[21]:
p1 = Point2D(0, 0)
p2 = Point2D(0, 1)
p3 = Point2D(1, 0)
p4 = Point2D(1, 1)

poly = Polygone([p1, p2, p3, p4])
print(poly.aire())  # Affiche : 12.0
0.0
[22]:
poly.tracer(titre="Mon rectangle", couleur="red")
../../../_images/practice_years_2025_seance1_point2d_7_0.png
[ ]:


Notebook on github