ENPC - Programmation - Corrections 5

La classe Point

public class Point {
  // Coordonnées du point
  private double x;
  private double y;

  /**
   * Constructeur d'un point acceptant ses deux coordonnées.
   */
  public Point(double x, double y) {
    this.x = x;
    this.y = y;
  }

  /**
   * Constructeur d'un point sans argument; les coordonées sont mises à (0,0).
   * Ce constrcuteur crée une surcharge: deux constrcuteurs ont même noms mais
   * celui qui est appelé est choisis grâce aux arguments qui sont passés à son appel.
   */
  public Point() {
    this.x = 0;
    this.y = 0;
    // Ces deux instructions peuvent être remplacées par la seule suivante:
    // this(0,0);
    // qui appelle l'autre constructeur
  }

  /**
   * Déplace un point de dx en abscisse et de dy en ordonnée.
   */
  public void translate(double dx, double dy) {
    x = x + dx;
    y = y + dy;
  }

  /**
   * Déplace un point de d en abscisse et de d en ordonnée.
   * Cette méthode est une surcharge de la précédente
   */
  public void translate(double d) {
    // Une première solution est la suivante :
    // x = x + d;
    // y = y + d;
    // Une autre façon plus élégante est d'appeler l'autre méthode:
    translate(d,d);
  }

  /**
   * Donne la représentation d'un point sous la forme (x,y).
   */
  public String toString() {
    return "(" + x + "," + y + ")";
  }

  /**
   * Retourne vrai si p a les même coordonnées que l'instance de cette
   * classe, et faux sinon.
   */
  public boolean same(Point p) {
    return ( (p.x == this.x) && (p.y == this.y) );
  }
  
  public static void main(String[] args) {
    Point o = new Point(0,0);
    System.out.println(o.toString());
    Point p = new Point(1.5,3.4);
    System.out.println(p.toString());
    p.translate(0.5,-1.4);
    System.out.println("Après translation: " + p.toString());

    Point p1 = new Point();
    Point p2 = new Point();
    System.out.println(p1 == p2);       // affiche false
    System.out.println(p1.same(p2));    // affiche true
  }
}

La classe Disque

public class Disque {
  
  private Point centre;
  private double rayon;      

  /**
   * Construit un disque à partir du centre et du rayon passés en arguments.
   */
  public Disque(Point centre, double rayon) {
    this.centre = centre;
    this.rayon = rayon;
  }

  /**
   * Construit un disque dont le centre est un Point par défaut et
   * dont le rayon est 1.
   */
  public Disque() {
    this.centre = new Point();
    this.rayon = 1;
  }

  /**
   * Donne la représentation d'un disque sous la forme:
   * Disque - centre: (x,y) rayon: r.
   */
  public String toString() {
    // La représentation du centre est de la responsabilité de la classe Point
    // Il est donc important de lui "déléguer" cette tâche en appelant la méthode
    // toString() sur l'objet centre. 
    return "Disque - centre: " + centre.toString() + " rayon: " + rayon;
  }

  /**
   * Déplace le disque de dx en abscisse et de dy en ordonnée.
   */
  public void translate(double dx, double dy) {
    // Pour déplacer le disque, il suffit de déplacer son centre. 
    centre.translate(dx,dy);
  }

  /**
   * Retourne la surface du disque.
   */ 
  public double surface() {
    // On utilise la constante (final static) PI de la classe java.lang.Math
    return  Math.PI * rayon * rayon;
  }

  /**
   * Retourne vrai si les deux disques ont des centres de mêmes
   * coordonnées et un même rayon.
   * On délègue le test d'égalité des centres à la classe Point.
   */
  public boolean same(Disque d) {
    return ((centre.same(d.centre)) && (rayon == d.rayon) );
  }

  public static void main(String[] args) {
    Point p = new Point(3.4, 5.7);
    Disque d = new Disque(p,4);
    System.out.println(d.toString());
    System.out.println("Surface du disque : " + d.surface());
    d.translate(1.6, -0.7);
    System.out.println("Après translation : " + d.toString());

    Disque d2 = new Disque(p,4);
    // Attention: réfléchissez à quel est l'état de p ici...
    System.out.println(d == d2);          // affiche false
    System.out.println(d.same(d2));       // affiche true
  }
}

La méthode isIn()

Il est prfrable de commencer par écrire dans la classe Point une méthode distance() qui calcule la distance entre deux points:
public class Point {
  ...

  /**
   * Retourne la distance entre ce point et p.
   */
  public double distance(Point p) {
    return Math.sqrt((x - p.x)*(x - p.x) + (y - p.y)*(y - p.y));
  }
  ...
}
Ensuite, il est plus facile d'écrire la méthode isIn() dans la classe Disque:
public class Disque {
  ...  
  /**
   * Retourne vrai si p est dans le disque et faux sinon.
   */
  public boolean isIn(Point p) {
    return (centre.distance(p) <= rayon);
  }
  ...
}

La méthode howManyIn()

  /**
   * Retourne le nombre de points du tableau tab qui sont dans le disque.
   */
  public int howManyIn(Point[] tab) {
    int total = 0;
    for(int i = 0; i<tab.length; i++) {
      if (isIn(tab[i]))
	total++;
    }
    return total;
  }

La méthode de tri

Le sujet de cet exercice supplémentaire est le suivant:
Écrire une méthode de tri d'un tableau de point qui accepte deux paramètres. L'un est le tableau à trier et l'autre est un booléen: si le booléen est vrai, il faut trier les points selon leur abscisse, si le booléen est faux, il faut les trier selon leur ordonnée.

La première solution sort1() donnée ici n'est pas très satisfaisante. Elle nécessite de toute façon d'écrire la méthode dans la classe Point pour diposer de la visibilité de x et de y.

  /**
   * Tri le tableau de points passés en argument par x croissant si b
   * est vrai et par y croissant si b est faux.
   */
  public static void sort1(Point[] t, boolean b) {
    if(b) {
      for(int i = 1; i<t.length; i++) {
	for(int j = 0; j<t.length-i; j++) {
	  if(t[j].x>t[j+1].x) {
	    Point tmp = t[j];
	    t[j] = t[j+1];
	    t[j+1] = tmp;
	  }
	}
      }
    } else {
      for(int i = 1; i<t.length; i++) {
	for(int j = 0; j<t.length-i; j++) {
	  if(t[j].y>t[j+1].y) {
	    Point tmp = t[j];
	    t[j] = t[j+1];
	    t[j+1] = tmp;
	  }
	}
      }

    }
  }

La seconde solution sort2() ici-dessous est un peu mieux car elle permet d'écrire cette méthode indépendament de la visibilité de x et de y, éventuellement à l'extérieur de la classe Point. D'une part, la méthode de tri est plus élégante et d'autre part, c'est la méthode greater() qui se charge d'encapsuler le choix de x ou de y comme référentiel de comparaison en fonction du booléen.

  // Dans la classe Point, trois nouvelles méthodes:

  /**
   * Retourne vrai si this est plus grand que p en les comparants sur
   * x si b est vrai et sur y si b est faux.
   */
  public boolean greater(Point p, boolean b) {
    // Si b est vrai, c'est comparaison en x
    if (b) 
      return greaterInX(p);
    // Sinon, c'est comparaison en y
    return greaterInY(p);
  }
  
  /**
   * Retourne vrai si this est plus grand que p en les comparants sur x.
   */
  private boolean greaterInX(Point p) {
    // Si p est plus grand en x on retourne faux
    if (this.x < p.x)
      return false;
    // Sinon on retourne vrai
    return true;
  }

  /**
   * Retourne vrai si this est plus grand que p en les comparants sur y.
   */
  private boolean greaterInY(Point p) {
    // Si p est plus grand en y on retourne faux
    if (this.y < p.y)
      return false;
    // Sinon on retourne vrai
    return true;
  }

// N'importe où (pas nécessairement dans Point, la nouvelle méthode
de tri:
 
  /**
   * Tri le tableau de points passés en argument par x croissant si b
   * est vrai et par y croissant si b est faux.
   */
  public static void sort2(Point[] t, boolean b) {
    for(int i = 1; i<t.length; i++) {
      for(int j = 0; j<t.length-i; j++) {
	if(t[j].greater(t[j+1], b)) {
	  Point tmp = t[j];
	  t[j] = t[j+1];
	  t[j+1] = tmp;
	}
      }
    }
  }

  // Un exemple d'utilisation:
 
  public static void main(String[] args) {
    Point t[] = new Point[]{
      new Point(2,3),
      new Point(3,2),
      new Point(1,4),
      new Point(3,5),
      new Point(4,2),
    };
    System.out.println("Trié sur x :");
    sort2(t,true);
    for(int i=0; i<t.length; i++)
      System.out.print(t[i]+" ");
    System.out.println();
    System.out.println("Trié sur y :");
    sort2(t,false);
    for(int i=0; i<t.length; i++)
      System.out.print(t[i]+" ");
  }

Nous verrons un peu plus tard qu'il est possible d'avoir une solution plus élégante en utilisant un Comparateur


Etienne.Duris[at]univ-mlv.fr - © École Nationale des Ponts et Chaussées - Décembre 2001 - http://www-igm.univ-mlv.fr/~duris/ENPC/