tete du loic

 Loïc YON [KIUX]

  • Enseignant-chercheur
  • Référent Formation Continue
  • Responsable des contrats pros ingénieur
  • Référent entrepreneuriat
  • Responsable de la filière F2 ingénieur
  • Secouriste Sauveteur du Travail
mail
loic.yon@isima.fr
phone
(+33 / 0) 4 73 40 50 42
location_on
ISIMA
  • twitter
  • linkedin
  • viadeo

local_cafe Septi local_cafe

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 :-)