Tracer des lignes [djgpp]

Description

voila une fonction que j'ai créer pour tracer des lignes. A l'origine elle est faite pour un kit pour faire des jeux videos en VGA 13h que je suis en train de faire, mais j'ai deja mis la fonction ici. Elle peut etre utilisee pour n'importe quelle mode graphique (ou meme texte) car elle utilise une reference de fonction.

Source / Exemple :


#include <stdio.h>		/* pour printf et getch */
#include <conio.h>		/* pour gotoxy */

/*
   Pour une meilleure comprehension voici la formule,
   le code en est tres different car il utilise plein
   d'astuces pour avoir moins de calcul a faire, mais 
   en gros c'est ça :

   soit deux point A(a,b) et B(c,d)

   m=(d-b)/(c-a);

   tout point M(x,y) appartenant a [AB]
   verifie donc l'equation :

   y=mx-ma+b  
   x=(ma-b+y)/m

  • /
/* firstx => position X du premier point de la ligne firsty => position Y du premier point de la ligne lastx => position X du dernier point de la ligne lasty => position Y du dernier point de la ligne void (&func)(int,int) => reference de la fonction a appeler
  • /
void glbDrawLine(int firstx,int firsty,int lastx,int lasty,void (&func)(int,int)) { int x1; /* debut de la ligne => milieu de la ligne */ int y1; /* debut de la ligne => milieu de la ligne */ int x2; /* fin de la ligne => milieu de la ligne */ int y2; /* fin de la ligne => milieu de la ligne */ int dx; /* longueur X de la droite */ int dy; /* longueur Y de la droite */ int sub; /* utilise pour des soustractions */ int remain; /* nombre de pixel restant */ int error; /* erreur du trace, doit etre corrige si positif */ int inc1; /* pour des incrementations/decrementations */ int inc2; /* pour des incrementations/decrementations */ /* x1 = premier point X x2 = dernier point X y1 = premier point Y y2 = dernier point Y si firstx > lastx les premiers et les derniers sont inverses
  • /
if (firstx>lastx) { x1=lastx; x2=firstx; y1=lasty; y2=firsty; } else { x1=firstx; x2=lastx; y1=firsty; y2=lasty; } dx=x2-x1; /* longueur X de la droite */ dy=y2-y1; /* longueur Y de la droite */ if ((!dx)&&(!dy)) return; /* quitte si aucun trace a effectuer */ /* si dy negatif, inverse dy et initialise les incrementation selon le signe de dy (afin que les droites aillent dans le bon sens
  • /
if (dy<0) { dy=-dy; inc1=-1; inc2=1; } else { inc1=1; inc2=1; } /* pour augmenter la rapidite du code vous pouvez rajoutez ici des algos pour les droites horizontales (dy==0), verticales (dx==0) et diagonale (dx==dy) car ces droites ne necessitent pas d'algorythme complique, mais la taille du code en souffrira
  • /
/* pour aller plus vite on dessine la droite des deux cotes a la fois, en meme temps a partir du premier point et du dernier
  • /
/* si la droite est plutot horizontale */ if (dx>dy) { sub=dx-dy; error=dy-(dx>>1); remain=(dx+1)>>1; /* dx+1 est le nombre de points a tracer, diviser par deux car on dessine des deux cotes a la fois
  • /
/* pour mieux comprendre sachez que la position x doit augmenter de 1 a chaque tour et y de dy/dx a chaque tour (car sur la longueur dx y doit en tout augmenter de dy).
  • /
do { func(x1,y1); /* appelle la fonction de dessin avec en parametre */ func(x2,y2); /* les positions des points a dessiner */ x1+=inc2; /* la position x1 augmente */ x2-=inc2; /* et la position x2 diminue (on va vers le centre) */ if (error>=0) /* si l'erreur est assez grande pour etre corrigee */ { y1+=inc1; /* la position y1 augmente */ y2-=inc1; /* et la position y2 diminue (on va vers le centre) */ error-=sub; /* diminue l'erreur */ } else error+=dy; /* sinon augmente l'erreur */ } while (--remain>0); /* diminue remain et recommence s'il reste des points a tracer */ if (!(dx&1)) func(x1,y1); /* si dx etait pair l'algo n'a pas pu tracer le point du milieu car il a fait une division entiere par deux sur dx pour connaitre le nombre de points a tracer et a ainsi perdu le 1
  • /
return; /* fin de la fonction */ } else { sub=dy-dx; error=dx-(dy>>1); remain=(dy+1)>>1; /* dy+1 est le nombre de points a tracer, diviser par deux car on dessine des deux cotes a la fois
  • /
/* pour mieux comprendre sachez que la position y doit augmenter de 1 a chaque tour et x de dx/dy a chaque tour (car sur la longueur dy x doit en tout augmenter de dx).
  • /
do { func(x1,y1); /* appelle la fonction de dessin avec en parametre */ func(x2,y2); /* les positions des points a dessiner */ y1+=inc2; /* la position y1 augmente */ y2-=inc2; /* et la position y2 diminue (on va vers le centre) */ if (error>=0) /* si l'erreur est assez grande pour etre corrigee */ { x1+=inc2; /* la position x1 augmente */ x2-=inc2; /* et la position x2 diminue (on va vers le centre) */ error-=sub; /* diminue l'erreur */ } else error+=dx; /* sinon augmente l'erreur */ } while (--remain>0); /* diminue remain et recommence s'il reste des points a tracer */ if (!(dy&1)) func(x1,y1); /* si dy etait pair l'algo n'a pas pu tracer le point du milieu car il a fait une division entiere par deux sur dy pour connaitre le nombre de points a tracer et a ainsi perdu le 1
  • /
return; /* fin de la fonction */ } } /* Fonction qui dessine le caractere 0xDB (un carre) a la position xy. Vous pouvez creer n'importe quelle autre fonction pour afficher vos points, aussi bien en mode texte qu'en mode graphique, mais la fonction ne doit rien renvoyer et accepter deux parametres de type int pour les positions du point.
  • /
void putcara(int x,int y) { gotoxy(x,y); printf("\xDB"); } /* Et enfin la fonction principale qui trace une ligne...
  • /
int main() { glbDrawLine(1,1,79,25,putcara); /* dessine une ligne de 1-1 a 79-25 avec la fonction putcara(int x,int y) */ getch(); /* attend une pression de touche */ return 0; /* fini ! */ }

Conclusion :


Voila. Pour informations, c'est l'algorythme de Bresenham (ou Bresenhau ?).
Pour mieux comprendre le code, allez faire un tour sur http://www.vije.net/~opecheux/abcp, dans la section divers il y a un article tres complet et bien fait pour tracer des lignes et qui m'a beaucoup aide.
J'ai mis niveau 2 parce que le code est complique, mais bon sinon c'est que du math il ne faut pas beaucoup de connaissances en C++. Désolé je n'ai pas commenté la source.

Codes Sources

A voir également

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.