Teaching - 2i002 - (TME: sujets)


2i002 : Introduction à la programmation Objet

Exercice LOGO

Le but de cet exercice est de proposer un environnement de type LOGO, en version objet. Dans le LOGO, une tortue joue le rôle centrale: elle porte un stylo, se déplace sur une feuille et reçoit des ordres pour avancer et tourner. Au bout d'un certains nombres d'instructions, la tortue dessine un motif.

Pour plus d'informations (A LA MAISON, PAS DURANT LE TME): page wikipedia

Travail préliminaire: classe Vecteur (pour faire de la géométrie)

Afin de repérer la position et la direction de la tortue, nous avons besoin d'un Vecteur. Le vecteur a deux attributs réels x et y, il permet de stocker une position (x et y sont alors des coordonnées) mais aussi une direction (x et y sont alors les dimensions d'un vecteur en 2D).

Définition et fonctionnalités

Attributs:

  • double x,y

Méthodes:

  • Constructeur avec 2 arguments
  • Méthodes d'addition:
    • addition génératrice: v1 et v2 forment v3 qui est retourné

** auto-addition: les coordonnées de v2 sont additionnées sur l'instance courrante

  • toString(): pour le debbuggage
  • Accesseur getX() et getY() (ils sont nécessaires dans le dernier exercice)
  • Méthode de rotation (pour incliner la direction de la tortue) d'un angle theta page wikipedia. Un angle, appliqué sur v1, permet de générer un nouveau vecteur v2 qui est retourné.
    • xnew = x \cos(\theta) - y \sin(\theta)
    • ynew = x \sin(\theta) + y \cos(\theta)

NB: toutes les fonctions mathématiques se trouvent dans la classe Math (Math.sin, Math.cos, Math.PI...)
NB2: tous les angles sont en radians

Test de la classe Vecteur

Avant d'aller plus loin, créer une classe de test avec un main pour tester que les fonctions marchent correctement.

  • vérification de toString en affichant des vecteurs de test
  • Addition de [1,2] avec [0, 0] donne [1,2]
  • Addition de [1,2] avec [10, 1] donne [11,3]
  • Rotation de Math.PI/2 sur [0,1] donne [-1, 0]
  • Rotation de Math.PI/2 sur [1,1] donne [-1, 1]

Ayez toujours un brouillon pour créer des cas de test et vérifier les résultats

Deuxième étape: jouer avec les images en JAVA

Il faut utiliser les instructions suivantes en comprenant la philosophie du code mais sans s'attarder sur les éléments techniques qui seront vus plus loin dans l'UE.

 import java.awt.Graphics;
 import java.awt.image.BufferedImage;
 import java.io.*;
 import javax.imageio.ImageIO;

 public class TestImage {
    public static void main(String[] args) {        
        // Construction d'une image 600x800
        int nColonnes = 800;
        int nLignes = 600;
        BufferedImage im = // objet image en mémoire
                new BufferedImage(nColonnes, nLignes, BufferedImage.TYPE_INT_ARGB);

        // récupération d'un stylo pour écrire dans l'image
        Graphics g = im.getGraphics();

        // tracer une ligne entre le point (10,10) et le point (100, 50)
        g.drawLine(10, 10, 100, 50);

        // Sauver l'image dans un fichier
        try {
            File outputfile = new File("saved.png");
            ImageIO.write(im, "png", outputfile);
         } catch (IOException e) {
            System.out.println("Erreur lors de la sauvegarde");
         }
    }
}

NB: ce programme n'affiche rien dans la console, il crée une image qu'il faut ensuite ouvrir avec un visualiseur (en général, il suffit de cliquer dans l'explorateur de fichiers).

L'exemple ci-dessus doit vous permettre de comprendre le fonctionnement basique d'une image... Vous êtes prêt pour jouer avec maintenant.

Aide sur les images (création...):
http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html

Aide sur le stylo (formes réalisables, choix des couleurs...)
http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics.html

Dans le cadre de cet exercice, vous avez besoin de :

  • drawline
  • éventuellement: setColor

ATTENTION Le repère image est particulier. Comme le montre l'image suivante, le point (0,0) est en haut à gauche, la première coordonnée désigne les colonnes, la seconde les lignes. Le repère est donc inversé et le sens trigo est toujours de l'axe x vers l'axe y... Je donne un exemple avec la tortue pour s'y repérer plus clairement.

On peut y aller! : le LOGO et la tortue

Classe Tortue

La tortue est composée des attributs suivants:

  • Vecteur position et direction
  • boolean draw (position levée ou baissée du stylo, la tortue se déplace parfois sans écrire)
  • Graphics g (la tortue doit avoir la main sur le stylo pour pouvoir dessiner au fur et à mesure de ses déplacements)

Méthodes:

  • Constructeur (donner le Graphics en argument, cf exemple ci-dessous)
    • par défaut: direction (1,0)
    • position (200,200) : pour partir du centre de l'image et être sûr d'avoir quelque chose à voir
    • draw = true
  • lever/baisser le stylo

* accesseur sur la position et la direction

  • avancer(int lg)
    • fonctionnement détaillé ci-dessous
  • rotation(double theta)
    • appliquer la rotation de l'angle theta sur la direction

Image de gauche: représentation de la tortue dans l'image, par sa position et sa direction. Image de droite: Illustration de la suite de commandes: AVANCE(20), TOURNE(-PI/3), AVANCE(10)

Méthode void avancer(int lg)

Cette méthode repose sur une boucle for. Avancer de 10 signifie faire 10 pas élémentaires. Si le stylo est en position baissée, il faut penser à imprimer les pixels au fur et à mesure de l'avancement, sinon, on se contente d'avancer. En pseudo-code, ça donne la solution suivante: void avancer(int lg)

  • Pour i allant de 1 à lg
    • position=position+direction : déplacement élémentaire illustré ci-dessous
    • Si draw Alors
      • g.drawLine((int) position.getX(), (int) position.getY(), (int) position.getX(), (int) position.getY())

NB: il n'est pas possible de dessiner un pixel par défaut... L'astuce consiste à dessiner une ligne qui part d'un point et arrive au même point.

Exemple de programme (et dessin associé)

import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;

public class TestTortue {


    public static void main(String[] args) {

        // Construction d'une image 600x600
        int nColonnes = 600;
        int nLignes = 600;
        BufferedImage im = // objet image en mémoire
                new BufferedImage(nColonnes, nLignes, BufferedImage.TYPE_INT_ARGB);

        // mise au bleu de tous les pixels pour mieux voir
        for(int i=0; i<im.getWidth();i++)
            for(int j=0; j<im.getHeight();j++)
                im.setRGB(i, j, Color.blue.getRGB()); // mettre le pixel (i,j) en bleu

        // récupération d'un stylo pour écrire dans l'image
        Graphics g = im.getGraphics();

        // création de la tortue
        Tortue t = new Tortue(g); // direction initiale (1,0),
                                 // position (0,0) = coin haut gauche

        t.leverStylo(); // ne pas écrire
        t.rotation(Math.PI/4); // aller vers le centre (ATTENTION AU SENS DE ROTATION)
        t.avancer(200); // approximativement au centre

        // Dessin
        t.baisserStylo();
        t.avancer(100);
        t.rotation(Math.PI/4);
        t.avancer(50);

        // Sauver l'image dans un fichier
        try {
            File outputfile = new File("saved.png");
            ImageIO.write(im, "png", outputfile);
         } catch (IOException e) {
            System.out.println("Erreur lors de la sauvegarde");
         }
    }
}

Algorithmes avancés

Tracer un rond

  • Pour i entre 0 et 359
    • avancer de 1
    • tourner de Math.PI/180

Tracer une rosace

  • Pour i entre 0 et 50
    • tracer un rond
    • tourner de Math.PI/50*2

Tracer les motifs proposés sur la page suivante:

lien

Tracer une fractale (flocon de Koch)

http://fr.wikipedia.org/wiki/Flocon_de_Koch

  • Pour un segment de longeur 4 lg
    • avancer de lg
    • tourner de -Math.PI/3
    • avancer de lg
    • tourner de Math.PI/3*2
    • avancer de lg
    • tourner de -Math.PI/3
    • avancer de lg