PDA

Voir la version complète : Clipping qui bug


Oragon
09/10/2005, 15h12
J'essaie de faire un peu de clipping avec mes fonctions graphiques.

Ca consiste juste en n'allumer que les pixels si les coordonnées respectent la condition suivante :
0=<X<screen witdh
0=<Y<screen height

pour mes pixels et mes lignes ça marche, mais voici le résultat pour mes cercles :
http://img394.imageshack.us/img394/396/badclipping0rx.jpg

(j'ai fait 4 cercles ici, j'ai mis en rouge ceux qui vont pas).

Savez vous d'ou vient mon erreur ?

Ey-Lord
09/10/2005, 17h30
Je pense ne pas trop m'avance en disant que sans de plus ample explication ... il va nous être tés difficile de savoir ou ca coince :/ ( si tes fonctions sont simple & courte), un peu de code pourrait aider :)

Oragon
10/10/2005, 20h38
Oui excusez-moi.

Je programme en C avec SDL.

voici ma fonction pour le pixel :
void pxl(Uint16 x, Uint16 y, Uint32 color)
{
if((x>0)&&(x<((screen->w)-1))&&(y>0)&&(y<((screen->h)-1))) // si ça reste dans la surface.
{
if(SDL_MUSTLOCK(screen)==1){SDL_LockSurface(screen);} //vérouille la surface
Uint32 *bufp;

bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
*bufp=color; // met la couleur là ou il faut ^^

if(SDL_MUSTLOCK(screen)==1){SDL_UnlockSurface(screen);} //dévérouille la surface
}
}

ligne :
void line(Uint16 xi, Uint16 yi, Uint16 xf, Uint16 yf, Uint32 color)
{
int dx,dy,i,xinc,yinc,cumul,x,y ;
x = xi;
y = yi;
dx = xf - xi;
dy = yf - yi;
xinc = ( dx > 0 ) ? 1 : -1;
yinc = ( dy > 0 ) ? 1 : -1;
dx = abs(dx);
dy = abs(dy);

pxl(x,y, color);

if ( dx > dy )
{
cumul = dx/2;
for ( i = 1 ; i <= dx ; i++ )
{
x += xinc ;
cumul += dy ;
if (cumul >= dx)
{
cumul -= dx ;
y += yinc ;
}
pxl(x,y, color);
}
}
else
{
cumul=dy/2;
for ( i = 1 ; i <= dy ; i++ )
{
y += yinc;
cumul += dx;
if ( cumul >= dy )
{
cumul -= dy;
x += xinc ;
}
pxl(x,y, color);
}
}
}
(c la seule que je n'ai pas faite moi même)

et cercle :
(ou plutot ellipse)
void ellipse(Uint16 cx, Uint16 cy, Uint16 rx, Uint16 ry, Uint32 color)
{
Uint16 oldx, oldy, x, y;
Uint16 angle;
double rad;

for(angle=0;angle<361;angle++)
{
rad=3.14159265*(angle)/180; //deg->rad

x=cx+cos(rad)*rx;
y=cy+sin(rad)*ry;

if(angle>0){line(x, y, oldx, oldy, color);}
oldx=x;oldy=y;

}
}
elle devait tracer allumer un pixel en :
centre+cos(angle)*rayon,
centre+sin(angle)*rayon

mais pour combler les trous j'ai fait des lignes entre eux.

kendeau
14/10/2005, 02h31
Salut, moi aussi je programme avec SDL mais je viens juste de la découvrir, en tous cas si je me refère à la condition que tu as donné :
0=<X<screen witdh
0=<Y<screen height

cela signifie que seuls les pixels faisant partie de l'écran seront affichés, donc je comprend que la moitié d'un cercle qui sort de l'ecran ne soit pas affiché ^^
pour moi il n'y a pas de problemes puisque ce que je vois correspond à ta condition.
Si tu ne veux pas que tes cercles soient coupés, il faut décaler leur centre de la longueur du rayon, car tel que je le vois à l'écran il semble que c'est x,y qui est le centre du cercle, enfin visuellement c'est ce que cela donne.

Ton probleme vient de cx et cy ^^
Il faut plutot les décaler des bords de l'ecran de la longueur du rayon.
par exemple en faisant :

cx++rx; // ajoute rx à cx, donc le rayon au centre.
cy++ry; // ajoute ry à cy, donc le rayon au centre.
for(angle=0;angle<361;angle++)
{
rad=3.14159265*(angle)/180; //deg->rad
x=cx+cos(rad)*rx;
y=cy+sin(rad)*ry;
if(angle>0){line(x, y, oldx, oldy, color);}
oldx=x;oldy=y;
}

Je veux dire par là que tu teste en ce moment si xy sort de l'écran, c'est valable pour tout sauf pour les cercles bien sûr, puisque pour eux ce n'est pas xy qu'il faut tester mais leur centre cx,cy.

Par contre une fois corrigé, quand tu voudra demander à dessiner un cercle à une position colonne,ligne tu pensera que c'est le centre du cercle qui sera à cette position, hé bien non, ce sera en fait la tangente, donc le centre+le rayon quoi^^ c'est un probleme un peu car tu ne pourra jamais placer le centre du cercle pile à l'endroit que tu veut.
LA solution est donc de n'accorder le dessin du cercle QUE si son centre est éloigné des bords d'une distance de rayon.
Comme ceci :

//maxWidth étant par exemple la largeur de l'écran.
//maxHeight étant par exemple la hauteur de l'écran.
if ( (cx<maxWidth-rx)&&(cx>rx) )
{
if ( (cy<maxHeight-ry)&&(cy>ry) )
{
// début du dessin du cercle autorisé.
for(angle=0;angle<361;angle++)
{
rad=3.14159265*(angle)/180; //deg->rad
x=cx+cos(rad)*rx;
y=cy+sin(rad)*ry;
if(angle>0){line(x, y, oldx, oldy, color);}
oldx=x;oldy=y;
}
// fin du dessin du cercle.
}
}

Voilà, la ça devrait fonctionner impeccable, sauf qu'il ne dessinera pas bien sûr les cercles dont le centre ferait couper le cercle s'il était affiché.

J'aurais pu mettre les deux conditions ensembles :

if ( ( (cx<maxWidth-rx)&&(cx>rx) )&&( (cy<maxHeight-ry)&&(cy>ry) ) )
{
// début du dessin du cercle.
//fin du dessin.
}

Mais je trouve que ça fait compliqué quand tu veux te relire un jour, il faut penser à plus tard ou quand tu filera ton source à autrui, c'est ça la bonne programmation aussi ^^


Une question :
Tu fais des fonctions pour tracer une ellypse par exemple, mais est-ce qu'il n'y a pas dans SDL ou dans Dev-c++ des fonctions toutes pretes et plus optimisées ?

Oragon
14/10/2005, 14h34
Salut Kendeau.
Méprends-toi. Mon problème ne vient pas du fait que le cercle soit coupé, car justement.

Si sans mon idée de "couper" le cercle, je decide d'en tracer un dont une partie sort de la surface. le programme plante et quitte directement.

Mon problème vient des deux droites attachées au dessin qui traversent la surace (revoie mon dessin tu verras). Le fait qu'elles soient en rouge montrent bien qu'elles font partie intégrante de mon cercle, et c'est ce qui me gêne. Comment ces lignes ont elles été tracées sachant que tout ce que j'ai demandé, c'est de ne pas afficher les pixels du cercle ne faisant pas partie de l'écran.

(Ma fonction cercle appelle la fonction ligne, qui appelle elle même la fonction pixel.)

Nrl je devrais obtenir ça :
http://img425.imageshack.us/img425/893/gclipping3tg.jpg