From 264d2bba603f69539d59fdfaf1524ef1d95f8b55 Mon Sep 17 00:00:00 2001
From: test <grave54122@gmail.com>
Date: Sun, 30 Mar 2025 13:13:59 +0000
Subject: [PATCH] TP2

---
 src/src/twisk/MainTwisk.java                 |   4 +
 src/src/twisk/exceptions/ArcException.java   |  15 ++
 src/src/twisk/exceptions/TwiskException.java |  15 ++
 src/src/twisk/modele/ActiviteIG.java         |   6 +-
 src/src/twisk/modele/ArcIG.java              |  45 ++++
 src/src/twisk/modele/CourbeIG.java           |  62 +++++
 src/src/twisk/modele/EtapeIG.java            |  88 ++++++-
 src/src/twisk/modele/LigneDroiteIG.java      |  16 ++
 src/src/twisk/modele/MondeIG.java            | 237 ++++++++++++++++++-
 src/src/twisk/modele/PointDeControleIG.java  |  57 +++++
 src/src/twisk/outils/TailleComposants.java   |  45 ++++
 src/src/twisk/ressources/css/style.css       |  99 ++++++++
 src/src/twisk/test/modele/MondeIGTest.java   |  79 ++++++-
 src/src/twisk/vues/VueActiviteIG.java        |  19 +-
 src/src/twisk/vues/VueArcIG.java             |  23 ++
 src/src/twisk/vues/VueCourbeIG.java          |  93 ++++++++
 src/src/twisk/vues/VueLigneDroiteIG.java     |  80 +++++++
 src/src/twisk/vues/VueMondeIG.java           |  69 +++++-
 src/src/twisk/vues/VueOutils.java            |   4 +
 src/src/twisk/vues/VuePointDeControleIG.java |  68 ++++++
 20 files changed, 1097 insertions(+), 27 deletions(-)
 create mode 100644 src/src/twisk/exceptions/ArcException.java
 create mode 100644 src/src/twisk/exceptions/TwiskException.java
 create mode 100644 src/src/twisk/modele/ArcIG.java
 create mode 100644 src/src/twisk/modele/CourbeIG.java
 create mode 100644 src/src/twisk/modele/LigneDroiteIG.java
 create mode 100644 src/src/twisk/modele/PointDeControleIG.java
 create mode 100644 src/src/twisk/outils/TailleComposants.java
 create mode 100644 src/src/twisk/ressources/css/style.css
 create mode 100644 src/src/twisk/vues/VueArcIG.java
 create mode 100644 src/src/twisk/vues/VueCourbeIG.java
 create mode 100644 src/src/twisk/vues/VueLigneDroiteIG.java
 create mode 100644 src/src/twisk/vues/VuePointDeControleIG.java

diff --git a/src/src/twisk/MainTwisk.java b/src/src/twisk/MainTwisk.java
index 3044754..785b687 100644
--- a/src/src/twisk/MainTwisk.java
+++ b/src/src/twisk/MainTwisk.java
@@ -30,6 +30,10 @@ public class MainTwisk extends Application {
             // Création de la scène
             Scene scene = new Scene(root, 800, 600);
 
+            // Chargement du fichier CSS
+            String cssPath = getClass().getResource("/twisk/ressources/css/style.css").toExternalForm();
+            scene.getStylesheets().add(cssPath);
+
             // Configuration de la fenêtre principale
             primaryStage.setTitle("TwiskIG");
             primaryStage.setScene(scene);
diff --git a/src/src/twisk/exceptions/ArcException.java b/src/src/twisk/exceptions/ArcException.java
new file mode 100644
index 0000000..b17d143
--- /dev/null
+++ b/src/src/twisk/exceptions/ArcException.java
@@ -0,0 +1,15 @@
+package twisk.exceptions;
+
+/**
+ * Exception levée lors d'un problème avec les arcs
+ */
+public class ArcException extends TwiskException {
+
+    /**
+     * Constructeur
+     * @param message message d'erreur
+     */
+    public ArcException(String message) {
+        super(message);
+    }
+}
diff --git a/src/src/twisk/exceptions/TwiskException.java b/src/src/twisk/exceptions/TwiskException.java
new file mode 100644
index 0000000..8980414
--- /dev/null
+++ b/src/src/twisk/exceptions/TwiskException.java
@@ -0,0 +1,15 @@
+package twisk.exceptions;
+
+/**
+ * Exception de base pour toutes les exceptions spécifiques à Twisk
+ */
+public class TwiskException extends Exception {
+
+    /**
+     * Constructeur
+     * @param message message d'erreur
+     */
+    public TwiskException(String message) {
+        super(message);
+    }
+}
diff --git a/src/src/twisk/modele/ActiviteIG.java b/src/src/twisk/modele/ActiviteIG.java
index 3ddd57b..bc4d491 100644
--- a/src/src/twisk/modele/ActiviteIG.java
+++ b/src/src/twisk/modele/ActiviteIG.java
@@ -1,8 +1,12 @@
 package twisk.modele;
 
+import twisk.outils.TailleComposants;
+
 public class ActiviteIG extends EtapeIG {
 
     public ActiviteIG(String nom) {
-        super(nom, 100, 60); // Dimensions par défaut pour une activité
+        // Utilisation des tailles définies dans TailleComposants
+        super(nom, TailleComposants.getInstance().getLargeurActivite(),
+                TailleComposants.getInstance().getHauteurActivite());
     }
 }
diff --git a/src/src/twisk/modele/ArcIG.java b/src/src/twisk/modele/ArcIG.java
new file mode 100644
index 0000000..c1557ee
--- /dev/null
+++ b/src/src/twisk/modele/ArcIG.java
@@ -0,0 +1,45 @@
+package twisk.modele;
+
+/**
+ * Classe abstraite représentant un arc dans l'interface graphique
+ */
+public abstract class ArcIG {
+    protected final PointDeControleIG p1;
+    protected final PointDeControleIG p2;
+    protected final String id;
+
+    /**
+     * Constructeur
+     * @param p1 premier point de contrôle
+     * @param p2 deuxième point de contrôle
+     */
+    public ArcIG(PointDeControleIG p1, PointDeControleIG p2) {
+        this.p1 = p1;
+        this.p2 = p2;
+        this.id = FabriqueIdentifiant.getInstance().getIdentifiantUnique();
+    }
+
+    /**
+     * Retourne le premier point de contrôle
+     * @return premier point de contrôle
+     */
+    public PointDeControleIG getP1() {
+        return p1;
+    }
+
+    /**
+     * Retourne le deuxième point de contrôle
+     * @return deuxième point de contrôle
+     */
+    public PointDeControleIG getP2() {
+        return p2;
+    }
+
+    /**
+     * Retourne l'identifiant de l'arc
+     * @return identifiant
+     */
+    public String getId() {
+        return id;
+    }
+}
diff --git a/src/src/twisk/modele/CourbeIG.java b/src/src/twisk/modele/CourbeIG.java
new file mode 100644
index 0000000..47add4d
--- /dev/null
+++ b/src/src/twisk/modele/CourbeIG.java
@@ -0,0 +1,62 @@
+package twisk.modele;
+
+/**
+ * Classe représentant une courbe dans l'interface graphique
+ */
+public class CourbeIG extends ArcIG {
+    private final int controlX1;
+    private final int controlY1;
+    private final int controlX2;
+    private final int controlY2;
+
+    /**
+     * Constructeur
+     * @param p1 premier point de contrôle
+     * @param p2 deuxième point de contrôle
+     * @param controlX1 coordonnée X du premier point de contrôle intermédiaire
+     * @param controlY1 coordonnée Y du premier point de contrôle intermédiaire
+     * @param controlX2 coordonnée X du deuxième point de contrôle intermédiaire
+     * @param controlY2 coordonnée Y du deuxième point de contrôle intermédiaire
+     */
+    public CourbeIG(PointDeControleIG p1, PointDeControleIG p2,
+                    int controlX1, int controlY1,
+                    int controlX2, int controlY2) {
+        super(p1, p2);
+        this.controlX1 = controlX1;
+        this.controlY1 = controlY1;
+        this.controlX2 = controlX2;
+        this.controlY2 = controlY2;
+    }
+
+    /**
+     * Retourne la coordonnée X du premier point de contrôle intermédiaire
+     * @return coordonnée X
+     */
+    public int getControlX1() {
+        return controlX1;
+    }
+
+    /**
+     * Retourne la coordonnée Y du premier point de contrôle intermédiaire
+     * @return coordonnée Y
+     */
+    public int getControlY1() {
+        return controlY1;
+    }
+
+    /**
+     * Retourne la coordonnée X du deuxième point de contrôle intermédiaire
+     * @return coordonnée X
+     */
+    public int getControlX2() {
+        return controlX2;
+    }
+
+    /**
+     * Retourne la coordonnée Y du deuxième point de contrôle intermédiaire
+     * @return coordonnée Y
+     */
+    public int getControlY2() {
+        return controlY2;
+    }
+}
diff --git a/src/src/twisk/modele/EtapeIG.java b/src/src/twisk/modele/EtapeIG.java
index fc57098..66514b0 100644
--- a/src/src/twisk/modele/EtapeIG.java
+++ b/src/src/twisk/modele/EtapeIG.java
@@ -1,12 +1,17 @@
 package twisk.modele;
 
-public abstract class EtapeIG {
-    private String nom;
-    private final String identifiant;
-    private int posX;
-    private int posY;
-    private int largeur;
-    private int hauteur;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public abstract class EtapeIG implements Iterable<PointDeControleIG> {
+    protected String nom;
+    protected String identifiant;
+    protected int posX;
+    protected int posY;
+    protected int largeur;
+    protected int hauteur;
+    protected List<PointDeControleIG> pointsDeControle;
 
     public EtapeIG(String nom, int largeur, int hauteur) {
         this.nom = nom;
@@ -16,8 +21,69 @@ public abstract class EtapeIG {
         this.posY = (int) (Math.random() * 500);
         this.largeur = largeur;
         this.hauteur = hauteur;
+
+        // Initialisation de la liste des points de contrôle
+        this.pointsDeControle = new ArrayList<>(4);
+
+        // Création des 4 points de contrôle (un au milieu de chaque côté)
+        creerPointsDeControle();
+    }
+
+    /**
+     * Crée les 4 points de contrôle pour l'étape
+     */
+    private void creerPointsDeControle() {
+        // Point sur le côté supérieur (milieu)
+        pointsDeControle.add(new PointDeControleIG(
+                posX + largeur / 2,
+                posY,
+                "p" + identifiant + "N", // N pour Nord
+                this
+        ));
+
+        // Point sur le côté droit (milieu)
+        pointsDeControle.add(new PointDeControleIG(
+                posX + largeur,
+                posY + hauteur / 2,
+                "p" + identifiant + "E", // E pour Est
+                this
+        ));
+
+        // Point sur le côté inférieur (milieu)
+        pointsDeControle.add(new PointDeControleIG(
+                posX + largeur / 2,
+                posY + hauteur,
+                "p" + identifiant + "S", // S pour Sud
+                this
+        ));
+
+        // Point sur le côté gauche (milieu)
+        pointsDeControle.add(new PointDeControleIG(
+                posX,
+                posY + hauteur / 2,
+                "p" + identifiant + "O", // O pour Ouest
+                this
+        ));
+    }
+
+    /**
+     * Met à jour la position des points de contrôle quand l'étape est déplacée
+     */
+    public void majPointsDeControle() {
+        // Vider la liste actuelle
+        pointsDeControle.clear();
+
+        // Recréer les points de contrôle avec les nouvelles coordonnées
+        creerPointsDeControle();
+    }
+
+    // Implémentation de l'interface Iterable
+    @Override
+    public Iterator<PointDeControleIG> iterator() {
+        return pointsDeControle.iterator();
     }
 
+    // Getters et setters existants
     public String getNom() {
         return nom;
     }
@@ -36,6 +102,8 @@ public abstract class EtapeIG {
 
     public void setPosX(int posX) {
         this.posX = posX;
+        // Mettre à jour les points de contrôle
+        majPointsDeControle();
     }
 
     public int getPosY() {
@@ -44,6 +112,8 @@ public abstract class EtapeIG {
 
     public void setPosY(int posY) {
         this.posY = posY;
+        // Mettre à jour les points de contrôle
+        majPointsDeControle();
     }
 
     public int getLargeur() {
@@ -52,6 +122,8 @@ public abstract class EtapeIG {
 
     public void setLargeur(int largeur) {
         this.largeur = largeur;
+        // Mettre à jour les points de contrôle
+        majPointsDeControle();
     }
 
     public int getHauteur() {
@@ -60,5 +132,7 @@ public abstract class EtapeIG {
 
     public void setHauteur(int hauteur) {
         this.hauteur = hauteur;
+        // Mettre à jour les points de contrôle
+        majPointsDeControle();
     }
 }
diff --git a/src/src/twisk/modele/LigneDroiteIG.java b/src/src/twisk/modele/LigneDroiteIG.java
new file mode 100644
index 0000000..f4b42a1
--- /dev/null
+++ b/src/src/twisk/modele/LigneDroiteIG.java
@@ -0,0 +1,16 @@
+package twisk.modele;
+
+/**
+ * Classe représentant une ligne droite dans l'interface graphique
+ */
+public class LigneDroiteIG extends ArcIG {
+
+    /**
+     * Constructeur
+     * @param p1 premier point de contrôle
+     * @param p2 deuxième point de contrôle
+     */
+    public LigneDroiteIG(PointDeControleIG p1, PointDeControleIG p2) {
+        super(p1, p2);
+    }
+}
diff --git a/src/src/twisk/modele/MondeIG.java b/src/src/twisk/modele/MondeIG.java
index edc5540..55e3ead 100644
--- a/src/src/twisk/modele/MondeIG.java
+++ b/src/src/twisk/modele/MondeIG.java
@@ -1,20 +1,26 @@
 package twisk.modele;
 
+import twisk.exceptions.ArcException;
 import twisk.outils.Observable;
 import twisk.outils.Observateur;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
+import javafx.geometry.Point2D;
+import java.util.*;
 
 public class MondeIG implements Iterable<EtapeIG>, Observable {
     private final Map<String, EtapeIG> etapes;
     private int compteurActivites;
     private ArrayList<Observateur> observateurs;
+    private ArrayList<ArcIG> arcs;
+    private PointDeControleIG pointSelectionne;
+    private List<Point2D> pointsCliques;
+    private static final int NB_POINTS_COURBE = 4;
 
     public MondeIG() {
         etapes = new HashMap<>();
+        arcs = new ArrayList<>();
+        pointSelectionne = null;
+        pointsCliques = new ArrayList<>();
         compteurActivites = 1;
         observateurs = new ArrayList<>();
 
@@ -22,6 +28,10 @@ public class MondeIG implements Iterable<EtapeIG>, Observable {
         ajouter("Activite");
     }
 
+    /**
+     * Ajoute une étape du type spécifié
+     * @param type le type d'étape à ajouter
+     */
     public void ajouter(String type) {
         if ("Activite".equals(type)) {
             String nom = "Activite " + compteurActivites++;
@@ -37,15 +47,105 @@ public class MondeIG implements Iterable<EtapeIG>, Observable {
         // Autres types d'étapes pourront être ajoutés ici dans le futur
     }
 
+    /**
+     * Ajoute un arc entre deux points de contrôle
+     * @param pt1 premier point de contrôle
+     * @param pt2 deuxième point de contrôle
+     * @throws ArcException si l'arc ne peut pas être ajouté
+     */
+    public void ajouter(PointDeControleIG pt1, PointDeControleIG pt2) throws ArcException {
+        // Contrainte 4: Vérifier que les points sont différents
+        if (pt1 == pt2) {
+            throw new ArcException("Impossible de créer un arc: les deux points sont identiques");
+        }
+
+        // Contrainte 1: Vérifier que les points ne sont pas sur la même étape
+        if (pt1.getEtape().equals(pt2.getEtape())) {
+            throw new ArcException("Impossible de créer un arc: les deux points appartiennent à la même étape");
+        }
+
+        // Contrainte 2: Vérifier qu'il n'existe pas déjà un arc entre ces deux points
+        for (ArcIG arc : arcs) {
+            if ((arc.getP1().equals(pt1) && arc.getP2().equals(pt2))) {
+                throw new ArcException("Impossible de créer un arc: un arc existe déjà entre ces deux points");
+            }
+        }
+
+        // Contrainte 3: Vérifier qu'il n'existe pas déjà un arc dans le sens inverse
+        for (ArcIG arc : arcs) {
+            if ((arc.getP1().equals(pt2) && arc.getP2().equals(pt1)) ||
+                    (arc.getP1().getEtape().equals(pt2.getEtape()) && arc.getP2().getEtape().equals(pt1.getEtape()))) {
+                throw new ArcException("Impossible de créer un arc: un arc existe déjà dans le sens inverse");
+            }
+        }
+
+        // Contrainte 5: Vérifier que le point de départ n'est pas déjà utilisé comme source d'un autre arc
+        for (ArcIG arc : arcs) {
+            if (arc.getP1().equals(pt1)) {
+                throw new ArcException("Impossible de créer un arc: le point de départ est déjà utilisé comme source d'un autre arc");
+            }
+        }
+
+        // Contrainte 6: Vérifier que le point d'arrivée n'est pas déjà utilisé comme destination d'un autre arc
+        for (ArcIG arc : arcs) {
+            if (arc.getP2().equals(pt2)) {
+                throw new ArcException("Impossible de créer un arc: le point d'arrivée est déjà utilisé comme destination d'un autre arc");
+            }
+        }
+
+        // Toutes les contraintes sont satisfaites, on peut ajouter l'arc
+        ArcIG arc = new LigneDroiteIG(pt1, pt2);
+        arcs.add(arc);
+        notifierObservateurs();
+    }
+
+    /**
+     * Gère la sélection d'un point de contrôle
+     * @param pt le point de contrôle sélectionné
+     * @throws ArcException si l'arc ne peut pas être créé
+     */
+    public void selectionnerPointDeControle(PointDeControleIG pt) throws ArcException {
+        if (pointSelectionne == null) {
+            // Premier point sélectionné
+            pointSelectionne = pt;
+        } else {
+            // Deuxième point sélectionné, on tente de créer un arc
+            PointDeControleIG premier = pointSelectionne;
+            // Réinitialiser la sélection avant de tenter d'ajouter l'arc
+            pointSelectionne = null;
+            // Tenter d'ajouter l'arc (peut lever une ArcException)
+            ajouter(premier, pt);
+        }
+    }
+
+
+
+    /**
+     * Retourne l'étape correspondant à l'identifiant
+     * @param identifiant l'identifiant de l'étape
+     * @return l'étape correspondante
+     */
     public EtapeIG getEtape(String identifiant) {
         return etapes.get(identifiant);
     }
 
+    /**
+     * Retourne un itérateur sur les étapes
+     * @return itérateur sur les étapes
+     */
     @Override
     public Iterator<EtapeIG> iterator() {
         return etapes.values().iterator();
     }
 
+    /**
+     * Retourne un itérateur sur les arcs
+     * @return itérateur sur les arcs
+     */
+    public Iterator<ArcIG> iteratorArcs() {
+        return arcs.iterator();
+    }
+
     @Override
     public void ajouterObservateur(Observateur o) {
         observateurs.add(o);
@@ -57,4 +157,133 @@ public class MondeIG implements Iterable<EtapeIG>, Observable {
             o.reagir();
         }
     }
+    /**
+     * Gère un clic sur le monde
+     * @param x coordonnée x du clic
+     * @param y coordonnée y du clic
+     * @throws ArcException si l'arc ne peut pas être créé
+     */
+    public void clic(double x, double y) throws ArcException {
+        // Vérifier si le clic est sur un point de contrôle
+        PointDeControleIG pointClique = null;
+
+        // Parcourir toutes les étapes et leurs points de contrôle
+        for (EtapeIG etape : etapes.values()) {
+            for (PointDeControleIG pt : etape) {
+                // Vérifier si le clic est sur ce point (distance < 10 pixels)
+                double distance = Math.sqrt(Math.pow(pt.getPosX() - x, 2) + Math.pow(pt.getPosY() - y, 2));
+                if (distance < 10) {
+                    pointClique = pt;
+                    break;
+                }
+            }
+            if (pointClique != null) {
+                break;
+            }
+        }
+
+        // Si le clic est sur un point de contrôle
+        if (pointClique != null) {
+            // Ajouter le point à la liste des points cliqués
+            pointsCliques.add(new Point2D(pointClique.getPosX(), pointClique.getPosY()));
+
+            // Si c'est le premier point, le mémoriser comme point sélectionné
+            if (pointsCliques.size() == 1) {
+                pointSelectionne = pointClique;
+            }
+            // Si c'est le deuxième point et que le premier était un point de contrôle,
+            // créer une ligne droite
+            else if (pointsCliques.size() == 2 && pointSelectionne != null) {
+                // Créer une ligne droite
+                try {
+                    ajouter(pointSelectionne, pointClique);
+                } catch (ArcException e) {
+                    // Réinitialiser en cas d'erreur
+                    pointSelectionne = null;
+                    pointsCliques.clear();
+                    throw e;
+                }
+
+                // Réinitialiser
+                pointSelectionne = null;
+                pointsCliques.clear();
+            }
+            // Si c'est le quatrième point et que le premier était un point de contrôle,
+            // créer une courbe
+            else if (pointsCliques.size() == NB_POINTS_COURBE && pointSelectionne != null) {
+                // Récupérer les points intermédiaires
+                Point2D p2 = pointsCliques.get(1);
+                Point2D p3 = pointsCliques.get(2);
+
+                // Vérifier les contraintes comme dans la méthode ajouter
+                if (pointSelectionne == pointClique) {
+                    pointSelectionne = null;
+                    pointsCliques.clear();
+                    throw new ArcException("Impossible de créer un arc: les deux points sont identiques");
+                }
+
+                if (pointSelectionne.getEtape().equals(pointClique.getEtape())) {
+                    pointSelectionne = null;
+                    pointsCliques.clear();
+                    throw new ArcException("Impossible de créer un arc: les deux points appartiennent à la même étape");
+                }
+
+                // Vérifier les autres contraintes comme dans la méthode ajouter
+                for (ArcIG arc : arcs) {
+                    if ((arc.getP1().equals(pointSelectionne) && arc.getP2().equals(pointClique))) {
+                        pointSelectionne = null;
+                        pointsCliques.clear();
+                        throw new ArcException("Impossible de créer un arc: un arc existe déjà entre ces deux points");
+                    }
+                }
+
+                for (ArcIG arc : arcs) {
+                    if ((arc.getP1().equals(pointClique) && arc.getP2().equals(pointSelectionne)) ||
+                            (arc.getP1().getEtape().equals(pointClique.getEtape()) && arc.getP2().getEtape().equals(pointSelectionne.getEtape()))) {
+                        pointSelectionne = null;
+                        pointsCliques.clear();
+                        throw new ArcException("Impossible de créer un arc: un arc existe déjà dans le sens inverse");
+                    }
+                }
+
+                for (ArcIG arc : arcs) {
+                    if (arc.getP1().equals(pointSelectionne)) {
+                        pointSelectionne = null;
+                        pointsCliques.clear();
+                        throw new ArcException("Impossible de créer un arc: le point de départ est déjà utilisé comme source d'un autre arc");
+                    }
+                }
+
+                for (ArcIG arc : arcs) {
+                    if (arc.getP2().equals(pointClique)) {
+                        pointSelectionne = null;
+                        pointsCliques.clear();
+                        throw new ArcException("Impossible de créer un arc: le point d'arrivée est déjà utilisé comme destination d'un autre arc");
+                    }
+                }
+
+                // Créer une courbe
+                ArcIG arc = new CourbeIG(
+                        pointSelectionne,
+                        pointClique,
+                        (int) p2.getX(), (int) p2.getY(),
+                        (int) p3.getX(), (int) p3.getY()
+                );
+                arcs.add(arc);
+
+                // Réinitialiser
+                pointSelectionne = null;
+                pointsCliques.clear();
+
+                // Notifier les observateurs
+                notifierObservateurs();
+            }
+        }
+        // Sinon, si on est en train de créer une courbe (entre 1 et 3 points déjà cliqués),
+        // ajouter le point comme point de contrôle intermédiaire
+        else if (pointsCliques.size() >= 1 && pointsCliques.size() < NB_POINTS_COURBE - 1) {
+            pointsCliques.add(new Point2D(x, y));
+        }
+    }
+
 }
diff --git a/src/src/twisk/modele/PointDeControleIG.java b/src/src/twisk/modele/PointDeControleIG.java
new file mode 100644
index 0000000..30fc179
--- /dev/null
+++ b/src/src/twisk/modele/PointDeControleIG.java
@@ -0,0 +1,57 @@
+package twisk.modele;
+
+/**
+ * Classe représentant un point de contrôle sur une étape
+ */
+public class PointDeControleIG {
+    private final int posX;
+    private final int posY;
+    private final String id;
+    private final EtapeIG etape;
+
+    /**
+     * Constructeur
+     * @param posX position X du centre du point
+     * @param posY position Y du centre du point
+     * @param id identifiant unique
+     * @param etape étape à laquelle le point est rattaché
+     */
+    public PointDeControleIG(int posX, int posY, String id, EtapeIG etape) {
+        this.posX = posX;
+        this.posY = posY;
+        this.id = id;
+        this.etape = etape;
+    }
+
+    /**
+     * Retourne la position X du point
+     * @return position X
+     */
+    public int getPosX() {
+        return posX;
+    }
+
+    /**
+     * Retourne la position Y du point
+     * @return position Y
+     */
+    public int getPosY() {
+        return posY;
+    }
+
+    /**
+     * Retourne l'identifiant du point
+     * @return identifiant
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Retourne l'étape à laquelle le point est rattaché
+     * @return étape
+     */
+    public EtapeIG getEtape() {
+        return etape;
+    }
+}
diff --git a/src/src/twisk/outils/TailleComposants.java b/src/src/twisk/outils/TailleComposants.java
new file mode 100644
index 0000000..e080df4
--- /dev/null
+++ b/src/src/twisk/outils/TailleComposants.java
@@ -0,0 +1,45 @@
+package twisk.outils;
+
+/**
+ * Classe singleton qui centralise les constantes de taille des composants graphiques
+ */
+public class TailleComposants {
+    private static TailleComposants instance = new TailleComposants();
+
+    // Tailles pour les activités
+    private final int largeurActivite;
+    private final int hauteurActivite;
+
+    // Constructeur privé (singleton)
+    private TailleComposants() {
+        // Initialisation des tailles par défaut
+        largeurActivite = 100;
+        hauteurActivite = 60;
+
+        // D'autres tailles pourront être ajoutées ici dans le futur
+    }
+
+    /**
+     * Retourne l'instance unique de TailleComposants
+     * @return l'instance de TailleComposants
+     */
+    public static TailleComposants getInstance() {
+        return instance;
+    }
+
+    /**
+     * Retourne la largeur par défaut d'une activité
+     * @return la largeur en pixels
+     */
+    public int getLargeurActivite() {
+        return largeurActivite;
+    }
+
+    /**
+     * Retourne la hauteur par défaut d'une activité
+     * @return la hauteur en pixels
+     */
+    public int getHauteurActivite() {
+        return hauteurActivite;
+    }
+}
diff --git a/src/src/twisk/ressources/css/style.css b/src/src/twisk/ressources/css/style.css
new file mode 100644
index 0000000..9618368
--- /dev/null
+++ b/src/src/twisk/ressources/css/style.css
@@ -0,0 +1,99 @@
+/* Styles généraux */
+.root {
+    -fx-font-family: 'Segoe UI', Arial, sans-serif;
+    -fx-background-color: #f5f5f5;
+}
+
+/* Style pour VueMondeIG */
+.monde {
+    -fx-background-color: white;
+    -fx-padding: 10px;
+}
+
+/* Style pour VueActiviteIG */
+.activite {
+    -fx-background-color: #e6f2ff;
+    -fx-border-color: #0066cc;
+    -fx-border-width: 2px;
+    -fx-border-radius: 5px;
+    -fx-background-radius: 5px;
+    -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.2), 5, 0, 0, 2);
+}
+
+/* Style pour le titre de l'activité */
+.titre-activite {
+    -fx-font-size: 14px;
+    -fx-font-weight: bold;
+    -fx-text-fill: #0066cc;
+    -fx-padding: 5px;
+    -fx-background-color: #cce0ff;
+    -fx-background-radius: 5px 5px 0 0;
+}
+
+/* Style pour la zone des clients */
+.zone-clients {
+    -fx-background-color: white;
+    -fx-border-color: #99ccff;
+    -fx-border-width: 1px;
+    -fx-border-radius: 0 0 5px 5px;
+    -fx-background-radius: 0 0 5px 5px;
+    -fx-padding: 5px;
+    -fx-min-height: 30px;
+}
+
+/* Style pour la barre d'outils */
+.outils {
+    -fx-background-color: #333333;
+    -fx-padding: 10px;
+    -fx-spacing: 10px;
+}
+
+/* Style pour les boutons */
+.bouton {
+    -fx-background-color: #0066cc;
+    -fx-text-fill: white;
+    -fx-font-weight: bold;
+    -fx-padding: 8px 15px;
+    -fx-background-radius: 5px;
+    -fx-cursor: hand;
+}
+
+.bouton:hover {
+    -fx-background-color: #0052a3;
+}
+
+.bouton:pressed {
+    -fx-background-color: #003d7a;
+}
+
+/* Style pour les points de contrôle */
+.point-controle {
+    -fx-cursor: hand;
+}
+
+.point-controle:hover {
+    -fx-fill: #66b3ff;
+    -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.3), 3, 0, 0, 0);
+}
+
+/* Style pour les arcs */
+.arc-ligne {
+    -fx-stroke: #0066cc;
+    -fx-stroke-width: 2;
+}
+
+.arc-fleche {
+    -fx-fill: #0066cc;
+    -fx-stroke: #0066cc;
+    -fx-stroke-width: 1;
+}
+
+/* Style pour les points de contrôle */
+.point-controle {
+    -fx-cursor: hand;
+}
+
+.point-controle:hover {
+    -fx-fill: #66b3ff;
+    -fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.3), 3, 0, 0, 0);
+}
diff --git a/src/src/twisk/test/modele/MondeIGTest.java b/src/src/twisk/test/modele/MondeIGTest.java
index 09129b8..5cd742c 100644
--- a/src/src/twisk/test/modele/MondeIGTest.java
+++ b/src/src/twisk/test/modele/MondeIGTest.java
@@ -2,10 +2,8 @@ package twisk.test.modele;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import twisk.modele.ActiviteIG;
-import twisk.modele.EtapeIG;
-import twisk.modele.FabriqueIdentifiant;
-import twisk.modele.MondeIG;
+import twisk.exceptions.ArcException;
+import twisk.modele.*;
 
 import java.util.Iterator;
 
@@ -69,4 +67,77 @@ class MondeIGTest {
 
         assertEquals(3, count, "Le monde devrait contenir 3 étapes");
     }
+    @Test
+    void testAjouterArcAvecExceptions() {
+        MondeIG monde = new MondeIG();
+
+        // Ajouter deux activités
+        monde.ajouter("Activite"); // Activite 2
+
+        // Récupérer les activités
+        Iterator<EtapeIG> it = monde.iterator();
+        EtapeIG etape1 = it.next(); // Activite 1 (par défaut)
+        EtapeIG etape2 = it.next(); // Activite 2
+
+        // Récupérer les points de contrôle
+        Iterator<PointDeControleIG> itPt1 = etape1.iterator();
+        PointDeControleIG pt1 = itPt1.next(); // Premier point de l'activité 1
+
+        Iterator<PointDeControleIG> itPt2 = etape2.iterator();
+        PointDeControleIG pt2 = itPt2.next(); // Premier point de l'activité 2
+
+        // Test d'ajout d'un arc valide
+        try {
+            monde.ajouter(pt1, pt2);
+            // Vérifier que l'arc a été ajouté
+            Iterator<ArcIG> itArc = monde.iteratorArcs();
+            assertTrue(itArc.hasNext(), "Un arc devrait avoir été ajouté");
+        } catch (ArcException e) {
+            fail("L'ajout d'un arc valide ne devrait pas lever d'exception");
+        }
+
+        // Test de la contrainte 2: pas de duplication d'arc
+        try {
+            monde.ajouter(pt1, pt2);
+            fail("Une exception aurait dû être levée pour un arc dupliqué");
+        } catch (ArcException e) {
+            // C'est le comportement attendu
+        }
+
+        // Test de la contrainte 3: pas d'arc dans le sens inverse
+        try {
+            monde.ajouter(pt2, pt1);
+            fail("Une exception aurait dû être levée pour un arc dans le sens inverse");
+        } catch (ArcException e) {
+            // C'est le comportement attendu
+        }
+
+        // Test de la contrainte 5: un point ne peut être source que d'un seul arc
+        PointDeControleIG pt1bis = itPt1.next(); // Deuxième point de l'activité 1
+        PointDeControleIG pt2bis = itPt2.next(); // Deuxième point de l'activité 2
+        try {
+            monde.ajouter(pt1, pt2bis);
+            fail("Une exception aurait dû être levée pour un point source déjà utilisé");
+        } catch (ArcException e) {
+            // C'est le comportement attendu
+        }
+
+        // Test de la contrainte 6: un point ne peut être destination que d'un seul arc
+        try {
+            monde.ajouter(pt1bis, pt2);
+            fail("Une exception aurait dû être levée pour un point destination déjà utilisé");
+        } catch (ArcException e) {
+            // C'est le comportement attendu
+        }
+
+        // Test de la contrainte 1: pas d'arc entre points de la même étape
+        PointDeControleIG pt1ter = itPt1.next(); // Troisième point de l'activité 1
+        try {
+            monde.ajouter(pt1, pt1ter);
+            fail("Une exception aurait dû être levée pour un arc entre points de la même étape");
+        } catch (ArcException e) {
+            // C'est le comportement attendu
+        }
+    }
+
 }
diff --git a/src/src/twisk/vues/VueActiviteIG.java b/src/src/twisk/vues/VueActiviteIG.java
index 7d4a70a..787d348 100644
--- a/src/src/twisk/vues/VueActiviteIG.java
+++ b/src/src/twisk/vues/VueActiviteIG.java
@@ -2,7 +2,6 @@ package twisk.vues;
 
 import javafx.scene.layout.HBox;
 import javafx.scene.layout.VBox;
-import twisk.modele.ActiviteIG;
 import twisk.modele.EtapeIG;
 
 public class VueActiviteIG extends VueEtapeIG {
@@ -11,23 +10,27 @@ public class VueActiviteIG extends VueEtapeIG {
     public VueActiviteIG(EtapeIG etape) {
         super(etape);
 
+        // Appliquer la classe CSS à l'activité
+        this.getStyleClass().add("activite");
+
+        // Appliquer la classe CSS au titre
+        titre.getStyleClass().add("titre-activite");
+
         // Création de la zone pour les clients
         zoneClients = new HBox();
-        zoneClients.setPrefSize(etape.getLargeur(), etape.getHauteur() - 20); // Réserver de l'espace pour le titre
-        zoneClients.setStyle("-fx-border-color: #0059FF; -fx-background-insets: 0 0 -1 0, 0, 1, 2; -fx-background-radius: 3px, 3px, 2px, 1px;");
+        zoneClients.setPrefSize(etape.getLargeur(), etape.getHauteur() - 30); // Réserver de l'espace pour le titre
+        zoneClients.getStyleClass().add("zone-clients");
 
         // Organisation verticale: titre en haut, zone clients en dessous
         VBox contenu = new VBox();
         contenu.getChildren().addAll(titre, zoneClients);
-
-        // Définir la taille du composant
-        this.setPrefSize(etape.getLargeur(), etape.getHauteur());
+        contenu.setPrefSize(etape.getLargeur(), etape.getHauteur());
 
         // Ajout du contenu au composant
         this.getChildren().clear();
         this.getChildren().add(contenu);
 
-        // Ajout d'un style pour la boîte
-        this.setStyle("-fx-border-color: black; -fx-border-width: 1px;");
+        // Positionnement du composant
+        relocate(etape.getPosX(), etape.getPosY());
     }
 }
diff --git a/src/src/twisk/vues/VueArcIG.java b/src/src/twisk/vues/VueArcIG.java
new file mode 100644
index 0000000..94adb20
--- /dev/null
+++ b/src/src/twisk/vues/VueArcIG.java
@@ -0,0 +1,23 @@
+package twisk.vues;
+
+import javafx.scene.layout.Pane;
+import javafx.scene.paint.Color;
+import twisk.modele.ArcIG;
+
+/**
+ * Vue abstraite d'un arc
+ */
+public abstract class VueArcIG extends Pane {
+    protected final ArcIG arc;
+
+    /**
+     * Constructeur
+     * @param arc l'arc à représenter
+     */
+    public VueArcIG(ArcIG arc) {
+        this.arc = arc;
+
+        // Ajouter une classe CSS pour le styling
+        this.getStyleClass().add("arc");
+    }
+}
diff --git a/src/src/twisk/vues/VueCourbeIG.java b/src/src/twisk/vues/VueCourbeIG.java
new file mode 100644
index 0000000..a1c973d
--- /dev/null
+++ b/src/src/twisk/vues/VueCourbeIG.java
@@ -0,0 +1,93 @@
+package twisk.vues;
+
+import javafx.scene.paint.Color;
+import javafx.scene.shape.CubicCurve;
+import javafx.scene.shape.Polyline;
+import twisk.modele.ArcIG;
+import twisk.modele.CourbeIG;
+import twisk.modele.PointDeControleIG;
+
+/**
+ * Vue d'une courbe
+ */
+public class VueCourbeIG extends VueArcIG {
+    private final CubicCurve courbe;
+    private final Polyline fleche;
+
+    /**
+     * Constructeur
+     * @param arc l'arc à représenter
+     */
+    public VueCourbeIG(ArcIG arc) {
+        super(arc);
+
+        CourbeIG courbeIG = (CourbeIG) arc;
+
+        // Récupérer les coordonnées des points de contrôle
+        PointDeControleIG p1 = arc.getP1();
+        PointDeControleIG p2 = arc.getP2();
+
+        // Créer la courbe
+        courbe = new CubicCurve(
+                p1.getPosX(), p1.getPosY(),                    // Point de départ
+                courbeIG.getControlX1(), courbeIG.getControlY1(), // Premier point de contrôle
+                courbeIG.getControlX2(), courbeIG.getControlY2(), // Deuxième point de contrôle
+                p2.getPosX(), p2.getPosY()                     // Point d'arrivée
+        );
+        courbe.setFill(null);  // Pas de remplissage
+        courbe.setStroke(Color.valueOf("#0066cc"));
+        courbe.setStrokeWidth(2);
+        courbe.getStyleClass().add("arc-courbe");
+
+        // Calculer les coordonnées de la flèche
+        // Pour une courbe, on utilise la tangente au point d'arrivée
+        double[] coordsFleche = calculerCoordonneesTrianglePourCourbe(
+                courbeIG.getControlX2(), courbeIG.getControlY2(),
+                p2.getPosX(), p2.getPosY()
+        );
+
+        // Créer la flèche (triangle)
+        fleche = new Polyline(coordsFleche);
+        fleche.setFill(Color.valueOf("#0066cc"));
+        fleche.setStroke(Color.valueOf("#0066cc"));
+        fleche.getStyleClass().add("arc-fleche");
+
+        // Ajouter les composants au Pane
+        this.getChildren().addAll(courbe, fleche);
+    }
+
+    /**
+     * Calcule les coordonnées des trois points du triangle formant la flèche
+     * en utilisant la tangente à la courbe au point d'arrivée
+     * @param controlX coordonnée x du point de contrôle précédant le point d'arrivée
+     * @param controlY coordonnée y du point de contrôle précédant le point d'arrivée
+     * @param x2 coordonnée x du point d'arrivée
+     * @param y2 coordonnée y du point d'arrivée
+     * @return tableau des coordonnées des trois points du triangle
+     */
+    private double[] calculerCoordonneesTrianglePourCourbe(double controlX, double controlY, double x2, double y2) {
+        // Longueur de la flèche
+        double longueurFleche = 15;
+
+        // Angle de la flèche (en radians)
+        double angleFleche = Math.PI / 6; // 30 degrés
+
+        // Calculer l'angle de la tangente à la courbe au point d'arrivée
+        double angle = Math.atan2(y2 - controlY, x2 - controlX);
+
+        // Calculer les coordonnées des trois points du triangle
+        double x3 = x2 - longueurFleche * Math.cos(angle - angleFleche);
+        double y3 = y2 - longueurFleche * Math.sin(angle - angleFleche);
+
+        double x4 = x2 - longueurFleche * Math.cos(angle + angleFleche);
+        double y4 = y2 - longueurFleche * Math.sin(angle + angleFleche);
+
+        // Retourner les coordonnées sous forme de tableau pour la Polyline
+        return new double[] {
+                x2, y2,   // Sommet de la flèche
+                x3, y3,   // Premier point de la base
+                x4, y4,   // Deuxième point de la base
+                x2, y2    // Retour au sommet pour fermer le triangle
+        };
+    }
+}
diff --git a/src/src/twisk/vues/VueLigneDroiteIG.java b/src/src/twisk/vues/VueLigneDroiteIG.java
new file mode 100644
index 0000000..0fe42a1
--- /dev/null
+++ b/src/src/twisk/vues/VueLigneDroiteIG.java
@@ -0,0 +1,80 @@
+package twisk.vues;
+
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Line;
+import javafx.scene.shape.Polyline;
+import twisk.modele.ArcIG;
+import twisk.modele.LigneDroiteIG;
+import twisk.modele.PointDeControleIG;
+
+/**
+ * Vue d'une ligne droite
+ */
+public class VueLigneDroiteIG extends VueArcIG {
+    private final Line ligne;
+    private final Polyline fleche;
+
+    /**
+     * Constructeur
+     * @param arc l'arc à représenter
+     */
+    public VueLigneDroiteIG(ArcIG arc) {
+        super(arc);
+
+        // Récupérer les coordonnées des points de contrôle
+        PointDeControleIG p1 = arc.getP1();
+        PointDeControleIG p2 = arc.getP2();
+
+        // Créer la ligne
+        ligne = new Line(p1.getPosX(), p1.getPosY(), p2.getPosX(), p2.getPosY());
+        ligne.setStroke(Color.valueOf("#0066cc"));
+        ligne.setStrokeWidth(2);
+        ligne.getStyleClass().add("arc-ligne");
+
+        // Calculer les coordonnées de la flèche
+        double[] coordsFleche = calculerCoordonneesTriangle(p1.getPosX(), p1.getPosY(), p2.getPosX(), p2.getPosY());
+
+        // Créer la flèche (triangle)
+        fleche = new Polyline(coordsFleche);
+        fleche.setFill(Color.valueOf("#0066cc"));
+        fleche.setStroke(Color.valueOf("#0066cc"));
+        fleche.getStyleClass().add("arc-fleche");
+
+        // Ajouter les composants au Pane
+        this.getChildren().addAll(ligne, fleche);
+    }
+
+    /**
+     * Calcule les coordonnées des trois points du triangle formant la flèche
+     * @param x1 coordonnée x du premier point
+     * @param y1 coordonnée y du premier point
+     * @param x2 coordonnée x du deuxième point
+     * @param y2 coordonnée y du deuxième point
+     * @return tableau des coordonnées des trois points du triangle
+     */
+    private double[] calculerCoordonneesTriangle(double x1, double y1, double x2, double y2) {
+        // Longueur de la flèche
+        double longueurFleche = 15;
+
+        // Angle de la flèche (en radians)
+        double angleFleche = Math.PI / 6; // 30 degrés
+
+        // Calculer l'angle de la ligne
+        double angle = Math.atan2(y2 - y1, x2 - x1);
+
+        // Calculer les coordonnées des trois points du triangle
+        double x3 = x2 - longueurFleche * Math.cos(angle - angleFleche);
+        double y3 = y2 - longueurFleche * Math.sin(angle - angleFleche);
+
+        double x4 = x2 - longueurFleche * Math.cos(angle + angleFleche);
+        double y4 = y2 - longueurFleche * Math.sin(angle + angleFleche);
+
+        // Retourner les coordonnées sous forme de tableau pour la Polyline
+        return new double[] {
+                x2, y2,   // Sommet de la flèche
+                x3, y3,   // Premier point de la base
+                x4, y4,   // Deuxième point de la base
+                x2, y2    // Retour au sommet pour fermer le triangle
+        };
+    }
+}
diff --git a/src/src/twisk/vues/VueMondeIG.java b/src/src/twisk/vues/VueMondeIG.java
index 8b1b5fc..0db916a 100644
--- a/src/src/twisk/vues/VueMondeIG.java
+++ b/src/src/twisk/vues/VueMondeIG.java
@@ -1,19 +1,36 @@
 package twisk.vues;
 
+import javafx.animation.PauseTransition;
+import javafx.scene.control.Alert;
 import javafx.scene.layout.Pane;
-import twisk.modele.EtapeIG;
-import twisk.modele.MondeIG;
+import javafx.util.Duration;
+import twisk.exceptions.ArcException;
+import twisk.modele.*;
 import twisk.outils.Observateur;
 
+import java.util.Iterator;
+
 public class VueMondeIG extends Pane implements Observateur {
     private MondeIG monde;
 
     public VueMondeIG(MondeIG monde) {
         this.monde = monde;
 
+        // Appliquer la classe CSS
+        this.getStyleClass().add("monde");
+
         // S'enregistrer comme observateur du monde
         monde.ajouterObservateur(this);
 
+        // Ajouter un écouteur de clic sur le monde
+        this.setOnMouseClicked(event -> {
+            try {
+                monde.clic(event.getX(), event.getY());
+            } catch (ArcException e) {
+                afficherMessageErreur(e.getMessage());
+            }
+        });
+
         // Initialiser la vue
         reagir();
     }
@@ -23,10 +40,56 @@ public class VueMondeIG extends Pane implements Observateur {
         // Effacer tous les composants existants
         this.getChildren().clear();
 
-        // Ajouter une vue pour chaque étape du monde
+        // IMPORTANT: Afficher d'abord les arcs
+        Iterator<ArcIG> itArcs = monde.iteratorArcs();
+        while (itArcs.hasNext()) {
+            ArcIG arc = itArcs.next();
+            VueArcIG vueArc;
+
+            // Créer la vue appropriée selon le type d'arc
+            if (arc instanceof LigneDroiteIG) {
+                vueArc = new VueLigneDroiteIG(arc);
+            } else if (arc instanceof CourbeIG) {
+                vueArc = new VueCourbeIG(arc);
+            } else {
+                // Ne devrait jamais arriver, mais au cas où
+                continue;
+            }
+
+            this.getChildren().add(vueArc);
+        }
+
+        // Ensuite, afficher les étapes et leurs points de contrôle
         for (EtapeIG etape : monde) {
+            // Créer et ajouter la vue de l'étape
             VueEtapeIG vueEtape = new VueActiviteIG(etape);
             this.getChildren().add(vueEtape);
+
+            // Ajouter les vues des points de contrôle de l'étape
+            for (PointDeControleIG pt : etape) {
+                VuePointDeControleIG vuePt = new VuePointDeControleIG(pt, monde);
+                this.getChildren().add(vuePt);
+            }
         }
     }
+    /**
+     * Affiche un message d'erreur dans une boîte de dialogue
+     * @param message le message à afficher
+     */
+    private void afficherMessageErreur(String message) {
+        // Créer une boîte de dialogue d'alerte
+        Alert alert = new Alert(Alert.AlertType.ERROR);
+        alert.setTitle("Erreur");
+        alert.setHeaderText("Impossible de créer l'arc");
+        alert.setContentText(message);
+
+        // Configurer la fermeture automatique après 3 secondes
+        PauseTransition delay = new PauseTransition(Duration.seconds(3));
+        delay.setOnFinished(event -> alert.close());
+        delay.play();
+
+        // Afficher la boîte de dialogue
+        alert.show();
+    }
+
 }
diff --git a/src/src/twisk/vues/VueOutils.java b/src/src/twisk/vues/VueOutils.java
index 50e50d5..013711d 100644
--- a/src/src/twisk/vues/VueOutils.java
+++ b/src/src/twisk/vues/VueOutils.java
@@ -11,8 +11,12 @@ public class VueOutils extends HBox {
     public VueOutils(MondeIG monde) {
         this.monde = monde;
 
+        // Appliquer la classe CSS
+        this.getStyleClass().add("outils");
+
         // Création du bouton pour ajouter une activité
         Button btnAjouterActivite = new Button("+ Activité");
+        btnAjouterActivite.getStyleClass().add("bouton");
 
         // Ajout d'un tooltip
         Tooltip tooltip = new Tooltip("Ajouter une nouvelle activité");
diff --git a/src/src/twisk/vues/VuePointDeControleIG.java b/src/src/twisk/vues/VuePointDeControleIG.java
new file mode 100644
index 0000000..6389576
--- /dev/null
+++ b/src/src/twisk/vues/VuePointDeControleIG.java
@@ -0,0 +1,68 @@
+package twisk.vues;
+
+import javafx.animation.PauseTransition;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Alert.AlertType;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Circle;
+import javafx.util.Duration;
+import twisk.exceptions.ArcException;
+import twisk.modele.MondeIG;
+import twisk.modele.PointDeControleIG;
+
+/**
+ * Vue d'un point de contrôle
+ */
+public class VuePointDeControleIG extends Circle {
+    private final PointDeControleIG pointDeControle;
+    private final MondeIG monde;
+
+    /**
+     * Constructeur
+     * @param pointDeControle le point de contrôle à représenter
+     * @param monde le monde
+     */
+    public VuePointDeControleIG(PointDeControleIG pointDeControle, MondeIG monde) {
+        super(pointDeControle.getPosX(), pointDeControle.getPosY(), 5); // Rayon de 5 pixels
+        this.pointDeControle = pointDeControle;
+        this.monde = monde;
+
+        // Style du point de contrôle
+        this.setFill(Color.LIGHTBLUE);
+        this.setStroke(Color.BLUE);
+        this.setStrokeWidth(1);
+
+        // Ajouter une classe CSS pour le styling
+        this.getStyleClass().add("point-controle");
+
+    }
+
+
+    /**
+     * Affiche un message d'erreur dans une boîte de dialogue
+     * @param message le message à afficher
+     */
+    private void afficherMessageErreur(String message) {
+        // Créer une boîte de dialogue d'alerte
+        Alert alert = new Alert(AlertType.ERROR);
+        alert.setTitle("Erreur");
+        alert.setHeaderText("Impossible de créer l'arc");
+        alert.setContentText(message);
+
+        // Configurer la fermeture automatique après 3 secondes
+        PauseTransition delay = new PauseTransition(Duration.seconds(3));
+        delay.setOnFinished(event -> alert.close());
+        delay.play();
+
+        // Afficher la boîte de dialogue
+        alert.show();
+    }
+
+    /**
+     * Retourne le point de contrôle associé à cette vue
+     * @return le point de contrôle
+     */
+    public PointDeControleIG getPointDeControle() {
+        return pointDeControle;
+    }
+}
-- 
GitLab