LibGD : affichage de cercles et d’arcs…

Aujourd'hui je devais changer la routines d'affichage de notre fonction "SoftRectangle", qui affiche des rectangles à bord arrondis, pour passer d'un affichage d'une couleur donnée à un affichage en utilisant un XOR (histoire que les contours marchent quelle que soit la couleur de fond).
Comme on utilisait de façon extensive les routines d'affichage de la libGD, ce n'était pas super compatible. Je me suis dit, un peu naïvement, que j'allais récupérer les sources, extraire les routines utilisées, et changer le pixel plot par du XOR... Et bien finalement quand j'ai vu tout ça j'ai préféré le refaire ^^
En fait, déjà, toutes les routines de dessin sont 100% génériques. Comprendre par là qu'un des paramètres d'une image est son type (truecolor, palette, etc...), et que bien entendu la façon d'écrire un pixel en dépend complètement. Du coup, quand on trace une ligne, pour chaque pixel à afficher on va utiliser la routine générique qui va regarder le type et appeler la bonne macro correspondante... Je ne sais pas si le compilo arrive à faire son boulot à fond pour optimiser tout ça, mais j'espère, sinon le résultat ne doit pas être terrible niveau perfs :s
Bref, je disais ça surtout pour la routine qui permet de tracer les arcs de cercle. Là j'ai eu un peu peur, car au final la routine ne fait que parcourir les angles possibles, degré par degré, et trace des lignes entre les différents points pour former le cercle... Forcément, pour mon XOR ce n'était pas terrible car chaque pixel était allumé/éteint une bonne dizaine de fois, donc c'était un poil trop aléatoire... La bonne optimisation que j'ai vue est l'utilisation d'une LUT en lien et place des cosinus/sinus, mais par contre pour ne pas dépasser, chaque accès dans la LUT nécessite un petit calcul de modulo 360 qui ne doit pas être gratuit :/
Bon, j'ai voulu faire mieux, à savoir un truc qui marchera dans mon cas et qui tournera, pour le coup, vraiment bien. Je me suis donc tourné vers Monseigneur Bresenham et son algorithme de tracé d'arc de cercle. Je ne vais pas rentrer trop dans les détails, mais en gros on ne va afficher les pixels qu'une fois, et en plus histoire d'aller super vite, pour chaque calcul de position, on l'utilise 8 fois (de façon assez logique on a 1 fois par cadran, donc ça fait déjà 4 fois, et en fait dans chaque cadran on peut imaginer partir d'un sens ou de l'autre (symétrie "en diagonale"), ce qui multiplie par 2
).
procédure tracerOctant (entier rayon, entier x_centre, entier y_centre) déclarer entier x, y, m ; x ←0 ; y ← rayon ; // on se place en haut du cercle m ←5-4*rayon ; // initialisation Tant que x <= y // tant qu'on est dans le second octant tracerPixel( x+x_centre , y+y_centre ) ; tracerPixel( y+x_centre , x+y_centre ) ; tracerPixel( -x+x_centre , y+y_centre ) ; tracerPixel( -y+x_centre , x+y_centre ) ; tracerPixel( x+x_centre , -y+y_centre ) ; tracerPixel( y+x_centre , -x+y_centre ) ; tracerPixel( -x+x_centre , -y+y_centre ) ; tracerPixel( -y+x_centre , -x+y_centre ) ; si m > 0 alors //choix du point F y ← y - 1 ; m ← m-8*y ; fin si ; x ← x+1 ; m ← m + 8*x+4 ; fin tant que ; fin de procédure ;
Là ça fait des cercles complets alors que je voulais juste faire des cadrans vite fait, mais en fait il m'a suffit de rajouter en paramètre la largeur et la hauteur de la boite à créer, et de rajouter des +w et des +h là où il faut (en gros en imagine qu'on dessine de base le cadran en haut à gauche, du coup les cadrans avec un x positif on doit leur ajouter +w, et les cadrans avec un y positif on leur ajoute +h...
Avec ça on obtient de façon rapide et efficace le tracé des 4 quart de cercle à moindre frais
Cet algo ne présente qu'une limite, qui fait que je vais probablement voir pour le remplacer par un autre : Si on affiche 2 cercles concentriques dans le but de faire un tracé 2 fois plus épais... on a des trous ! Il n'a pas été fait pour ça, et donc il faudra alors se tourner vers un autre algo, tel quel algorithme de tracé de cercle d'Andres.
Aucun trackbacks pour l'instant