La classe Persp comporte un constructeur réalisant le calcul de la matrice de transformation.

Elle implante des méthodes permettant de réaliser l'ensemble des calculs nécessaires à la mise en perspective:
- transformation géométrique,
- division de x et de y par t.

/**
 * La classe <code>Persp</code> permet l'instanciation d'objets
 * de type transformation geometrique pour mise en perspective.
 * 
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 12/11/08
 */


public class Persp extends TransformationGeometrique3D {

/**
 * Constructeur pour une transformation <code>Persp</code> definie
 * par la position de l'observateur, un point directement vise
 * et la conservation des verticales.
 *
 * @param observateur la {@link Position3D Position3D} definissant
 *   la position de l'observateur
 * @param pointVise la {@link Position3D Position3D} definissant
 *   la position du point directement vise par l'observateur
 */

  public Persp(Position3D observateur,Position3D pointVise,double d) {
    super();
    Direction3D n = new Direction3D(observateur,pointVise);
    double nx = n.getX();
    double ny = n.getY();
    double nz = n.getZ();
    double pox = observateur.getX();
    double poy = observateur.getY();
    double poz = observateur.getZ();
    double a = 1.0/Math.sqrt(1.0-ny*ny);
    c[0][0] = -a*nz;
    c[0][1] = 0.0;
    c[0][2] = a*nx;
    c[0][3] = a*(pox*nz-poz*nx);
    c[1][0] = -a*nx*ny;
    c[1][1] = 1.0/a;
    c[1][2] = -a*nz*ny;
    c[1][3] = (a*ny*(pox*nx+poz*nz)-poy/a);
    c[2][0] = -nx;
    c[2][1] = -ny;
    c[2][2] = -nz;
    c[2][3] = (pox*nx+poy*ny+poz*nz);
    c[3][0] = c[2][0]/d;
    c[3][1] = c[2][1]/d;
    c[3][2] = c[2][2]/d;
    c[3][3] = c[2][3]/d;
  }
  
/**
 * Transforme une {@link CoordonneesHomogenes3D CoordonneesHomogenes3D}
 * en une nouvelle {@link CoordonneesHomogenes3D CoordonneesHomogenes3D}.<br>
 * Les coordonnees x et y sont divisees par t.
 *
 * @param ch la {@link CoordonneesHomogenes3D CoordonneesHomogenes3D} a transformer
 * @return la {@link CoordonneesHomogenes3D CoordonneesHomogenes3D} obtenue
 *   par transformation
 */

  public CoordonneesHomogenes3D transformAll(CoordonneesHomogenes3D ch) {
    double [] v = super.transform(ch).getValue();
    return(new CoordonneesHomogenes3D(v[0]/v[3],v[1]/v[3],v[2],v[3]));
  }
  
/**
 * Transforme une {@link Position3D Position3D} en une nouvelle
 * {@link Position3D Position3D}.<br>
 * Les coordonnees x et y sont divisees par t.<br>
 * t est reaffecte a 1.0.
 *
 * @param p la {@link Position3D Position3D} a transformer
 * @return la {@link Position3D Position3D} obtenue par transformation
 */

  public Position3D transformAll(Position3D p) {
    double [] v = transformAll((CoordonneesHomogenes3D) p).getValue();
    return(new Position3D(v[0],v[1],v[2]));
  }
  
/**
 * Transforme une {@link Direction3D Direction3D} en une nouvelle
 * {@link Direction3D Direction3D}.<br>
 * Les coordonnees x et y sont divisees par t.<br>
 * t est reaffecte a 0.0.
 *
 * @param d la {@link Direction3D Direction3D} a transformer
 * @return la {@link Direction3D Direction3D} obtenue par transformation
 */

  public Direction3D transformAll(Direction3D d) {
    double [] v = transformAll((CoordonneesHomogenes3D) d).getValue();
    return(new Direction3D(v[0],v[1],v[2]));
  }
}

Persp.java

Cette première solution d'implantation d'un afficheur est axée sur l'utilisation des méthodes transform héritées de la classe CoordonneesHomogenes3D qui n'assurent pas la division des coordonnées x et y obtenues par produit matriciel par la coordonnées t. Cela impose une programmation légèrement plus complexe.

import java.awt.*;

/**
 * La classe <code>AfficheurProjectionPerspective</code> implante l'interface
 * {@link Afficheur Afficheur} pour developper une methode d'affichage d'un objet
 * en projection en perspective utilisable au sein
 * d'un {@link ApplicationCanvas ApplicationCanvas}.
 * 
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 12/11/08
 */


public class AfficheurProjectionPerspective implements Afficheur {
  
/**
 * Tableau de stockage des {@link Position3D Position3D} des sommets
 * definissant l'objet affiche.
 */

  private static final Position3D [] pts = { new Position3D( 2.0,0.0,3.0),
                                             new Position3D( 2.0,3.0,3.0),
                                             new Position3D( 0.0,5.0,3.0),
                                             new Position3D(-2.0,3.0,3.0),
                                             new Position3D(-2.0,0.0,3.0),
                                             new Position3D( 2.0,0.0,-3.0),
                                             new Position3D( 2.0,3.0,-3.0),
                                             new Position3D( 0.0,5.0,-3.0),
                                             new Position3D(-2.0,3.0,-3.0),
                                             new Position3D(-2.0,0.0,-3.0) };

/**
 * Tableau de stockage des indices au sein du tableau de {@link Position3D Position3D}
 * definissant les segments de droite de dessin en fil de fer de l'objet affiche.
 */

  private static final int [][] indexe = { {  0, 1 },
                                           {  1, 2 },
                                           {  2, 3 },
                                           {  3, 4 },
                                           {  4, 0 },
                                           {  5, 6 },
                                           {  6, 7 },
                                           {  7, 8 },
                                           {  8, 9 },
                                           {  9, 5 },
                                           {  0, 5 },
                                           {  1, 6 },
                                           {  2, 7 },
                                           {  3, 8 },
                                           {  4, 9 } };

/**
 * Facteur de zoom a l'affichage.
 */

  private static final double zoom = 60.0;
  
/**
 * Methode d'affichage executee en boucle infinie pour realiser l'affichage
 * d'un objet en projection en perspective.
 * 
 * @param g l'objet <code>Graphics</code> d'affichage.
 * @param numeroImage le nombre de fois ou cette methode a deja ete appelee.
 * @param tx la largeur (en pixels) de la zone de dessin.
 * @param ty la hauteur (en pixels) de la zone de dessin.
 */

  public void paint(Graphics g,int numeroImage,int tx,int ty) {
    g.drawString("Image : "+numeroImage,10,20);
    double angle = numeroImage*Math.PI/45.0;
    double x = Math.round(1000.0*Math.cos(angle))/100.0;
    double y = 4.0;
    double z = Math.round(1000.0*Math.sin(angle))/100.0;
    g.drawString("x : "+x,10,40);
    g.drawString("y : "+y,10,60);
    g.drawString("z : "+z,10,80);
    Persp persp = new Persp(new Position3D(x,y,z),
                            new Position3D(0.0,3.0,0.0),-5.0);
    CoordonneesHomogenes3D [] np = new CoordonneesHomogenes3D[pts.length];
    for ( int i = 0 ; i < np.length ; i++ ) {
      CoordonneesHomogenes3D ch = new CoordonneesHomogenes3D(pts[i].getValue());
      CoordonneesHomogenes3D p = persp.transform(ch);
      double [] tab = p.getValue();
      tab[0] /= tab[3];
      tab[1] /= tab[3];
      np[i] = new CoordonneesHomogenes3D(tab); }
    double cx = tx/2.0;
    double cy = ty/2.0;
    for ( int i = 0 ; i < indexe.length ; i++ ) {
      CoordonneesHomogenes3D pi = np[indexe[i][0]];
      CoordonneesHomogenes3D pf = np[indexe[i][1]];
      g.drawLine((int) (cx+pi.getX()*zoom),
                 (int) (cy-pi.getY()*zoom),
                 (int) (cx+pf.getX()*zoom),
                 (int) (cy-pf.getY()*zoom));
    }
  }
}

AfficheurProjectionPerspective.java

Cette seconde solution d'implantation d'un afficheur utilise des méthodes transformAll développées dans la classe Persp qui assurent la division des coordonnées x et y obtenues par produit matriciel par la coordonnées t. Elle ressemble beaucoup à l'afficheur en projection parallèle orthographique.

import java.awt.*;

/**
 * La classe <code>AfficheurProjectionPerspective2</code> implante l'interface
 * {@link Afficheur Afficheur} pour developper une methode d'affichage d'un objet
 * en projection en perspective utilisable au sein
 * d'un {@link ApplicationCanvas ApplicationCanvas}.
 * 
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 12/11/08
 */


public class AfficheurProjectionPerspective2 implements Afficheur {
  
/**
 * Tableau de stockage des {@link Position3D Position3D} des sommets
 * definissant l'objet affiche.
 */

  private static final Position3D [] pts = { new Position3D( 2.0,0.0,3.0),
                                             new Position3D( 2.0,3.0,3.0),
                                             new Position3D( 0.0,5.0,3.0),
                                             new Position3D(-2.0,3.0,3.0),
                                             new Position3D(-2.0,0.0,3.0),
                                             new Position3D( 2.0,0.0,-3.0),
                                             new Position3D( 2.0,3.0,-3.0),
                                             new Position3D( 0.0,5.0,-3.0),
                                             new Position3D(-2.0,3.0,-3.0),
                                             new Position3D(-2.0,0.0,-3.0) };

/**
 * Tableau de stockage des indices au sein du tableau de {@link Position3D Position3D}
 * definissant les segments de droite de dessin en fil de fer de l'objet affiche.
 */

  private static final int [][] indexe = { {  0, 1 },
                                           {  1, 2 },
                                           {  2, 3 },
                                           {  3, 4 },
                                           {  4, 0 },
                                           {  5, 6 },
                                           {  6, 7 },
                                           {  7, 8 },
                                           {  8, 9 },
                                           {  9, 5 },
                                           {  0, 5 },
                                           {  1, 6 },
                                           {  2, 7 },
                                           {  3, 8 },
                                           {  4, 9 } };

/**
 * Facteur de zoom a l'affichage.
 */

  private static final double zoom = 60.0;
  
/**
 * Methode d'affichage executee en boucle infinie pour realiser l'affichage
 * d'un objet en projection en perspective.
 * 
 * @param g l'objet <code>Graphics</code> d'affichage.
 * @param numeroImage le nombre de fois ou cette methode a deja ete appelee.
 * @param tx la largeur (en pixels) de la zone de dessin.
 * @param ty la hauteur (en pixels) de la zone de dessin.
 */

  public void paint(Graphics g,int numeroImage,int tx,int ty) {
    g.drawString("Image : "+numeroImage,10,20);
    double angle = numeroImage*Math.PI/45.0;
    double x = Math.round(1000.0*Math.cos(angle))/100.0;
    double y = 4.0;
    double z = Math.round(1000.0*Math.sin(angle))/100.0;
    g.drawString("x : "+x,10,40);
    g.drawString("y : "+y,10,60);
    g.drawString("z : "+z,10,80);
    Persp persp = new Persp(new Position3D(x,y,z),
                            new Position3D(0.0,3.0,0.0),-5.0);
    Position3D [] np = new Position3D[pts.length];
    for ( int i = 0 ; i < np.length ; i++ )
      np[i] = persp.transformAll(pts[i]);
    double cx = tx/2.0;
    double cy = ty/2.0;
    for ( int i = 0 ; i < indexe.length ; i++ ) {
      Position3D pi = np[indexe[i][0]];
      Position3D pf = np[indexe[i][1]];
      g.drawLine((int) (cx+pi.getX()*zoom),
                 (int) (cy-pi.getY()*zoom),
                 (int) (cx+pf.getX()*zoom),
                 (int) (cy-pf.getY()*zoom));
    }
  }
}

AfficheurProjectionPerspective2.java

RETOUR