Ce petit programme vous permet de dessiner une structure fractale à la main. En fait c'est assez différent des autres générateurs de fractales habituels : ici pas de plan complexe, pas de jolies fractales de Mandelbrot, on peut très bien comprendre comment ça marche avec quelques connaissances de base en géométrie et trigonométrie (comme moi quoi). Pour donner un exemple vous dessinez d'abord un 'générateur' et puis vous dessinez la 'forme' que vous voulez faire prendre à votre fractale. Le programme va s'occuper de répéter votre 'générateur' sur chaque segment de votre 'forme', et le faire plusieurs fois afin d'obtenir une structure fractale. Par exemple, avec une ligne composé de 4 segments qui forme un triangle comme 'générateur', et un triangle équilatéral comme 'forme', vous aurez un flocon de Koch.
Ici le programme fait seulement trois générations, mais vous pouvez facilement changez ça dans la fonction BOUTON_Valider
Le vrai intérêt du code est je pense plutôt le système de 'event' développé pour pouvoir facilement manipuler des boutons, des 'surfaces',... que l'algorithme de génération de la fractale
connaissances requises pour ce programme : quelques bases en géométrie/trigonométrie, listes chainées, pointeurs sur fonctions, mode graphique VGA 13h
Source / Exemple :
#include "fractal.h"
int addy; // permet d'afficher le 200eme pixel
//------//------//------//------//------//------//------//------//------//
int main(int argc,char** argv)
{
EVENT* e;
int i;
//------// DESSIN DE L'INTERFACE //-----------------------------//
// initialise le mode graphique
GFX_Init();
// dessine l'interface rouge a droite
for (i=0 ; i<200 ; i++)
memset(SCREEN+201+320*i,LIGHTRED,119);
// affiche le titre (avec une petite ombre)
GFX_Print(SCREEN,220, 9,RED ,-1,"GENERATEUR");
GFX_Print(SCREEN,220,17,RED ,-1,"DE FRACTAL");
GFX_Print(SCREEN,219, 8,BLACK,-1,"GENERATEUR");
GFX_Print(SCREEN,219,16,BLACK,-1,"DE FRACTAL");
// affiche la 'boite de texte'
for (i=MENU_TEXT-1 ; i<MENU_TEXT+(18-MENU_BOUTONS)*8+1 ; i++)
memset(SCREEN+MENU_X+320*i-1,WHITE,99);
//------// EVENEMENTS //----------------------------------------//
// initialise le gestionnaire d'evenements
EVENT_Init(0,319,0,199,0x3FF,0xFF);
// cree les boutons
BOUTON_Func[0]=&BOUTON_Nouveau;
BOUTON_Func[1]=&BOUTON_Valider;
BOUTON_Func[2]=&BOUTON_Annuler;
BOUTON_Func[3]=&BOUTON_Quitter;
strcpy(BOUTON_String[0]," Nouveau ");
strcpy(BOUTON_String[1]," Valider ");
strcpy(BOUTON_String[2]," Annuler ");
strcpy(BOUTON_String[3]," Quitter ");
for (i=0 ; i<MENU_BOUTONS ; i++)
{
e=EVENT_Create(); // nouvel evenement
e->Id=i; // id = numero du bouton
e->AreaIn=1; // interieur 'plein'
e->x1=MENU_X-1; // defini les coordonnees
e->x2=e->x1+99; // du bouton, d'apres le
e->y1=i*12+MENU_Y; // numero du bouton et les
e->y2=e->y1+9; // coordonnees du menu
e->fin=&BOUTON_RemplirIn; // fonction 'IN'
e->fout=&BOUTON_RemplirOut; // fonction 'OUT'
BOUTON_RemplirOut(e); // dessine le bouton
BOUTON_Event[i]=e; // le rajoute au tableau
}
// cree la surface de dessin
e=EVENT_Create();
e->AreaIn=1;
e->x1=0;
e->x2=200;
e->y1=0;
e->y2=200;
e->fin=&FRACTAL_Dessin;
e->fout=&FRACTAL_DessinOut;
addy=0;
//------// AUTRES INITIALISATIONS + PROGRAMME //----------------//
// initialise le fractal et le generateur
FRACTAL_Init();
while (1)
{
// gestionnaire des evenements
EVENT_Manager(&__fractal_intermediaire);
// affichage (avec curseur magenta clair)
GFX_Display(LIGHTMAGENTA);
}
// cette partie est absolument inutile
// vu qu'on a une boucle infinie juste
// avant, elle est la juste pour faire
// 'plus propre'...
// efface les fractals
EVENT_Delete(NULL);
// fini !
return 0;
}
//------//------//------//------//------//------//------//------//------//
void FRACTAL_Affiche()
{
FRACT* f;
int i;
// avant toute chose, on efface la surface de dessin
for (i=0 ; i<200 ; i++) memset(SCREEN+320*i,BLACK,201);
if (etape==MODE_GENER)
FRACTAL_Tracer(gener_debut,LIGHTGREEN);
else if (etape==MODE_FRACT)
{
FRACTAL_Tracer(gener_debut,DARKGRAY);
FRACTAL_Tracer(fract_debut,LIGHTGREEN);
}
else
{
// convertit les positions
f=final;
while (f)
{
f->x=100.0+f->x*100.0;
f->y=100.0-f->y*100.0;
f=f->n;
}
// dessine le fractal
FRACTAL_Tracer(final,LIGHTRED);
// reconvertit les positions
f=final;
while (f)
{
f->x=f->x/100.0-1.0;
f->y=1.0-f->y/100.0;
f=f->n;
}
}
}
//------//------//------//------//------//------//------//------//------//
FRACT* FRACTAL_Copier(FRACT* f1)
{
FRACT* f2;
FRACT* f2_debut;
f2=malloc(sizeof(FRACT));
f2_debut=f2;
f2->p=NULL;
while (f1->n)
{
f2->x=f1->x;
f2->y=f1->y;
f2->a=f1->a;
f2->l=f1->l;
f2->n=malloc(sizeof(FRACT));
f2->n->p=f2;
f2=f2->n;
f1=f1->n;
}
f2->x=f1->x;
f2->y=f1->y;
f2->a=f1->a;
f2->l=f1->l;
f2->n=NULL;
return f2_debut;
}
//------//------//------//------//------//------//------//------//------//
void FRACTAL_Dessin(EVENT* e)
{
FRACT* f;
FRACT* f2;
// fixe le pointeur selon ce qui doit etre dessine
if (etape==MODE_GENER) f=gener;
else if (etape==MODE_FRACT) f=fract;
else return;
// affiche la position
GFX_Print(SCREEN,MENU_X,MENU_TEXT ,BLACK,WHITE,
"X : %.2f ",(double)(EVENT_x)/100.0-1.0);
GFX_Print(SCREEN,MENU_X,MENU_TEXT+8 ,BLACK,WHITE,
"Y : %.2f ",1.0-(double)(EVENT_y)/100.0);
// empeche l'utilisateur de dessiner trop de segments
if (((nsegs_fract==MAX_SEGS)&&(etape==MODE_FRACT))
|| ((nsegs_gener==MAX_SEGS)&&(etape==MODE_GENER)))
{
FRACTAL_Affiche();
return;
}
// si l'utilisateur doit dessiner le tout premier point
if (!f)
{
// si l'utilisateur a clique
if ((EVENT_button&1)&&(!(EVENT_button2&1)))
{
// creation du premier vertex
f=malloc(sizeof(FRACT));
f->p=NULL;
f->n=NULL;
f->x=EVENT_x;
f->y=EVENT_y;
nsegs_fract++;
fract_debut=f;
}
}
// si l'utilisateur rajoute un segment
else if ((f->x!=EVENT_x)||(f->y!=EVENT_y))
{
// affiche l'angle et la longueur
f->a=ANGLE(f->x,f->y,EVENT_x,EVENT_y);
f->l=LONGUEUR(f->x,f->y,EVENT_x,EVENT_y)/200.0;
GFX_Print(SCREEN,MENU_X,MENU_TEXT+16,BLACK,WHITE,
"A : %.2f ",f->a);
GFX_Print(SCREEN,MENU_X,MENU_TEXT+24,BLACK,WHITE,
"L : %.2f ",f->l);
// redessine le fractal
FRACTAL_Affiche();
// dessine la premiere ligne
LIGNE
(
SCREEN,
f->x,
f->y,
EVENT_x,
EVENT_y,
LIGHTBLUE
);
// dessine la deuxieme ligne, si mode generateur
if (etape==MODE_GENER) LIGNE
(
SCREEN,
EVENT_x,
EVENT_y,
f->n->x,
f->n->y,
LIGHTBLUE
);
// si clic gauche
if ((EVENT_button&1)&&(!(EVENT_button2&1)))
{
// nouveau point
f2=f->n;
f->n=malloc(sizeof(FRACT));
f->n->p=f;
f=f->n;
f->n=f2;
if (f2) f2->p=f;
// on enregistre les coordonnees
f->x=EVENT_x;
f->y=EVENT_y;
// on augmente le compteur correspondant
if (etape==MODE_GENER) nsegs_gener++;
else if (etape==MODE_FRACT) nsegs_fract++;
}
}
// on actualise le pointeur correspondant
if (etape==MODE_GENER) gener=f;
else if (etape==MODE_FRACT) fract=f;
}
//------//------//------//------//------//------//------//------//------//
void FRACTAL_DessinOut(EVENT* e)
{
// dessine le fractal
FRACTAL_Affiche();
if (etape!=MODE_FINAL)
{
// efface les coordonnes de la souris
GFX_Print(SCREEN,MENU_X,MENU_TEXT ,BLACK,WHITE,
"X : ");
GFX_Print(SCREEN,MENU_X,MENU_TEXT+8 ,BLACK,WHITE,
"Y : ");
GFX_Print(SCREEN,MENU_X,MENU_TEXT+16,BLACK,WHITE,
"A : ");
GFX_Print(SCREEN,MENU_X,MENU_TEXT+24,BLACK,WHITE,
"L : ");
}
}
//------//------//------//------//------//------//------//------//------//
void FRACTAL_Effacer(FRACT* pf)
{
while (pf->n)
{
pf=pf->n;
free(pf->p);
}
free(pf);
}
//------//------//------//------//------//------//------//------//------//
void FRACTAL_Generation(FRACT* pf)
{
FRACT* f;
double a;
double l;
// genere le fractal
while (pf->n)
{
a=pf->a;
l=pf->l;
gener=gener_debut;
while (gener->n->n)
{
// on cree un nouveau point
f=pf->n;
pf->n=malloc(sizeof(FRACT));
pf->n->p=pf;
pf->n->n=f;
f->p=pf->n;
// on calcule l'angle et la longueur
pf->a=a+gener->a;
pf->l=l*gener->l;
// on calcule ses coordonnees
pf->n->x=pf->x+pf->l*cos(pf->a*PI/180.0);
pf->n->y=pf->y+pf->l*sin(pf->a*PI/180.0);
gener=gener->n;
pf=pf->n;
}
pf->a=a+gener->a;
pf->l=l*gener->l;
pf=pf->n;
}
}
//------//------//------//------//------//------//------//------//------//
void FRACTAL_Init()
{
// initialise la variable qui specifie l'action en cours
etape=MODE_GENER;
// initialise le fractal
fract=NULL;
fract_debut=NULL;
nsegs_fract=-1;
final=NULL;
// initialise le generateur
gener=malloc(sizeof(FRACT));
gener->x=0;
gener->y=100;
gener->n=malloc(sizeof(FRACT));
gener->p=NULL;
gener_debut=gener;
gener=gener->n;
gener->n=NULL;
gener->p=gener_debut;
gener->x=200;
gener->y=100;
gener=gener_debut;
nsegs_gener=1;
}
//------//------//------//------//------//------//------//------//------//
void FRACTAL_Tracer(FRACT* f,char c)
{
// on dessine le fractal
if (f) while (f->n)
{
LIGNE // on trace un segment
(
SCREEN,
f->x,
f->y,
f->n->x,
f->n->y,
c
);
f=f->n; // segment suivant
if (EVENT_button&2) { getch(); GFX_Display(LIGHTMAGENTA); }
}
}
//------//------//------//------//------//------//------//------//------//
void __fractal_intermediaire()
{
if (EVENT_key==72<<8) addy=0;
if (EVENT_key==80<<8) addy=1;
EVENT_y+=addy;
}
Conclusion :
en fait je dois vous avertir que j'ai abandonné l'écriture du programme alors qu'il était presque fini, en fait ça m'intéressait plus trop. il n'est donc pas possible d'enregistrer la fractale
cependant je trouve le code assez intéressant pour figurer sur cppfrance
j'avais aussi déjà fait un programme similaire, mais très mal foutu et qui faisait planter nombre de PC. ici c'est simplement du mode graphique 320x200x256, ça devrait aller mieux. le code est également un peu plus clair
pour compiler le prog, faites :
gcc fractal.c bouton.c gfx.c event.c -s -Wall -o fractal.exe
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.