INFO607
main.c
Go to the documentation of this file.
1#include <stdlib.h>
2#include <math.h>
3#include <assert.h>
4#include <gtk/gtk.h>
5#include "points.h"
6#include "particules.h"
7#include "forces.h"
8
9//-----------------------------------------------------------------------------
10// Déclaration des types
11//-----------------------------------------------------------------------------
12/**
13 Le contexte contient les informations utiles de l'interface pour
14 les algorithmes de géométrie algorithmique.
15*/
16typedef struct SContexte {
17 int width;
18 int height;
19 GtkWidget* drawing_area;
22 GtkWidget* label_nb;
23 GtkWidget* label_distance;
25
26// Pas de temps en s
27#define DT 0.01
28// Pas de temps en s pour le réaffichage
29#define DT_AFF 0.02
30
31
32//-----------------------------------------------------------------------------
33// Déclaration des fonctions
34//-----------------------------------------------------------------------------
35/**
36 Crée l'interface graphique en fonction du contexte \a pCtxt.
37*/
38GtkWidget* creerIHM( Contexte* pCtxt );
39
40/**
41 c'est la réaction principale qui va redessiner tout.
42*/
43gboolean on_draw( GtkWidget *widget, GdkEventExpose *event, gpointer data );
44
45/**
46 Fait la conversion coordonnées réelles de \a p vers coordonnées de la zone de dessin.
47 @param pCtxt le contexte de l'IHM
48 @param p le point en entrée
49 @return ses coordonnées dans la zone de dessin.
50*/
52
53/**
54 Fait la conversion longueur réelle \a l vers longueur en pixel dans la zone de dessin.
55 @param pCtxt le contexte de l'IHM
56 @param l la longueur réelle
57 @return la longueur correspondante en pixels.
58*/
59double length2DrawingAreaLength( Contexte* pCtxt, double l );
60
61/**
62 Fait la conversion coordonnées pixel de \a p vers coordonnées réelles.
63 @param pCtxt le contexte de l'IHM
64 @param p les coordonnées pixel en entrée
65 @return ses coordonnées réelles.
66*/
68
69/**
70 Affiche un point \a p dans une zone de dessin cairo \a cr comme un disque.
71 La masse influe sur la taille d'affichage de la particule.
72
73 @param cr le contexte CAIRO pour dessiner dans une zone de dessin.
74 @param p un point dans la zone de dessin.
75 */
76void drawParticule( Contexte* pCtxt, cairo_t* cr, Particule p );
77
78/**
79 Fonction de base qui affiche un disque de centre (x,y) et de rayon r via cairo.
80*/
81void drawPoint( cairo_t* cr, double x, double y, double r );
82
83/**
84 Fonction appelée régulièrement (tous les DT secondes) et qui s'occupe de (presque tout):
85 - générer de nouvelles particules: \ref fontaine
86 - calculer les forces sur chaque particule: \ref calculDynamique
87 - déplacer les particules et gérer les collisions: \ref deplaceTout
88
89 @param data correspond en fait au pointeur vers le Contexte.
90*/
91gint tic( gpointer data );
92
93/**
94 Fonction appelée régulièrement (tous les DT_AFF secondes) et qui
95 s'occupe de demander le réaffichage dela zone de dessin.
96
97 @param data correspond en fait au pointeur vers le Contexte.
98*/
99gint ticAffichage( gpointer data );
100
101/**
102 Fonction appelée régulièrement (tous les secondes) et qui
103 affiche le nombre d'appels à la fonction \c distance par seconde.
104
105 @param data correspond en fait au pointeur vers le Contexte.
106*/
107gint ticDistance( gpointer data );
108
109/**
110 Calcul la dynamique de tous les points en appliquant les forces et
111 met à jour la vitesse.
112*/
113void calculDynamique( Contexte* pCtxt );
114
115/**
116 Déplace toutes les particules en fonction de leur vitesse.
117*/
118void deplaceTout( Contexte* pCtxt );
119
120/**
121 Déplace une particule en fonction de sa vitesse. Devra s'occuper
122 des collisions plus tard.
123*/
124void deplaceParticule( Contexte* pCtxt, Particule* p );
125
126/**
127 Fontaine pour créer une particule à la position (\a x, \a y), avec
128 la vitesse (\a vx, \a vy) et la masse \a m.
129
130 @param p probabilité (entre 0 et 1) qu'une particule soit effectivement créée.
131 @param x la coordonnée x de la position où la particule est créée.
132 @param y la coordonnée y de la position où la particule est créée.
133 @param vx la composante x de la vitesse de la particule.
134 @param vy la composante y de la vitesse de la particule.
135 @param m la masse de la particule créée.
136 */
137void fontaine( Contexte* pCtxt, double p,
138 double x, double y, double vx, double vy, double m );
139
140
141//-----------------------------------------------------------------------------
142// Programme principal
143//-----------------------------------------------------------------------------
144int main( int argc,
145 char* argv[] )
146{
147 Contexte context;
148 TabParticules_init( &context.TabP );
149
150 /* Passe les arguments à GTK, pour qu'il extrait ceux qui le concernent. */
151 gtk_init( &argc, &argv );
152
153 /* Crée une fenêtre. */
154 creerIHM( &context );
155
156 /* Rentre dans la boucle d'événements. */
157 gtk_main ();
158 return 0;
159}
160
161
162gboolean
163on_draw( GtkWidget *widget, GdkEventExpose *event, gpointer data )
164{
165 // c'est la réaction principale qui va redessiner tout.
166 Contexte* pCtxt = (Contexte*) data;
167 TabParticules* ptrP = &(pCtxt->TabP);
168 // c'est la structure qui permet d'afficher dans une zone de dessin
169 // via Cairo
170 GdkWindow* window = gtk_widget_get_window(widget);
171 cairo_region_t* cairoRegion = cairo_region_create();
172 GdkDrawingContext* drawingContext
173 = gdk_window_begin_draw_frame( window, cairoRegion );
174 cairo_t* cr = gdk_drawing_context_get_cairo_context( drawingContext );
175 cairo_set_source_rgb (cr, 1, 1, 1); // choisit le blanc.
176 cairo_paint( cr ); // remplit tout dans la couleur choisie.
177
178 // Affiche tous les points en bleu.
179 cairo_set_source_rgb (cr, 0, 0, 1);
180 for ( int i = 0; i < TabParticules_nb( ptrP ); ++i )
181 {
182 drawParticule( pCtxt, cr, TabParticules_get( ptrP, i ) );
183 }
184
185 // On a fini, on peut détruire la structure.
186 gdk_window_end_draw_frame(window,drawingContext);
187 // cleanup
188 cairo_region_destroy(cairoRegion);
189 return TRUE;
190}
191
193{
194 Point q;
195 q.x[ 0 ] = ( p.x[ 0 ] + 1.0 ) / 2.0 * pCtxt->width;
196 q.x[ 1 ] = ( 1.0 - p.x[ 1 ] ) / 2.0 * pCtxt->height;
197 return q;
198}
199
200double length2DrawingAreaLength( Contexte* pCtxt, double l )
201{
202 return pCtxt->width * l / 2.0;
203}
204
206{
207 Point q;
208 q.x[ 0 ] = 2.0 * ((double)p.x[0] / (double)pCtxt->width) - 1.0;
209 q.x[ 1 ] = -2.0 * ((double)p.x[1] / (double)pCtxt->height) + 1.0;
210 return q;
211}
212
213void drawParticule( Contexte* pCtxt, cairo_t* cr, Particule p )
214{
215 Point pp;
216 pp.x[ 0 ] = p.x[ 0 ];
217 pp.x[ 1 ] = p.x[ 1 ];
218 // On convertit les coordonnées réelles des particules (dans [-1:1]x[-1:1]) en coordonnées
219 // de la zone de dessin (dans [0:499]x[0:499]).
220 Point q = point2DrawingAreaPoint( pCtxt, pp );
221 drawPoint( cr, q.x[ 0 ], q.x[ 1 ], 1.5*sqrt( p.m ) );
222}
223
224void drawPoint( cairo_t* cr, double x, double y, double r )
225{
226 cairo_arc( cr, x, y, r, 0.0, 2.0 * 3.14159626 );
227 cairo_fill( cr );
228}
229
230void drawLine( cairo_t* cr, Point p, Point q )
231{
232 cairo_move_to( cr, p.x[ 0 ], p.x[ 1 ] );
233 cairo_line_to( cr, q.x[ 0 ], q.x[ 1 ]);
234 cairo_stroke( cr );
235}
236
237/// Charge l'image donnée et crée l'interface.
238GtkWidget* creerIHM( Contexte* pCtxt )
239{
240 GtkWidget* window;
241 GtkWidget* vbox1;
242 GtkWidget* vbox2;
243 GtkWidget* hbox1;
244 GtkWidget* button_quit;
245
246 /* Crée une fenêtre. */
247 window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
248 // Crée un conteneur horizontal box.
249 hbox1 = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, 10 );
250 // Crée deux conteneurs vertical box.
251 vbox1 = gtk_box_new( GTK_ORIENTATION_VERTICAL, 10 );
252 vbox2 = gtk_box_new( GTK_ORIENTATION_VERTICAL, 10 );
253 // Crée une zone de dessin
254 pCtxt->drawing_area = gtk_drawing_area_new();
255 pCtxt->width = 500;
256 pCtxt->height = 500;
257 gtk_widget_set_size_request ( pCtxt->drawing_area, pCtxt->width, pCtxt->height );
258 // Crée le pixbuf source et le pixbuf destination
259 gtk_container_add( GTK_CONTAINER( hbox1 ), pCtxt->drawing_area );
260 // ... votre zone de dessin s'appelle ici "drawing_area"
261 g_signal_connect( G_OBJECT ( pCtxt->drawing_area ), "draw",
262 G_CALLBACK( on_draw ), pCtxt );
263 // Rajoute le 2eme vbox dans le conteneur hbox (pour mettre les boutons sélecteur de points
264 gtk_container_add( GTK_CONTAINER( hbox1 ), vbox2 );
265 // Crée les labels pour afficher le nombre de points et le nombre
266 // d'appel à la fonction distance.
267 pCtxt->label_nb = gtk_label_new( "0 points" );
268 gtk_container_add( GTK_CONTAINER( vbox2 ), pCtxt->label_nb );
269 pCtxt->label_distance = gtk_label_new( "" );
270 gtk_container_add( GTK_CONTAINER( vbox2 ), pCtxt->label_distance );
271
272 // Crée le bouton quitter.
273 button_quit = gtk_button_new_with_label( "Quitter" );
274 // Connecte la réaction gtk_main_quit à l'événement "clic" sur ce bouton.
275 g_signal_connect( button_quit, "clicked",
276 G_CALLBACK( gtk_main_quit ),
277 NULL);
278 // Rajoute tout dans le conteneur vbox.
279 gtk_container_add( GTK_CONTAINER( vbox1 ), hbox1 );
280 gtk_container_add( GTK_CONTAINER( vbox1 ), button_quit );
281 // Rajoute la vbox dans le conteneur window.
282 gtk_container_add( GTK_CONTAINER( window ), vbox1 );
283
284 // Rend tout visible
285 gtk_widget_show_all( window );
286 g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
287
288 // Crée les forces
289 Force g = gravite( 0.0, -0.2 );
290 pCtxt->forces[ 0 ] = g;
291
292 // enclenche le timer pour se déclencher dans 5ms.
293 g_timeout_add ( 1000*DT, tic, (gpointer) pCtxt );
294 // enclenche le timer pour se déclencher dans 20ms.
295 g_timeout_add ( 1000*DT_AFF, ticAffichage, (gpointer) pCtxt );
296 // enclenche le timer pour se déclencher dans 1000ms.
297 g_timeout_add ( 1000, ticDistance, (gpointer) pCtxt );
298
299 return window;
300}
301
302void fontaine( Contexte* pCtxt,
303 double p, double x, double y, double vx, double vy, double m )
304{
305 TabParticules* P = &pCtxt->TabP;
306 if ( ( rand() / (double) RAND_MAX ) < p )
307 {
308 Particule q;
309 initParticule( &q, x, y, vx, vy, m );
310 TabParticules_ajoute( P, q );
311 }
312}
313
314gint tic( gpointer data )
315{
316 Contexte* pCtxt = (Contexte*) data;
317 fontaine( pCtxt, 0.25, -0.5, 0.5, 0.3, 0.3, 2.5 );
318 calculDynamique( pCtxt );
319 deplaceTout( pCtxt );
320 g_timeout_add (1000*DT, tic, (gpointer) pCtxt ); // réenclenche le timer.
321 return 0;
322}
323
324gint ticAffichage( gpointer data )
325{
326 Contexte* pCtxt = (Contexte*) data;
327 char buffer[ 128 ];
328 sprintf( buffer, "%d points", TabParticules_nb( &pCtxt->TabP ) );
329 gtk_label_set_text( GTK_LABEL( pCtxt->label_nb ), buffer );
330 gtk_widget_queue_draw( pCtxt->drawing_area );
331 g_timeout_add (1000*DT_AFF, ticAffichage, (gpointer) pCtxt ); // réenclenche le timer.
332 return 0;
333}
334
335gint ticDistance( gpointer data )
336{
337 Contexte* pCtxt = (Contexte*) data;
338 char buffer[ 128 ];
339 sprintf( buffer, "%7d nb appels à distance()", getCompteurDistance() ),
340 gtk_label_set_text( GTK_LABEL( pCtxt->label_distance ), buffer );
342 g_timeout_add (1000, ticDistance, (gpointer) pCtxt ); // réenclenche le timer.
343 return 0;
344}
345
347{
348 TabParticules* P = &pCtxt->TabP;
349 int n = TabParticules_nb( P );
350 Force* F = pCtxt->forces;
351 // On met à zéro les forces de chaque point.
352 for ( int i = 0; i < n; ++i )
353 {
354 Particule* p = TabParticules_ref( P, i );
355 p->f[ 0 ] = 0.0;
356 p->f[ 1 ] = 0.0;
357 }
358 // On applique les forces à tous les points
359 for ( int i = 0; i < n; ++i )
360 {
361 Particule* p = TabParticules_ref( P, i );
362 for ( int j = 0; j < NB_FORCES; ++j )
363 appliqueForce( p, &F[ j ] );
364 }
365 // On applique la loi de Newton: masse*acceleration = somme des forces
366 // ie m dv/dt = sum f
367 // ie v[t+dt] = v[t] + (dt/m) * sum f
368 for ( int i = 0; i < n; ++i )
369 {
370 Particule* p = TabParticules_ref( P, i );
371 p->v[ 0 ] += (DT / p->m) * p->f[ 0 ];
372 p->v[ 1 ] += (DT / p->m) * p->f[ 1 ];
373 }
374}
375
377{
378 /* Déplace p en supposant qu'il n'y a pas de collision. */
379 p->x[ 0 ] += DT * p->v[ 0 ];
380 p->x[ 1 ] += DT * p->v[ 1 ];
381}
382
383void deplaceTout( Contexte* pCtxt )
384{
385 TabParticules* P = &pCtxt->TabP;
386 int n = TabParticules_nb( P );
387 // Applique le vecteur vitesse sur toutes les particules.
388 for ( int i = 0; i < n; ++i )
389 {
390 Particule* p = TabParticules_ref( P, i );
391 deplaceParticule( pCtxt, p );
392 }
393 // Détruit les particules trop loin de la zone
394 for ( int i = 0; i < TabParticules_nb( P ); )
395 {
396 Particule* p = TabParticules_ref( P, i );
397 if ( ( p->x[ 0 ] < -1.5 ) || ( p->x[ 0 ] > 1.5 )
398 || ( p->x[ 1 ] < -1.5 ) || ( p->x[ 1 ] > 1.5 ) )
400 else ++i;
401 }
402}
403
int getCompteurDistance(void)
Definition points.c:64
void resetCompteurDistance(void)
Remet à zéro le compteur du nombre d'appel à distance.
Definition points.c:59
Force gravite(double gx, double gy)
Définit la force de gravité dans la direction donnée.
Definition forces.c:3
void appliqueForce(Particule *p, Force *f)
Ajoute à la particule p la force donnée f.
Definition forces.c:12
#define NB_FORCES
Definition forces.h:6
#define DT_AFF
Definition main.c:29
gint tic(gpointer data)
Definition main.c:314
gint ticAffichage(gpointer data)
Definition main.c:324
gboolean on_draw(GtkWidget *widget, GdkEventExpose *event, gpointer data)
Definition main.c:163
void fontaine(Contexte *pCtxt, double p, double x, double y, double vx, double vy, double m)
Definition main.c:302
GtkWidget * creerIHM(Contexte *pCtxt)
Charge l'image donnée et crée l'interface.
Definition main.c:238
double length2DrawingAreaLength(Contexte *pCtxt, double l)
Definition main.c:200
void calculDynamique(Contexte *pCtxt)
Definition main.c:346
#define DT
Definition main.c:27
void deplaceParticule(Contexte *pCtxt, Particule *p)
Definition main.c:376
void drawPoint(cairo_t *cr, double x, double y, double r)
Definition main.c:224
Point point2DrawingAreaPoint(Contexte *pCtxt, Point p)
Definition main.c:192
Point drawingAreaPoint2Point(Contexte *pCtxt, Point p)
Definition main.c:205
gint ticDistance(gpointer data)
Definition main.c:335
void deplaceTout(Contexte *pCtxt)
Definition main.c:383
void drawLine(cairo_t *cr, Point p, Point q)
Definition main.c:230
void drawParticule(Contexte *pCtxt, cairo_t *cr, Particule p)
Definition main.c:213
struct SContexte Contexte
int TabParticules_nb(TabParticules *tab)
Definition particules.c:50
Particule * TabParticules_ref(TabParticules *tab, int i)
Definition particules.c:44
void TabParticules_init(TabParticules *tab)
Definition particules.c:18
void TabParticules_supprime(TabParticules *tab, int i)
Definition particules.c:80
void TabParticules_ajoute(TabParticules *tab, Particule p)
Definition particules.c:25
void initParticule(Particule *p, double x, double y, double vx, double vy, double m)
Definition particules.c:6
Particule TabParticules_get(TabParticules *tab, int i)
Definition particules.c:38
GtkWidget * label_distance
Definition main.c:23
GtkWidget * drawing_area
Definition convex.c:17
Force forces[NB_FORCES]
Definition main.c:21
TabParticules TabP
Definition main.c:20
GtkWidget * label_nb
Definition main.c:22
Une force est un type et des paramètres qui la définissent.
Definition forces.h:11
double x[DIM]
Definition particules.h:9
double f[DIM]
Definition particules.h:11
double v[DIM]
Definition particules.h:10
double m
Definition particules.h:12
Definition points.h:4
double x
Definition points.h:5
Représente un tableau dynamique de particules.
Definition particules.h:23
int main(int argc, char *argv[])
Definition union-find.c:49