Venez dessiner des formes d'une autre dimension... avec du code !

Atelier de programmation

a marqué ce sujet comme résolu.

Salut les zestes ! :)

Je vous propose un petit atelier créatif pour réaliser ce type d’images (cliquez pour agrandir) :

q    s     s    q

Concept

Chaque pixel d’une image se positionne à partir de son abscisse x et de son ordonnée y. En parcourant les pixels dont l’abscisse est multiple de N1 et l’ordonnée multiple de N2, on leurs associe une ellipse de hauteur h, de largeur k et de couleur c. En dessinant ces ellipses dont les paramètres h, k et c dépendent de la position du pixel courant, on peut obtenir de chouettes dessins. Notons également d la distance entre un pixel donné et le milieu de l’image.

La couleur c est encodée en RVBA : c = (Rouge, Vert, Bleu, Alpha ou transparence).

Par exemple, si N1 = 50, N2 = 50, h = 2*d, k = 2*d et c = (0, 255 - d, 255 - d/3, d/2) :

s

Codes

Voici le pseudo-code de l’exemple ci-dessus :

N1 ← 50
N2 ← 50

largeur ← 500
hauteur ← 500
im ← creer_image(largeur, hauteur)

Pour x de 0 jusqu'à largeur avec un pas de N1
    Pour y de 0 jusqu'à hauteur avec un pas de N2

        qx ← x - largeur/2
        qy ← y - hauteur/2

        d ← sqrt(qx*qx + qy*qy)

        Si d > 0 ET d < 255

            k ← 2*d
            h ← 2*d

            c ← creer_couleur_RVBA(0, 255 - d, 255 - d/3, d/2)
            dessiner_ellipse(x, y, k, h, c)

        Fin Si

    Fin Pour
Fin Pour

afficher_image(im)

Le même exemple implémenté en PHP, puis Java (avec Processing 3) :

<?php

$N1 = 50;
$N2 = 50;

$width = 500;
$height = 500;

$im = imagecreatetruecolor($width, $height);

for ($x = 0; $x < $width; $x += $N1)
{
    for ($y = 0; $y < $height; $y += $N2)
    {
        $qx = $x - $width/2;
        $qy = $y - $height/2;

        $d = sqrt($qx*$qx + $qy*$qy);

        if ($d > 0 && $d < 255)
        {
            $color = imagecolorallocatealpha($im, 0, 255-$d, 255-$d/3, $d/2);
            imageellipse($im, $x, $y, 2*$d, 2*$d, $color);
        }
    }
}

header('Content-type: image/png');
imagepng($im);
int N1 = 50;
int N2 = 50;

void setup()
{
    size(500, 500);
    background(0);
    noFill();

    for (int x = 0; x < width; x += N1)
    {
        for (int y = 0; y < height; y += N2)
        {
            float qx = x - width/2;
            float qy = y - height/2;

            float d = sqrt(qx*qx + qy*qy);

            if (d > 0 && d < 255)
            {
                float k = 2*d;
                float h = 2*d;

                color c = color(0, 255 - d, 255 - d/3, 256-d);
                stroke(c);
                ellipse(x, y, k, h);
            }
        }
    }
}

Codes sources PHP des images présentées :

<?php

$NX = 52;
$NY = 48;

$width = 500;
$height = 500;

$im = imagecreatetruecolor($width, $height);

for ($x = 0; $x < $width; $x += $NX)
{
    for ($y = 0; $y < $height; $y += $NY)
    {
        $qx = $x - $width/2;
        $qy = $y - $height/2;

        $d = sqrt($qx*$qx + $qy*$qy);

        if ($d > 0 && $d < 255)
        {
            $color = imagecolorallocatealpha($im, $d*$d/50, 255-$d, 255-$d/3, $d/2);
            imageellipse($im, $x, $y, (2*$d)%70, $d%90, $color);
        }
    }
}

header('Content-type: image/png');
imagepng($im);
<?php

$NX = 20;
$NY = 1;

$width = 500;
$height = 500;

$im = imagecreatetruecolor($width, $height);

for ($x = 0; $x < $width; $x += $NX)
{
    for ($y = 0; $y < $height; $y += $NY)
    {
        $qx = $x - $width/2;
        $qy = $y - $height/2;

        $d = sqrt(0.4*$qx*$qx + ($qx%30)*$qy*$qy);

        if ($d > 0 && $d < 255)
        {
            $color = imagecolorallocatealpha($im, 255-$d, $d, 255, 100);
            imageellipse($im, $x, $y, $d, $d, $color);
            
            if ($d < 50)
            {
                $NX += 0.3;
            }
        }
    }
}

header('Content-type: image/png');
imagepng($im);
<?php

$NX = 4;
$NY = 4;

$width = 500;
$height = 500;

$im = imagecreatetruecolor($width, $height);

for ($x = 0; $x < $width; $x += $NX)
{
    for ($y = 0; $y < $height; $y += $NY)
    {
        $qx = $x - $width/2;
        $qy = $y - $height/2;

        $d = 1.5*sqrt($qx*$qx - $qy*$qy);

        if ($d > 0 && $d < 255)
        {
            $color = imagecolorallocatealpha($im, 255-$d/1.5, 255-$d/1.5, 0, 95);
            imageellipse($im, $x, $y, (150-$d)*sin(0.08*$d-1), cos(0.1*$d)*(180-$d), $color);
        }
    }
}

header('Content-type: image/png');
imagepng($im);

Pour aller plus loin…

  • Au lieu d’associer une ellipse à chaque pixel, associer une couleur, un triangle, un carré, un polygone à n côtés…
  • …ou pourquoi pas un morceau de la fractale de Mandelbrot, dont voici un tutoriel sur ZdS.
    Cette fractale suit un principe assez similaire : on associe à chaque pixel une suite de nombres complexes. Si cette suite est bornée au pixel courant, on dessine le pixel.
  • Au lieu de prendre les pixels sur toute l’image, prendre ceux situés sur un cercle et les relier par un segment : ce sujet de @Rockaround a été source d’inspiration pour cet atelier.
  • Implémenter l’algorithme dans un max. de langages ;)
  • Me donner un retour sur cet atelier.

À vous de jouer, essayez de faire un chouette dessin ! ^^

Bravo, en effet, des résultats attrayants.

Si d > 0 ET d < 255

est-ce que
Si d<255
ne suffirait pas ?
En effet, une racine carrée est positive ou nulle.
Faut-il éviter d=0 ?

+0 -0

Si d = 0, la hauteur h et la largeur k de l’ellipse sont nulles selon les lignes 18 et 19 du pseudo-code. Dès lors, ce n’est pas nécessaire de tracer l’ellipse car elle ne devrait pas s’afficher, en théorie. En pratique, un point parasite peut quand même s’afficher, cela dépend du langage.

En PHP, une telle ellipse s’affiche par un point :

<?php

$width = 500;
$height = 500;

$im = imagecreatetruecolor($width, $height);

$color = imagecolorallocate($im, 255, 255, 255); // blanc opaque
imageellipse($im, $width/2, $height/2, 0, 0, $color);

header('Content-type: image/png');
imagepng($im); // On remarque un point blanc au milieu d'une image noire

Si d < 0, ce qui peut arriver lorsqu’on modifie ultérieurement la formule de d pour s’amuser ou pour faire des tests, on risque de dessiner une ellipse avec de la transparence et des coefficients de couleurs (ligne 21 du pseudo-code) qui sont hors de l’intervalle [0, 255]. Cela peut avoir des résultats inattendus car la couleur est encodée en RVBA. De mémoire, donner un code couleur < 0 n’affiche rien et s’il dépasse 255, cela empiète sur les autres couleurs.

J’ai moi-même joué avec cette limite d’intervalle à la ligne 22 $d*$d du premier code PHP des images présentées.
Je ne me suis pas assuré que 0 < $d*$d/50 < 255 pour la couleur rouge.

EPS est l’abréviation d’Encapsulated PostScript. Créé par Adobe Systems en 1992, c’est un format standard pour l’importation et l’exportation de texte et d’images. Les premières éditions d’Adobe Illustrator Artwork étaient basées sur des fichiers EPS respectant des conventions de structuration ouvertes DCS.

Wikipédia

@Rockaround En fait je me demande si l’implémentation ne se fait pas en Python plutôt, grâce à cette bibliothèque.
J’ai lu le document PostScript en diagonale, il semblerait que tu puisses « implémenter » les codes EPS dans un document word ou LaTeX (p7).

Par ailleurs, j’ai essayé de dessiner un triangle équilatéral en EPS puis héberger l’image sur ZdS, mais cela ne fonctionne pas :
Cliquez ici pour télécharger l’image

En fait je me demande si l’implémentation ne se fait pas en Python plutôt, grâce à cette bibliothèque.

C’est exactement ce que j’ai fait, mais l’ellipse n’y était pas. Je l’ai ajoutée hier, il faut que je la teste. C’était déjà ce que j’avais fait pour mes illustrations du cercle modulaire.

Par hasard, dans la bibliothèque, en dessous du cercle (def circle), l’ellipse ne serait-elle pas appelée sector ?

#CIRCLES, both accept optional trailing argument 'F', for fill
#circle with center at x,y with radius r :
    def circle(self,x,y,r,*tags):
        self.eps.write("N %8.2f %8.2f %8.2f csize 0 360 arc %s\n" %
                (self.ix(x), self.jy(y), self.sx(r), detag('CS',tags)))

#sector with center at user (x,y), but radius r1 and r2 are in pts:
    def sector(self,x,y,r1,r2,a1,a2,*tags):
        self.eps.write("N %8.2f %8.2f %8.2f csize %8.2f %8.2f arc RP\n" %
                (self.ix(x),self.jy(y),self.sx(r1),a1,a2))
        self.eps.write("  %8.2f %8.2f %8.2f csize %8.2f %8.2f arc %s\n" %
                (self.ix(x),self.jy(y),self.sx(r2),a1,a2,detag('CS',tags)))
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte