===== Algorithmes de tracer de cercles =====
Pour l'étude, on considère la partie dans le deuxième octant((pour avoir 1 pixel par colonne)) (x>0, y>x) d'un cercle de rayon R et centre (0,0). x2 + y2 = R2.
Deux approches se présente :
* Calculs flottants : pour x=0,1,\ldots\quad y=arrondi(sqrt{R*R - x*x)
* Algorithme de Bresenham (analogue de son algorithme pour les segments) : incrémentale, arithmétique entière.
==== Algorithme de Bresenham ====
=== Principe ===
A chaque étape, le pixel à choisir dans la colonne suivante sera soit au même niveau, soit un cran plus bas, car dans cet octant la tangente varie de pente 0 à pente -1, pas plus. Soient S: (\left(x_c+1,y_c\right), T : \left(x_c +1, y_c -1\right). La distance algébrique de chacun de ces points au cercle indique si le point est à l'intérieur (valeur négative) ou extérieur (valeur positive) et se calcule:
* D\left(S\right) = \left(x_c + 1\right)^2 + \left(y_c \right)^2 - R^2
* D\left(T\right) = \left(x_c + 1\right)^2 + \left(y_c -1\right)^2 - R^2
De trois choses l'une :
* si les deux points sont à l'intérieur (si S l'est, T le sera) indiqué par deux valeurs négatives, on choisit S (le point au dessus est plus proche du cercle dans cette région). La somme D(S)+D(T) < 0.
* si les deux points sont à l'extérieur (si T l'est, S aussi) indiqué par deux valeurs positives, on choisit T. La somme D(S) + D(T) > 0
* si S est à l'extérieur et T à l'intérieur, on compare leurs distances on faisant leur somme.
* Somme D(S) + D(T) > 0 => S est plus loin, on choisit T;
* Somme D(S) + D(T) < 0 => T est plus loin, on choisit S;
* Somme D(S) + D(T) = 0 => on choisit S (aussi).
Donc, en générale, D(S) + D(T) > 0 => choisir T =\left(x_c +1, y_c -1\right) et sinon choisir S =\left(x_c +1, y_c \right) .
=== Algorithme ===
cercle (R, couleur)
{
x=0; y=R; d=3 - 2*R;
tant que (x =< y) faire
{ affichePixel(x,y, couleur);
si (d < 0) alors d = d + 4*x + 6 /* S est choisi */
sinon {d = d + 4*(x-y) +10; y=y-1;}
x=x+1;
}
}
=== évolution de "d" ===
Pour un point donné, la somme
* D(S)+D(T)=(x+1)^2 + y^2-R^2 + (x+1)^2 + (y-1)^2 - R^2
* =2x^2 +2x +2y^2 -2y + 2 - 2R^2
* Si le successeur au même niveau est choisi (choix S, y ne change pas) sa prochaine valeur sera
* (x+2)^2 + y^2-R^2 + (x+2)^2 + (y-1)^2 - R^2
* si S est choisi, l'incrément de ''d'' sera
* \Delta_{S} = 2(x+2)^2 + y^2 + (y-1)^2 - 2R^2- \left(2(x+1)^2 + y^2 + (y-1)^2 -2 R^2\right)
* = 2\left[ \left(x+2\right)^2 - \left(x+1\right)^2\right] = 2\left[ x^2 +4x +4 - x^2 + 2x +1\right]= 4x +6
* sinon, si T est choisi, le successeur baisse de niveau et la valeur sera
* (x+2)^2 + (y-1)^2-R^2 + (x+2)^2 + (y-2)^2 - R^2
* si T est choisi, l'incrément de ''d'' sera
* \Delta_{T} =2(x+2)^2 + (y-1)^2 + (y-2)^2 - 2R^2 - \left( 2 (x+1)^2 + y^2 + (y-1)^2 - 2R^2\right)
* =2\left[(x+2)^2 - (x+1)^2\right] + (y-2)^2 -y^2 = 4x+6-4y+4=4\left(x-y\right)+10
=== Remarque ===
Il existe des points n'appartenant à aucun cercle de Bresenham.
=== reste à faire ===
* généralisation à tout cercle (autre centre, R pas forcément entier, autres octants)
* calculer l'incrément de manière incrémental avec des constantes
==== Cercle arithmétique ====
Un invention récente, de Eric Andrès, 1992.
=== Définition ===
Un cercle arithmétique C de rayon R entré en O passe par \left(x,y\right) \Leftrightarrow \left(R-\frac{1}{2}\right) \leq x^2 + y^2 \lt \left( R -\frac{1}{2}\right)
Tout point entier appartient à un cercle arithmétique de rayon R, et un seul.
=== Principe ===
Même contexte qu'avant (deuxième octant, etc.). Le prochain pixel est choisi parmi __3__ candidats au lieu de deux (et on peut afficher deux pixels dans une colonne) avec deux règles:
* on n'aura pas à la fois (x, y-1) et (x+1, y) sur le cercle
* si ni (x, y-1) ni (x+1, y) n'est sur le cercle, (x+1, y-1) y est
cercle (x0, y0, couleur)
{
x=0; y=R; d=R-1;
tantque (x =< y) faire
{ affichePixel(x,y,couleur);
si (d >= 2*x) alors {d=d-2x-1; x=x+1;} // a
sinon
si (d < 2*(R-y)) alors {d=d+2*x -1; y=y-1;} // b
sinon {d=d-2*(y-x-1); x=x+1; y=y-1;} // c
}
}
==== Exemples des Deux ====
=== Bresenham ===
FIXME attention ce tableau n'a pas été vérifié !
^ R ^ d ^ x ^ y ^ allumer ^ traiter d ^ traiter y ^ traiter x ^
^ 1 | 3-2=1 | 0 | 1 | (0,1) | 1+4*(0-1)+10 | - 1 | + 1 |
| | 7 | 1 | 0 | rien: x>y | | | |
^ 2 | 3-4=-1 | 0 | 2 | (0,2) | -1+4*0+6 | -0 | +1 |
| | 5 | 1 | 2 | (1,2 ) | 5 +4(1-2)+10 | -1 | +1 |
| | 11 | 2 | 1 | rien: x>y | | | |
^ 3 | -3 | 0 | 3 | (0,3) | -3+4*0+6 | -0 | + 1 |
| | 3 | 1 | 3 | (1,3) | 3+4*(1-3)+10 | -1 | +1 |
| | 5 | 2 | 2 | (2,2) | 5 + 4*(2-2)+10 | -1 | + 1 |
| | 15 | 3 | 1 | rien : x>y | | | |
^ 4 | -5 | 0 | 4 | (0,4) | -5+4*0+6 | -0 | +1 |
| | 1 | 1 | 4 | (1,4) | 1 +4*(1-4)+10 | -1 | +1 |
| | -1 | 2 | 3 | (2,3) | -1+4*2+6 | -0 | +1 |
| | 13 | 3 | 3 | (3,3) | 13 +4(3-3)+10 | -1 | +1 |
| | 23 | 4 | 2 | rien : x>y | | | |
=== arithmétiques ===
FIXME attention ce tableau n'a pas été vérifié !
^ R ^ d ^ x ^ y ^ allumer ^ d >= 2*x ^ d<2*(R-y) ^ traiter d ^ traiter y ^ traiter x ^
^ 1 | 0 | 0 | 1 | (0,1) | oui | --- | d=d-2x-1 | -0- | x<- x+1 |
| | -1 | 1 | 1 | (1,1) | non | oui | d <- d+2x-1 | y <- y-1 | -0- |
| | 0 | 1 | 0 | rien : x>y | |||||
^ 2 | 1 | 0 | 2 | (0,2) | oui | | d<-d-2x-1 | -0- | x <- x+1 |
| | 0 | 1 | 2 | (1,2) | non | non | d <- d-2*(y-x-1) | y<-y-1 | x<- x+1 |
| | 0 | 2 | 1 | rien : x>y | |||||
^ 3 | 2 | 0 | 3 | (0,3) | oui | | d <- 2 -2*0 - 1 | -0- | x <- x+1 |
| | 1 | 1 | 3 | (1,3) | non | non | d <- d-2*(y-x-1) | y<-y-1 | x<- x+1 |
| | -1 | 2 | 2 | (2,2) | oui | | d <- d -2x-1 | -0- | x <- x+1 |
| | -6 | 3 | 2 | rien : x>y | |||||
^ 4 | 3 | 0 | 4 | (0,4) | oui | | d <- d-2*x -1 | -0- | x <- x+1 |
| | 2 | 1 | 4 | (1,4) | oui | | d <- d-2*x -1 | -0- | x <- x+1 |
| | -1 | 2 | 4 | (2,4) | non | oui | d <- d+2x-1 | y <- y-1 | -0- |
| | 2 | 2 | 3 | (2,3) | non | non | d <- d+2x-1 | y <- y-1 | x <- x+1 |
| | 5 | 3 | 2 | rien: x>y | |||||