La classe Shapes
¶
- Github: Shapes.java
Code
package v1;
import java.awt.Color;
public class Shapes {
public static Color defaultColor = Color.BLACK;
public static Image image = new Image(400);
public static void drawPoint(int x, int y) {
drawPoint(x, y, defaultColor);
}
public static void drawPoint(int x, int y, Color color) {
image.SetPixel(x, y, color);
}
public static void drawHorizontalLine(int x1, int y1, int width) {
drawHorizontalLine(x1, y1, width, defaultColor);
}
public static void drawHorizontalLine(int x1, int y1, int width, Color color) {
for (int i = 0; i < width; i++) {
drawPoint(x1 + i, y1, color);
}
}
public static void drawVerticalLine(int x1, int y1, int height) {
for (int j = 0; j < height; j++) {
drawPoint(x1, y1 + j, defaultColor);
}
}
public static void drawVerticalLine(int x1, int y1, int height, Color color) {
for (int j = 0; j < height; j++) {
drawPoint(x1, y1 + j, color);
}
}
public static void drawLine(int x1, int y1, int x2, int y2) {
drawLine(x1, y1, x2, y2, defaultColor);
}
public static void drawLine(int x1, int y1, int x2, int y2, Color color) {
// ligne verticale, il faut éviter une division par 0
if (x1 == x2) {
drawVerticalLine(x1, Math.min(y1, y2), Math.abs(y2 - y1) + 1, color);
return;
}
// éviter une division int/int qui entraînerait une imprécision
double slope = (y2 - y1) / (double) (x2 - x1);
double intercept = y2 - slope * x2;
if (Math.abs(slope) < 1) {
drawCloserToHorizontal(x1, x2, slope, intercept, color);
} else {
drawCloserToVertical(y1, y2, intercept, slope, color);
}
}
private static void drawCloserToVertical(int startY, int endY, double intercept, double slope, Color color) {
int minY = Math.min(startY, endY);
int maxY = Math.max(startY, endY);
for (int y = minY; y <= maxY; y++) {
int x = (int) Math.round((y - intercept) / slope);
image.SetPixel(x, y, color);
}
}
private static void drawCloserToHorizontal(int startX, int endX, double slope, double intercept, Color color) {
int minX = Math.min(startX, endX);
int maxX = Math.max(startX, endX);
for (int x = minX; x <= maxX; x++) {
int y = (int) Math.round(slope * x + intercept);
image.SetPixel(x, y, color);
}
}
public static void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3) {
drawTriangle(x1, y1, x2, y2, x3, y3, defaultColor);
}
public static void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color) {
drawLine(x1, y1, x2, y2, color);
drawLine(x2, y2, x3, y3, color);
drawLine(x3, y3, x1, y1, color);
}
public static void drawRectangle(int x, int y, int width, int height) {
drawRectangle(x, y, width, height, defaultColor);
}
public static void drawRectangle(int x, int y, int width, int height, Color color) {
drawLine(x, y, x + width, y, color);
drawLine(x + width, y, x + width, y + height, color);
drawLine(x + width, y + height, x, y + height, color);
drawLine(x, y + height, x, y, color);
}
public static void drawSquare(int x, int y, int width) {
drawSquare(x, y, width, defaultColor);
}
public static void drawSquare(int x, int y, int width, Color color) {
//noinspection SuspiciousNameCombination
drawRectangle(x, y, width, width, color);
}
public static void drawPolyLine(int[] x, int[] y) {
drawPolyLine(x, y, defaultColor);
}
public static void drawPolyLine(int[] x, int[] y, Color color) {
for (int i = 1; i < x.length; i++) {
drawLine(x[i - 1], y[i - 1], x[i], y[i], color);
}
}
public static void drawPolygon(int[] x, int[] y) {
drawPolygon(x, y, defaultColor);
}
public static void drawPolygon(int[] x, int[] y, Color color) {
drawPolyLine(x, y, color);
drawLine(x[0], y[0], x[x.length - 1], y[y.length - 1], color);
}
public static void drawCircle(int x, int y, int radius) {
drawCircle(x, y, radius, defaultColor);
}
public static void drawCircle(int x, int y, int radius, Color color) {
int cos45 = (int) Math.round(radius * Math.cos(Math.PI / 4));
for (int i = 0; i <= cos45; i++) {
int j = (int) Math.round(Math.sqrt(radius * radius - i * i));
image.SetPixel(x + i, y + j, color); // point 1
image.SetPixel(x - i, y + j, color); // point 2: symétrie du point 1 par rapport à l'axe Y
image.SetPixel(x + i, y - j, color); // point 3: symétrie du point 1 par rapport à l'axe X
image.SetPixel(x - i, y - j, color); // point 4: symétrie du point 3 par rapport à l'axe Y
image.SetPixel(x + j, y + i, color); // point 5: symétrie du point 1 par rapport à la diagonale 45°
image.SetPixel(x + j, y - i, color); // point 6: symétrie du point 5 par rapport à l'axe X
image.SetPixel(x - j, y + i, color); // point 7: symétrie du point 5 par rapport à l'axe Y
image.SetPixel(x - j, y - i, color); // point 8: symétrie du point 7 par rapport à l'axe X
}
}
}
La classe Shapes
fournit des méthodes statiques pour dessiner différentes formes sur une image. Elle utilise une image
Image
de taille 400x400 pixels et une couleur par défaut Color.BLACK
.
Voici une explication des méthodes :
-
Méthodes de dessin de points et de lignes :
drawPoint(x, y)
etdrawPoint(x, y, color)
: Dessine un point aux coordonnées(x, y)
avec la couleur spécifiée ou la couleur par défaut.drawHorizontalLine(x1, y1, width)
etdrawHorizontalLine(x1, y1, width, color)
: Dessine une ligne horizontale à partir de(x1, y1)
sur une largeur donnée.drawVerticalLine(x1, y1, height)
etdrawVerticalLine(x1, y1, height, color)
: Dessine une ligne verticale à partir de(x1, y1)
sur une hauteur donnée.drawLine(x1, y1, x2, y2)
etdrawLine(x1, y1, x2, y2, color)
: Dessine une ligne entre les points(x1, y1)
et(x2, y2)
. Elle gère les cas particuliers des lignes verticales et optimise le dessin en fonction de la pente de la ligne.
-
Méthodes de dessin de formes :
drawTriangle(x1, y1, x2, y2, x3, y3)
etdrawTriangle(x1, y1, x2, y2, x3, y3, color)
: Dessine un triangle en reliant les trois points donnés.drawRectangle(x, y, width, height)
etdrawRectangle(x, y, width, height, color)
: Dessine un rectangle avec le coin supérieur gauche à (x, y), la largeur et la hauteur spécifiées.drawSquare(x, y, width)
etdrawSquare(x, y, width, color)
: Dessine un carré avec le coin supérieur gauche à(x, y)
et le côté de longueurwidth
.drawPolyLine(x[], y[])
etdrawPolyLine(int[] x, int[] y, Color color)
: Dessine une ligne brisée en reliant les points spécifiés par les tableauxx
ety
.drawPolygon(x[], y[])
etdrawPolygon(int[] x, int[] y, Color color)
: Dessine un polygone en reliant les points spécifiés par les tableaux x et y et en fermant le polygone.drawCircle(x, y, radius)
etdrawCircle(x, y, radius, color)
: Dessine un cercle de centre(x, y)
et de rayonradius
. Il utilise une méthode optimisée pour dessiner des points sur le cercle en utilisant la symétrie et les propriétés du cercle.
Chaque méthode de dessin a une version avec et sans le paramètre color
. Si la couleur n’est pas spécifiée, la couleur
par défaut (Color.BLACK
) est utilisée. Toutes les méthodes modifient directement l’image image
statique.
Méthode drawLine
¶
La méthode drawLine(int x1, int y1, int x2, int y2, Color color)
dessine une ligne entre les points (x1, y1)
et
(x2, y2)
avec la couleur spécifiée. Voici une explication détaillée :
Cas particulier : ligne verticale¶
Si x1
est égal à x2
, la ligne est verticale. Dans ce cas, la méthode drawVerticalLine
est appelée pour
dessiner la ligne. Ceci est important, car le calcul de la pente dans le cas général impliquerait une division par
zéro.
Calcul de la pente et de l’ordonnée à l’origine¶
Si la ligne n’est pas verticale, la pente (slope
) et
l’ordonnée à l’origine (intercept
) sont calculées. Le calcul de la pente est effectué avec un cast en double
pour
l’un des termes afin d’éviter une division entière qui pourrait entraîner une perte de précision.
Optimisation basée sur la pente¶
La méthode utilise une optimisation pour minimiser l’effet d’escalier (aliasing) :
- Si la valeur absolue de la pente est inférieure à 1, la ligne est plus proche de l’horizontale. Dans ce cas, la
méthode
drawCloserToHorizontal
est appelée. Cette méthode itère sur les coordonnées x et calcule la coordonnée y correspondante en utilisant l’équation de la droite :y = slope * x + intercept
. - Si la valeur absolue de la pente est supérieure ou égale à 1, la ligne est plus proche de la verticale. Dans ce
cas, la méthode
drawCloserToVertical
est appelée. Cette méthode itère sur les coordonnées y et calcule la coordonnée x correspondante en utilisant l’équation :x = (y - intercept) / slope
.
drawCloserToHorizontal
¶
Cette méthode parcourt les valeurs de x entre minX
et maxX
(les valeurs minimales et maximales de x1 et x2). Pour
chaque valeur de x, elle calcule la valeur de y correspondante à l’aide de l’équation de la droite et arrondit à
l’entier le plus proche. Ensuite, elle appelle image.SetPixel(x, y, color)
pour dessiner le point.
drawCloserToVertical
¶
Cette méthode est similaire à drawCloserToHorizontal
, mais elle itère sur les valeurs de y entre minY
et maxY
.
Pour chaque valeur de y, elle calcule la valeur de x, l’arrondit et dessine le point.
Résumé¶
En résumé, la méthode drawLine
gère les cas particuliers des lignes verticales, calcule la pente et l’ordonnée à
l’origine, puis choisit la méthode de dessin la plus appropriée en fonction de la pente pour minimiser l’effet
d’escalier et dessiner une ligne plus lisse.
Méthodes drawCloserToHorizontal
et drawCloserToVertical
¶
drawCloserToHorizontal
¶
Cette méthode parcourt les valeurs de x entre minX
et maxX
(les valeurs minimales et maximales de x1 et x2). Pour
chaque valeur de x, elle calcule la valeur de y correspondante à l’aide de l’équation de la droite et arrondit à
l’entier le plus proche. Ensuite, elle appelle image.SetPixel(x, y, color)
pour dessiner le point.
drawCloserToVertical
¶
Cette méthode est similaire à drawCloserToHorizontal
, mais elle itère sur les valeurs de y entre minY
et maxY
.
Pour chaque valeur de y, elle calcule la valeur de x, l’arrondit et dessine le point.
Les variables minX
, maxX
, minY
et maxY
dans les méthodes drawCloserToHorizontal
et drawCloserToVertical
sont
essentielles pour déterminer les bornes de l’itération et garantir que la ligne est dessinée correctement, quel que soit
l’ordre des points fournis.
Voici pourquoi elles sont utiles :
-
Indépendance de l’ordre des points : L’utilisateur peut appeler
drawLine
avec(x1, y1)
et(x2, y2)
dans n’importe quel ordre.minX
etmaxX
(ouminY
etmaxY
) garantissent que la bouclefor
itère toujours du plus petit au plus grand, quel que soit l’ordre des points d’entrée. Sans ces variables, six1 > x2
, la bouclefor
dansdrawCloserToHorizontal
ne s’exécuterait pas, et aucune ligne ne serait dessinée. -
Détermination des bornes de la ligne : Ces variables définissent les limites du segment de droite à dessiner. Elles garantissent que tous les pixels entre les deux points spécifiés sont parcourus et potentiellement colorés. Sans ces limites, la ligne pourrait être dessinée au-delà des points d’extrémité souhaités ou être incomplète.
-
Optimisation des performances : En déterminant les bornes minimales et maximales, la boucle
for
itère uniquement sur les valeurs nécessaires pour dessiner la ligne. Cela évite des itérations inutiles et optimise les performances du dessin, en particulier pour les longues lignes.
En résumé, ces variables locales permettent de gérer l’ordre des points d’entrée, de définir les bornes correctes du
segment de droite et d’optimiser les performances du dessin. Elles sont donc cruciales pour le bon fonctionnement des
méthodes drawCloserToHorizontal
et drawCloserToVertical
.
Méthode drawPolyLine
¶
La méthode drawPolyLine(int[] x, int[] y, Color color)
dessine une ligne brisée en reliant les points spécifiés par
les tableaux x
et y
avec la couleur donnée. La boucle for
dans cette méthode est au cœur de son fonctionnement :
Voici une explication détaillée :
-
Initialisation :
int i = 1;
La boucle commence à l’indice 1, et non à 0.
-
Condition :
i < x.length;
La boucle continue tant que
i
est strictement inférieur à la longueur du tableaux
. Ceci est important, car la boucle accède aux élémentsx[i]
etx[i-1]
. -
Incrémentation :
i++;
À chaque itération,
i
est incrémenté de 1. -
Corps de la boucle :
drawLine(x[i - 1], y[i - 1], x[i], y[i], color);
Le corps de la boucle appelle la méthode
drawLine
pour tracer un segment entre deux points consécutifs de la ligne brisée. Plus précisément :x[i-1]
ety[i-1]
sont les coordonnées du point précédent.x[i]
ety[i]
sont les coordonnées du point actuel.
En résumé, la boucle itère sur les tableaux de coordonnées x
et y
et dessine des segments de droite entre chaque
paire de points consécutifs, créant ainsi la ligne brisée.
Utilisation de drawPolyLine
dans drawPolygon
¶
La méthode drawPolygon(int[] x, int[] y, Color color)
utilise drawPolyLine
pour dessiner un polygone fermé. Voici
comment :
-
Appel à
drawPolyLine
:La méthode appelle d’abord
drawPolyLine
pour dessiner les côtés du polygone, sauf le dernier côté qui ferme le polygone. -
Fermeture du polygone :
Ensuite, elle appelle
drawLine
pour dessiner le dernier segment entre le dernier point(x[x.length - 1], y[y.length - 1])
et le premier point(x[0], y[0])
, fermant ainsi le polygone.
En combinant ces deux appels, drawPolygon
dessine efficacement un polygone fermé en utilisant la fonctionnalité de
drawPolyLine
pour dessiner la majorité des côtés.
Méthode drawCircle¶
La méthode drawCircle(int x, int y, int radius, Color color)
dessine un cercle de centre (x, y) et de rayon radius
avec la couleur spécifiée. Elle utilise une approche optimisée basée sur la symétrie des cercles pour dessiner les
points.
Voici une explication détaillée :
-
Calcul de
Cette ligne calcule la valeur de x (ou y) lorsqu’on est à 45 degrés sur le cercle. Elle est utilisée pour optimiser la boucle, en itérant seulement sur le premier octant du cercle (0 à 45 degrés). Les autres points sont calculés par symétrie.cos45
: -
Boucle principale :
La boucle itère de 0 jusqu’àcos45
.i
représente la coordonnée x par rapport au centre du cercle. -
Calcul de
À chaque itération,j
:j
est calculé.j
représente la coordonnée y par rapport au centre du cercle. Le calcul est basé sur le théorème de Pythagore (\(x^2 + y^2 = r^2\)), oùi
est la coordonnée x,j
est la coordonnée y etradius
est le rayon. -
Dessin des points par symétrie : Les lignes suivantes dessinent 8 points à chaque itération en exploitant la symétrie du cercle :
En dessinant 8 points à la fois, la méthode optimise le processus de dessin du cercle.image.SetPixel(x + i, y + j, color); // point 1 image.SetPixel(x - i, y + j, color); // point 2: symétrie du point 1 par rapport à l'axe Y image.SetPixel(x + i, y - j, color); // point 3: symétrie du point 1 par rapport à l'axe X image.SetPixel(x - i, y - j, color); // point 4: symétrie du point 3 par rapport à l'axe Y image.SetPixel(x + j, y + i, color); // point 5: symétrie du point 1 par rapport à la diagonale 45° image.SetPixel(x + j, y - i, color); // point 6: symétrie du point 5 par rapport à l'axe X image.SetPixel(x - j, y + i, color); // point 7: symétrie du point 5 par rapport à l'axe Y image.SetPixel(x - j, y - i, color); // point 8: symétrie du point 7 par rapport à l'axe X
En résumé, la méthode drawCircle
utilise une approche efficace pour dessiner un cercle en itérant sur un seul octant
et en utilisant la symétrie pour calculer et dessiner les autres points. Cela minimise les calculs et améliore les
performances.
Note
Page rédigée en partie avec l’aide d’un assistant IA, principalement à l’aide de Perplexity AI, avec le LLM Claude 3.5 Sonnet. L’IA a été utilisée pour générer des explications, des exemples et/ou des suggestions de structure. Toutes les informations ont été vérifiées, éditées et complétées par l’auteur.