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]));
}
}
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));
}
}
}