Skip to content
Snippets Groups Projects
Commit 264d2bba authored by test's avatar test
Browse files

TP2

parent 615c58f7
Branches
No related tags found
No related merge requests found
Showing
with 1097 additions and 27 deletions
......@@ -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);
......
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);
}
}
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);
}
}
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());
}
}
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;
}
}
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;
}
}
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();
}
}
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);
}
}
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));
}
}
}
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;
}
}
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;
}
}
/* 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);
}
......@@ -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
}
}
}
......@@ -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());
}
}
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");
}
}
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
};
}
}
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
};
}
}
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();
}
}
......@@ -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é");
......
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;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment