Date de première publication : 2024/1O/01
S comme Sept, comme Supplémentaire et comme SVG.
L'idée du TP est de développer un programme qui va générer les instructions au format SVG d'une scène graphique composée de formes.
Dans la proposition qui est faite, on affiche des chaines de caractères à l'écran.
L'arborescence du projet final donne quelque chose comme cela :
├── Application.java
├── forme
│ ├── Cercle.java
│ ├── Forme.java
│ ├── Groupe.java
│ ├── Rectangle.java
│ ├── Scene.java
│ └── Triangle.java
├── lib
└── tests
forme
est le package où sont rangées les formes, lib
contient les bibliothèques externes comme celle des tests unitaires
et tests
contient les tests unitaires.
git clone https://gitlab.com/kiux/java-forme.git
Minimum Viable Product
Une forme abstraite peut être convertie en SVG. On la repèrera grossièrement par une boite englobante (connue par deux coordonnées et une largeur et une hauteur - ces informations peuvent être pertinentes avec une interface graphique)
Les formes peuvent être groupées (éventuellement dans une scène).
Classe Forme
La classe a une méthode abstraite toSVG()
. On peut choisir la couleur de la forme qui est une chaine de caractère,
au format HTML. Par exemple le noir peut être désigné par "black" ou "#000000".
Classe Rectangle
La classe Rectangle est la Forme la plus facile à écrire. Après avoir ajouté les bons attributs
, les accesseurs et les constructeurs. On pourra redéfinir la méthode toSVG()
comme suit :
@Override
public String toSVG() {
StringBuffer sb = new StringBuffer("<rect ");
sb.append("x=\"").append(getX()).append("\" ");
sb.append("y=\"").append(getY()).append("\" ");
sb.append("width=\"").append(getWidth()).append("\" ");
sb.append("height=\"").append(getHeight()).append("\" ");
sb.append("fill=\"").append(getColor()).append("\" ");
sb.append("/>");
return sb.toString();
}
classe Groupe
La classe Groupe
est un peu particulière car elle permet de traiter un ensemble de formes comme une forme.
Il faut tout d'abord choisir comment stocker les objets, sachant que l'on pourrait être intéressés par changer l'ordre des objets (passer un objet en avant-plan ou en arrière-plan par exemple).
Hormis les méthodes spécifiques pour ajouter ou enlever une forme, il faut penser à adapter la génération du SVG afficher les différentes formes du groupe.
@Override
public String toSVG() {
StringBuffer sb = new StringBuffer();
// une belle boucle
return sb.toString();
}
classe Scene
On se sert de cette classe pour gérer l'ensemble de nos formes au plus haut niveau. La méthode toSVG()
permet de gérer l'entête du format :
@Override
public String toSVG() {
StringBuffer r = new StringBuffer();
r.append("<svg version=\"1.1\" ");
r.append("baseProfile=\"full\" ");
r.append("xmlns=\"http://www.w3.org/2000/svg\" >\n");
// appeler la méthode de la classe mère
r.append("</svg>");
return sb.toString();
}
Compléments
On propose d'ajouter une identification des formes, le clonage et des formes spécifiques : le cercle et le triangle.
Identifiants pour les formes
Pour faciliter le repérage des formes, on les identifiera avec un identifiant unique id
.
Clonage
On proposera également de cloner une forme.
Si cela ne pose pas de problème pour une classe basique comme Rectangle
où la copie de surface est suffisante, il faudra faire attention à la redéfinition de la classe Groupe
où la copie en profondeur est nécessaire.
Voici un bout de test unitaire qui vérifie que la copie en profondeur a été faite. Si ce n'est pas le cas, le test est défaillant :
@Test
public void cloneGroup() {
Groupe g1 = new Groupe();
Rectangle r = new Rectangle(10, 20, 300, 400, "orange");
g1.ajouter(r);
Groupe g2 = (Groupe) g1.clone();
r.setX(20);
assertNotEquals(g1.toSVG(), g2.toSVG());
}
La classe Cercle
Un cercle est connu avec les coordonnées du centre (cx
, cy
) et du rayon (r
).
Le morceau de code pour obtenir le SVG équivalent est le suivant :
@Override
public String toSVG() {
StringBuffer sb = new StringBuffer("<circle ");
sb.append("cx=\"").append(getX()+getWidth()/2).append("\" ");
sb.append("cy=\"").append(getY()+getWidth()/2).append("\" ");
sb.append("r=\"").append(getWidth()/2).append("\" ");
sb.append("fill=\"").append(getColor()).append("\" ");
sb.append("/>");
return sb.toString();
}
La classe Triangle
Pour le triangle, on se contente d'avoir trois couples de coordonnées : x1
, y1
, x2
, y2
, x3
, y3
Le morceau de code pour obtenir le SVG équivalent est le suivant :
@Override
public String toSVG() {
StringBuffer sb = new StringBuffer("<polygon ");
sb.append("points=\"");
sb.append(x1).append(", ");
sb.append(y1).append(" ");
sb.append(x2).append(", ");
sb.append(y2).append(" ");
sb.append(x3).append(", ");
sb.append(y3).append("\" ");
sb.append("fill=\"").append(getColor()).append("\" ");
sb.append("/>");
return sb.toString();
}
(Dé)sérialisation d'une scène
Avec les morceaux de code fournis en cours, il est très facile de proposer la lecture et l'écriture d'une scène dans un fichier.
Même si la scène est complexe, elle est complètement reconstruite à la lecture et cà, c'est génial :-)
- 1
- 2
- 3
- 4
- 5
- 6
- 7