Suite à la remarque de BADOUX concernant le "camembert" de la source N°34131 d'adresse :
http://www.phpcs.com/codes/CAMEMBERTS-3D_34131.aspx
et dont les bords lui semblaient "un peux pixellisé", j'ai décidé de revoir tout le code avec la ferme intention de faire disparaître ces vilains petits défauts (d'où cette nouvelle publication et non pas une simple mise à jour).
Un mot-clé à retenir : Anti-Aliasing (AA pour les connaisseurs)
Sa définition : "algorithme appliqué sur le contour des formes pour en rendre l'aspect plus agréable, et éviter de voir la structure grillagée de l'image."
La méthode "bourrin" consiste à créer une image plus grande (par exemple 3 fois plus grande)que l'on réduit à la bonne taille une fois le travail effectué. L'AA est réalisé par la fonction de réduction "ImageCopyResampled()", qui se charge de trouver un compromis satisfaisant entre les pixels constituant chaque carré de 3x3. Cette technique est efficace, l'image finale qu'elle produit acceptable (pour un camembert!), le code l'implémentant court et facile à comprendre, son seul défaut est de requérir un temps d'exécution important (que je n'ai pas mesuré, mais bon...). On peut trouver un code de ce type en allant sur "
http://www.phpclasses.org" (y rechercher quelque chose comme "EQ_Smooth_3D_Pie_Graph").
On peut aussi attaquer le problème par la face nord, en partant d'une image à l'échelle 1, et gérer les transitions entre les zones de couleurs différentes.
Cette technique suppose en fait la réécriture des fonctions de gd2 impliquées dans l'image, et l'utilisation intensive d'algorithmes qui ont pour nom : Bresenham, Gupta-Sproull, point-milieu, ainsi que la mise à contribution de la transparence alpha.
C'est cette deuxième méthode qui est traitée ici.
Le code ci-dessous est entièrement fonctionnel, on peut donc en faire un copier-coller et l'exécuter immédiatement (php5 et gd2 requis).
Pour ceux qui veulent approfondir, ils trouveront dans le zip une version plus aboutie utilisant une véritable police de caractères et donnant le choix entre trois tailles de camembert différentes et trois types de fonds différents.
La démo en ligne :
http://michel.vanthodiep.free.fr/smooth3dcamembert/
Source / Exemple :
<?php
header ('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header ('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header ('Cache-Control: no-cache, must-revalidate');
header ('Pragma: no-cache');
/*
- Date de création : 27/01/2008
- Nom : aacamembert.php, version simplifiée à "copier-coller"
- Auteur : opossum_farceur
- Object : Camembert, 3D, Antialiasing, Bresenham, Statistiques
define('coef',M_PI/180);
class aacamembert
{
private $img;
private $a,$b,$cx,$cy,$aa,$bb,$aabb; /* ellipse */
private $data,$sort,$ellipse; /* tableaux */
private $quarter,$pivot; /* autres */
private $num,$linecolor; /* algorithme de Gupta-Sproull */
/* constructeur ---------------------------------------------------------------------------------------*/
function __construct($title,$arr)
{
$width=500;
$head=35; /* 15+15+5 : réservés pour le titre */
$height=300;
$w=240; /* grand axe horizontal */
$h=$w/2; /* 120 : petit axe vertical */
$thickness=$w/4; /* 60 : "épaisseur" du camembert */
$topcolor=0xFFFF00; /* dégradé : couleur du haut */
$bottomcolor=0x00FFFF; /* dégradé : couleur du bas */
$fontsize=3;
/* attributs calculés */
$this->a=$w/2; /* 1/2 grand axe : 120 */
$this->b=$h/2; /* 1/2 petit axe : 60 */
$this->cx=$width/2; /* abscisse et ordonnée du "centre" du camembert */
$this->cy=($height+$head-$thickness)/2;
$this->aa=$this->a*$this->a;
$this->bb=$this->b*$this->b;
$this->aabb=$this->aa*$this->bb;
/* attributs renseignés en cours de route */
$this->data=array();
$this->sort=array();
$this->ellipse=array();
/* antialiasing ligne droite */
$this->num=10; /* à choisir pair */
$this->linecolor=array(); /* taille du tableau : 1+3/2*$this->num, soit 16 (suffisant) */
/* préliminaires */
$this->img=imagecreatetruecolor($width,$height);
$this->mybackground($width-1,$height-1,$topcolor,$bottomcolor);
$textcolor=imagecolorallocate($this->img,0x00,0x00,0x00);
imagestring($this->img,5,($width-imagefontwidth(5)*strlen($title))/2,15,$title,$textcolor);
$this->aaellipse();
$this->gupta_sproull();
$specialcase=$this->init($arr,$thickness);
/* tracés */
$this->aadraw($thickness,$fontsize,$textcolor,$specialcase);
/* affichage */
header('Content-type: image/png');
imagepng($this->img);
imagedestroy($this->img);
}
/* "splite" une couleur en ses 3 composantes ----------------------------------------------------------*/
private function hex2rgb($hex)
{
return array(($hex>>16)& 0xFF,($hex>>8)& 0xFF,$hex & 0xFF);
}
/* mise en place du fond ------------------------------------------------------------------------------*/
private function mybackground($w,$h,$topcolor,$bottomcolor)
{
list($red,$green,$blue)=$this->hex2rgb($topcolor);
$bc=$this->hex2rgb($bottomcolor);
$incr=($bc[0]-$red)/$h;
$incg=($bc[1]-$green)/$h;
$incb=($bc[2]-$blue)/$h;
for($j=0;$j<=$h;$j++,$red+=$incr,$green+=$incg,$blue+=$incb)
imageline($this->img,0,$j,$w,$j,imagecolorallocate($this->img,$red,$green,$blue));
}
/* à partir de l'angle donné en argument retourne l'index correspondant du tableau de l'ellipse -------*/
private function index($v)
{ /* formulation du sinus à partir du cosinus, en principe + rapide */
$cosv=cos(coef*$v);
$sinv= ($v>180)? -sqrt(1-$cosv*$cosv) : sqrt(1-$cosv*$cosv);
$x=round($this->a*abs($cosv));
$y=round($this->b*abs($sinv));
$case=floor($v/90);
$p=($case+$case%2)*$this->quarter;
$sign= ($case%2)? -1 : 1;
$q= ($this->aa*$y-$this->bb*$x<0)? $y : $this->quarter-$x;
return $p+$sign*$q;
}
/* traitement des données fournies dans le tableau ----------------------------------------------------*/
private function init($arr,$e)
{ /* calcul de la somme des données */
for ($j=$sum=0,$n=count($arr);$j<$n;$j++) $sum+=$arr[$j][0];
/* analyse du tableau */
for ($j=$k=$v1=0;$j<$n;$j++) if ($arr[$j][0]) { /* cas non traité si donnée nulle */
/* extraction des composantes red, green et blue */
list($red,$green,$blue)=$this->hex2rgb($arr[$j][1]);
$this->data[$k]['color']=imagecolorallocate($this->img,$red,$green,$blue);
/* traitement des angles */
$v2=$v1+$arr[$j][0]*360/$sum;
if ($v1<=270 && $v2>=270) $first=$k;
if ($v1<=90 && $v2>=90) $last=$k;
$this->data[$k]['v']=$v2;
/* détermine la couleur ombrée */
$this->data[$k]['shade']=imagecolorallocate($this->img,max(0,$red-50),max(0,$green-50),max(0,$blue-50));
/* préparation du texte */
$this->data[$k]['legend']=$arr[$j][2];
$this->data[$k]['value']=number_format(100*$arr[$j][0]/$sum,2,',','').'%';
$this->data[$k]['xploded']=$arr[$j][3];
$v1=$v2;
$k++;
}
$m=count($this->data); /* différent de $n si une ou plusieurs donnée(s) sont nulles */
if ($first!=$last) {
for ($j=0,$k=$first;$k!=$last;$j++,$k=($k+1)%$m) $this->sort[$j]=$k;
$this->pivot=$j;
for ($k=$first-1;$k>=$last;$j++,$k--) $this->sort[$j]=$k;
return false;
}
else { /* cas particulier préoccupant : une grosse portion présente à la fois à 12h et à 18h */
for ($j=0,$k=($first+1)%$m;$j<$m;$j++,$k=($k+1)%$m) $this->sort[$j]=$k;
$this->pivot=$m-1;
/* mise en place du 2ème panneau de la dernière portion (origine du code : méthode "aadraw()") */
$j=$this->sort[$m-1];
$xploded=$this->data[$j]['xploded'];
if ($this->data[$this->sort[0]]['xploded'] || $xploded) {
$shade=$this->data[$j]['shade'];
$v1= ($j)? $this->data[$j-1]['v'] : 0;
$v2=$this->data[$j]['v'];
$vm=($v1+$v2)/2;
if ($xploded) {
$ox=round($this->cx+$this->a*cos(coef*$vm)/6); /* a/6, b/6 : "offsets" des portions */
$oy=round($this->cy+$this->b*sin(coef*$vm)/6);
}
else {
$ox=$this->cx;
$oy=$this->cy;
}
$index2=$this->index($v2);
$x2=$ox+$this->ellipse[$index2]['x'];
$y2=$oy+$this->ellipse[$index2]['y'];
imageline($this->img,$ox,$oy,$ox,$oy+$e,$shade);
imageline($this->img,$x2,$y2,$x2,$y2+$e,$shade);
$this->aaborder($ox,$oy,$x2,$y2,0,$backup2,$shade); /* ligne du haut */
$this->aaborder($x2,$y2+$e,$ox,$oy+$e,1,$backup2,$shade);/* ligne du bas (attention à l'ordre!) */
if ($x2-$ox>1) imagefilltoborder($this->img,round(($ox+$x2)/2),round(($oy+$y2+$e)/2),$shade,$shade);
$this->aaborder($x2,$y2+$e,$ox,$oy+$e,2,$backup2); /* aa ligne du bas */
}
return true;
}
}
/* calcul des 16 tons de gris utiles au dessin des lignes droites antialiassées -----------------------*/
private function gupta_sproull()
{ /* cette fonction crée une table allant de 0 à 1.5*$this->num */
$col=array();
$numdiv2=$this->num/2;
/* calcul du volume interceptant chaque colonne, i et j parcourent un quart du cône */
for ($i=$this->num,$total=0;$i>=0;$i--) {
for ($j=$this->num,$k=0,$ii=$i*$i;$j>=0;$j--) {
$d=sqrt($ii+$j*$j);
if ($d<$this->num) $k+=$this->num-$d;
}
$col[$this->num-$i]=2*$k;
$total+=4*$k;
}
/* calcul de la table : 1ere partie correspondant à une intersection d'épaisseur inférieure à 1 */
$max=$this->num+$numdiv2;
for ($i=$k=0;$i<=$this->num;$i++) {
$k+=$col[$i];
$this->linecolor[$max-$i]=imagecolorexactalpha($this->img,0,0,0,round(127*(1-$k/$total)));
}
/* calcul de la table : 2eme partie correspondant à une intersection d'épaisseur supérieure à 1 */
for ($i=1;$i<=$numdiv2;$i++) {
$k+=$col[$this->num-$i]-$col[$i];
$this->linecolor[$numdiv2-$i]=imagecolorexactalpha($this->img,0,0,0,round(127*(1-$k/$total)));
}
}
/* "allume" le pixel avec une intensité fonction de la distance à la droite ---------------------------*/
private function plot($x,$y,$d)
{
if ($d<0) $d=-$d;
if ($d>1.5) return; /* rien à allumer si le pixel est trop loin */
imagesetpixel($this->img,$x,$y,$this->linecolor[round($d*$this->num)]);
}
/* tracé de droite "antialiassée" ---------------------------------------------------------------------*/
private function aaline($x1,$y1,$x2,$y2)
{
$dx=abs($x2-$x1);
$dy=abs($y2-$y1);
$incj= (($x2-$x1)*($y2-$y1)>0)? 1 : -1;
$K=1/(2*sqrt($dx*$dx+$dy*$dy));
if ($dx>$dy) { /* tendance "horizontale" */
if ($x2>$x1) {
$y=$y1;
$begin=$x1;
$end=$x2;
}
else {
$y=$y2;
$begin=$x2;
$end=$x1;
}
$p=2*$dy;
$delta=$dx;
$incx=0;
$incy=$incj;
$i=&$x;
$j=&$y;
}
else { /* tendance "verticale" */
if ($y2>$y1) {
$x=$x1;
$begin=$y1;
$end=$y2;
}
else {
$x=$x2;
$begin=$y2;
$end=$y1;
}
$p=2*$dx;
$delta=$dy;
$incx=$incj;
$incy=0;
$i=&$y;
$j=&$x;
}
/* tronc commun */
for ($i=$begin,$e=$p-$delta,$q=$e-$delta,$D=0,$R=2*$K*$delta;$i<=$end;$i++) {
$this->plot($x,$y,$D);
$this->plot($x+$incx,$y+$incy,$R-$D);
$this->plot($x-$incx,$y-$incy,$R+$D);
if ($e>=0) {
$D=$K*($e-$delta);
$j+=$incj;
$e+=$q;
}
else {
$D=$K*($e+$delta);
$e+=$p;
}
}
}
/* traitement de l'aa des "bordures" ------------------------------------------------------------------*/
private function aaborder($x1,$y1,$x2,$y2,$mode,&$backup,$mycolor=0)
{
$dx=$x2-$x1;
$dy=$y2-$y1;
$incj= ($dx*$dy>0)? 1 : -1;
if ($mode==1) $backup=array();
elseif ($mode==2) $const=$dx*$y1-$dy*$x1;
if (abs($dx)>abs($dy)) { /* tendance "horizontale" */
if ($dx>0) {
$y=$y1;
$begin=$x1;
$end=$x2;
}
else {
$y=$y2;
$begin=$x2;
$end=$x1;
}
$p=2*abs($dy);
$e=$p-abs($dx);
$q=$e-abs($dx);
$i=&$x;
$j=&$y;
}
else { /* tendance "verticale" */
if ($dy>0) {
$x=$x1;
$begin=$y1;
$end=$y2;
}
else {
$x=$x2;
$begin=$y2;
$end=$y1;
}
$p=2*abs($dx);
$e=$p-abs($dy);
$q=$e-abs($dy);
$i=&$y;
$j=&$x;
}
/* tronc commun */
for ($i=$begin,$t=0;$i<=$end;$i++,$t++) {
if ($mode==1) $backup[]=imagecolorat($this->img,$x,$y); /* mode "sauvegarde" */
elseif ($mode==2) { /* mode "antialiasing" */
for ($f=$x-0.2,$g1=$y-0.2,$g3=$y+0.2,$alpha=0;$f<=$x+0.2;$f+=0.2) {
$k=$const+$dy*$f;
for ($g=$g1;$g<=$g3;$g+=0.2) if ($dx*$g>$k) $alpha++;
}
list($red,$green,$blue)=$this->hex2rgb($backup[$t]);
$mycolor=imagecolorexactalpha($this->img,$red,$green,$blue,11*$alpha+28);
}
imagesetpixel($this->img,$x,$y,$mycolor);
if ($e>=0) {
$j+=$incj;
$e+=$q;
}
else $e+=$p;
}
}
/* tracé du camembert ---------------------------------------------------------------------------------*/
private function aadraw($e,$fontsize,$textcolor,$specialcase)
{
$A=$this->a*21/16; /* 1/2 grand axe de l'ellipse "englobante" */
$B=3*$A/4; /* bien que dépendant de $e, mais bon... */
$dy=-$e/2; /* "centre" du camembert à celui de l'ellipse "englobante" */
$AA=$A*$A;
$BB=$B*$B;
$ifw=imagefontwidth($fontsize);
/* "grande boucle" */
for ($i=0,$m=count($this->data);$i<$m;$i++) {
$j=$this->sort[$i];
/* initialisations */
$color=$this->data[$j]['color'];
$shade=$this->data[$j]['shade'];
$v1= ($j)? $this->data[$j-1]['v'] : 0;
$v2=$this->data[$j]['v'];
$vm=($v1+$v2)/2;
$index1=$this->index($v1);
$index2=$this->index($v2);
$xploded=$this->data[$j]['xploded'];
$panel1=$panel2=false;
$flag=0;
if ($xploded) {
$px=$this->a*cos(coef*$vm);
$py=$this->b*sin(coef*$vm);
$ox=round($this->cx+$px/6); /* a/6, b/6 : "offsets" des portions */
$oy=round($this->cy+$py/6);
}
else {
$px=5*$this->a*cos(coef*$vm)/6;
$py=5*$this->b*sin(coef*$vm)/6;
$ox=$this->cx;
$oy=$this->cy;
switch ($i) { /* cumulations possibles */
case 0: $flag=$this->data[$this->sort[$this->pivot]]['xploded'];
case $this->pivot-1: $flag|=$this->data[$this->sort[$m-1]]['xploded'];
default: $flag|=$this->data[$this->sort[$i+1]]['xploded'];
}
}
$x1=$ox+$this->ellipse[$index1]['x'];
$y1=$oy+$this->ellipse[$index1]['y'];
$x2=$ox+$this->ellipse[$index2]['x'];
$y2=$oy+$this->ellipse[$index2]['y'];
$gx=round($this->cx+$px); /* sans arrondi, problème raccordement segment en size 1 */
$gy=round($this->cy+$py);
/* traitement secteur du bas + paravent vertical */
if ($v1<180) {
if ($v2<180) {
$indexmax=$index2;
$x=$x2;
$y=$y2;
}
else { /* le traitement s'arrête à 180° */
$indexmax=2*$this->quarter; /* aussi : $this->index(180); */
$x=$ox-$this->a; /* aussi : $ox+$this->ellipse[$indexmax]['x']; */
$y=$oy; /* aussi : $oy+$this->ellipse[$indexmax]['y'] */
}
/* dessin des secteurs hauts et bas de l'ellipse */
for ($k=$index1,$backup0=array();$k<=$indexmax;$k++) {
$xk=$ox+$this->ellipse[$k]['x'];
$yk=$oy+$this->ellipse[$k]['y'];
$backup0[]=imagecolorat($this->img,$xk,$yk+$e);
imagesetpixel($this->img,$xk,$yk,$shade);
imagesetpixel($this->img,$xk,$yk+$e,$shade);
}
/* lignes verticales */
imageline($this->img,$x1,$y1,$x1,$y1+$e,$shade);
imageline($this->img,$x,$y,$x,$y+$e,$shade);
/* "remplissage" peu optimisé mais valable dans tous les cas de figures */
if ($x1-$x>1) imagefilltoborder($this->img,$x+1,$y+$e/2,$shade,$shade);
/* antialiasing secteur ellipse du bas */
$this->aaarc($index1,$indexmax,$ox,$oy+$e,$backup0);
}
if ($xploded || $flag) { /* dessine les "panneaux" verticaux */
if ($v1>90 && $v1<270) {
imageline($this->img,$ox,$oy,$ox,$oy+$e,$shade);
imageline($this->img,$x1,$y1,$x1,$y1+$e,$shade); /* parfois inutile, mais bon... */
$this->aaborder($x1,$y1,$ox,$oy,0,$backup1,$shade); /* ligne du haut, backup inutile */
$this->aaborder($ox,$oy+$e,$x1,$y1+$e,1,$backup1,$shade);/* ligne du bas, backup parfois inutile */
if ($ox-$x1>1)
imagefilltoborder($this->img,round(($ox+$x1)/2),round(($oy+$y1+$e)/2),$shade,$shade);
$this->aaborder($ox,$oy+$e,$x1,$y1+$e,2,$backup1); /* aa ligne du bas */
if ($v1<180) imageline($this->img,$x1,$y1,$x1,$y1+$e,$color); /* séparation verticale */
$panel1=true;
}
if ($v2<90 ||($v2>270 &&!($specialcase && $i==$m-1))) { /* $specialcase n'apparait qu'ici */
imageline($this->img,$ox,$oy,$ox,$oy+$e,$shade);
imageline($this->img,$x2,$y2,$x2,$y2+$e,$shade);
$this->aaborder($ox,$oy,$x2,$y2,0,$backup2,$shade); /* ligne du haut, backup inutile */
$this->aaborder($x2,$y2+$e,$ox,$oy+$e,1,$backup2,$shade);/* ligne du bas */
if ($x2-$ox>1)
imagefilltoborder($this->img,round(($ox+$x2)/2),round(($oy+$y2+$e)/2),$shade,$shade);
$this->aaborder($x2,$y2+$e,$ox,$oy+$e,2,$backup2); /* aa ligne du bas */
if ($v2<90) imageline($this->img,$x2,$y2,$x2,$y2+$e,$color); /* séparation verticale */
$panel2=true;
}
if ($panel1 && $panel2) imageline($this->img,$ox,$oy,$ox,$oy+$e,$color);/* séparation verticale */
}
/* dessine le dessus de la portion */
for ($k=$index1,$backup0=array();$k<=$index2;$k++) {
$xk=$ox+$this->ellipse[$k]['x'];
$yk=$oy+$this->ellipse[$k]['y'];
$backup0[]=imagecolorat($this->img,$xk,$yk);
imagesetpixel($this->img,$xk,$yk,$color);
}
/* tracé des "rayons", sauvegarde parfois inutile, mais bon... */
$this->aaborder($ox,$oy,$x1,$y1,1,$backup1,$color); /* centre -> extrémité */
$this->aaborder($x2,$y2,$ox,$oy,1,$backup2,$color); /* extrémité -> centre */
/* "remplissage" du secteur en partant du "germe" */
imagefilltoborder($this->img,$gx,$gy,$color,$color);
/* correction du défaut du "secteur trop étroit" (pas toujours nécessaire) */
imageline($this->img,$ox,$oy,$gx,$gy,$color);
/* antialiasing secteur ellipse du haut */
$this->aaarc($index1,$index2,$ox,$oy,$backup0);
/* antialiasing des "rayons" du secteur elliptique */
if ($xploded || $flag) {
$this->aaborder($ox,$oy,$x1,$y1,2,$backup1); /* centre -> extrémité */
$this->aaborder($x2,$y2,$ox,$oy,2,$backup2); /* extrémité -> centre */
}
else if ($i) { /* centre -> extrémité */
if ($i<$this->pivot) $this->aaborder($ox,$oy,$x1,$y1,2,$backup1);
else { /* extrémité -> centre */
$this->aaborder($x2,$y2,$ox,$oy,2,$backup2);
if ($i==$m-1) $this->aaborder($ox,$oy,$x1,$y1,2,$backup1);
}
}
/* traitement des légendes */
$ka=$AA*$py*$py+$BB*$px*$px;
$kb=$AA*$dy*$px*$py;
$kc=$AA*$px*$px*($dy*$dy-$BB);
if ($vm<=90 || $vm>270) {
$root=(-$kb+sqrt($kb*$kb-$ka*$kc))/$ka;
$qx=round($this->cx+$root);
$qy=round($this->cy+$root*$py/$px);
$this->aaline($gx,$gy,$qx,$qy);
$this->aaline($qx+1,$qy,$qx+10,$qy);
imagestring($this->img,$fontsize,$qx+14,$qy-12,$this->data[$j]['legend'],$textcolor);
imagestring($this->img,$fontsize,$qx+14,$qy-2,$this->data[$j]['value'],$textcolor);
}
else {
$root=(-$kb-sqrt($kb*$kb-$ka*$kc))/$ka;
$qx=round($this->cx+$root);
$qy=round($this->cy+$root*$py/$px);
$this->aaline($gx,$gy,$qx,$qy);
$this->aaline($qx-1,$qy,$qx-10,$qy);
$legendposx=$qx-12-$ifw*strlen($this->data[$j]['legend']);
$valueposx=$qx-12-$ifw*strlen($this->data[$j]['value']);
imagestring($this->img,$fontsize,$legendposx,$qy-12,$this->data[$j]['legend'],$textcolor);
imagestring($this->img,$fontsize,$valueposx,$qy-2,$this->data[$j]['value'],$textcolor);
}
}
}
/* dessine un arc avec l'aa ---------------------------------------------------------------------------*/
private function aaarc($begin,$end,$dx,$dy,&$backup)
{
for ($j=$begin,$i=0;$j<=$end;$j++,$i++) {
list($red,$green,$blue)=$this->hex2rgb($backup[$i]);
$mix=imagecolorexactalpha($this->img,$red,$green,$blue,$this->ellipse[$j]['alpha']);
imagesetpixel($this->img,$dx+$this->ellipse[$j]['x'],$dy+$this->ellipse[$j]['y'],$mix);
}
}
/* calcul de la transparence du point, intégration de l'enregistrement au tableau ---------------------*/
private function add($x,$y)
{ /* 9 échantillons sont suffisants */
for ($f=$x-0.2,$g1=$y-0.2,$g3=$y+0.2,$alpha=0;$f<=$x+0.2;$f+=0.2) {
$k=$this->aabb-$this->bb*$f*$f;
for ($g=$g1;$g<=$g3;$g+=0.2) if ($this->aa*$g*$g<$k) $alpha++;
}
return array('x'=>$x,'y'=>$y,'alpha'=>11*$alpha+28);
}
/* calcul d'un quart de l'ellipse, généralisation à l'ellipse entière ---------------------------------*/
private function aaellipse()
{
$temp=array();
/* algorithme volontairement non optimisé, pour ne pas le rendre encore plus hermétique ! */
for ($x=0,$y=$this->b,$e=4*$this->bb+$this->aa*(1-4*$y);$this->bb*$x<$this->aa*$y;$x++) {
$temp[2][]=$this->add($x,$y); /* octant n°2 */
$e+= ($e<0)? $this->bb*(8*$x+12) : $this->bb*(8*$x+12)+8*$this->aa*(1-$y--);
}
for ($x=$this->a,$y=0,$e=4*$this->aa+$this->bb*(1-4*$x);$this->aa*$y<$this->bb*$x;$y++) {
$temp[1][]=$this->add($x,$y); /* octant n° 1 */
$e+= ($e<0)? $this->aa*(8*$y+12) : $this->aa*(8*$y+12)+8*$this->bb*(1-$x--);
}
/* on remet tout dans l'ordre qui convient */
$this->ellipse=array_merge($temp[1],array_reverse($temp[2]));
unset($temp);
/* généralisation aux 3 autres quadrants */
for ($i=0,$n=count($this->ellipse),$p=2*$n-2,$q=4*$n-4;$i<$n;$i++) {
$x=$this->ellipse[$i]['x'];
$y=$this->ellipse[$i]['y'];
$alpha=$this->ellipse[$i]['alpha'];
$this->ellipse[$p-$i]=array('x'=>-$x,'y'=>$y,'alpha'=>$alpha);
$this->ellipse[$p+$i]=array('x'=>-$x,'y'=>-$y,'alpha'=>$alpha);
$this->ellipse[$q-$i]=array('x'=>$x,'y'=>-$y,'alpha'=>$alpha);
}
$this->quarter=(count($this->ellipse)-1)/4;
}
/* fin de la classe -----------------------------------------------------------------------------------*/
}
$title='CodeS-SourceS : 33620 sources publiées!';
$arr=array(
/* donnée couleur légende xploded */
array(2072, 0x969696, 'Divers', 0),
array(1003, 0xFF9900, 'JAVA/J2EE', 0),
array(1038, 0xFFCB03, 'C#', 0),
array(1623, 0x99CC00, 'Flash', 0),
array(1854, 0x339966, 'IRC', 0),
array(1873, 0x33CCCC, 'Javascript/DHTML', 0),
array(2208, 0x0091C3, 'PHP', 1),
array(2624, 0xAA44AA, 'Delphi', 0),
array(4971, 0xFF99CC, 'C/C++', 0),
array(14354, 0xFF4C4C, 'Visual Basic', 0)
);
$mon_caprice_des_dieux=new aacamembert($title,$arr);
?>
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.