Code beautification with uncrustify
[alexxy/gromacs.git] / src / ngmx / g_highway.c
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  *                        VERSION 3.2.0
10  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12  * Copyright (c) 2001-2004, The GROMACS development team,
13  * check out http://www.gromacs.org for more information.
14
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * as published by the Free Software Foundation; either version 2
18  * of the License, or (at your option) any later version.
19  *
20  * If you want to redistribute modifications, please consider that
21  * scientific software is very special. Version control is crucial -
22  * bugs must be traceable. We will be happy to consider code for
23  * inclusion in the official distribution, but derived work must not
24  * be called official GROMACS. Details are found in the README & COPYING
25  * files - if they are missing, get the official version at www.gromacs.org.
26  *
27  * To help us fund GROMACS development, we humbly ask that you cite
28  * the papers on the package - you can find them in the top README file.
29  *
30  * For more info, check our website at http://www.gromacs.org
31  *
32  * And Hey:
33  * Gyas ROwers Mature At Cryogenic Speed
34  */
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include <stdio.h>
40 #include <string.h>
41 #include <math.h>
42 #include "futil.h"
43 #include "macros.h"
44 #include "smalloc.h"
45 #include "xutil.h"
46 #include "copyrite.h"
47 #include "statutil.h"
48 #include "gmx_fatal.h"
49
50 /* Units are meter and second   */
51
52 typedef struct {
53     int           id;            /* Identification      */
54     float         x, xold;
55     float         v;             /* Position and velocity       */
56     float         vwanted;       /* Wants to drive at this speed        */
57     float         acc;           /* Acceleration                        */
58     float         brake;         /* Break                       */
59     int           lane, oldlane; /* Currently in lane           */
60     gmx_bool      bBrake;        /* Currently on the brakes     */
61     unsigned long col;           /* Colour                      */
62     unsigned long roof;          /* Roof Colour                 */
63 } t_car;
64
65 typedef struct {
66     int   nlane;    /* Number of lanes on highway       */
67     int   metres;   /* Road length                      */
68     float dt;       /* Time step                        */
69     float min_dist; /* Min distance cars can come       */
70     int   sleep;    /* How long to sleep in between updates */
71 } t_input;
72
73 static const char *Driving[]      = { "Start", "Stop"   };
74 static const char *Fogs[]         = { "Fog",  "No Fog" };
75 enum buttons                        {
76     Quit,   StartStop,   Fog, NBUT
77 };
78 static const char *but_name[NBUT] = { "Quit", "Start", "Fog"  };
79
80 typedef struct {
81     int           ncars;
82     t_car        *cars;
83     t_input       ir;
84     int           step;
85     gmx_bool      bDriving; /* Are we driving ?         */
86     gmx_bool      bFog;     /* Is it foggy ?            */
87     t_windata     main;
88     t_windata     win;
89     t_windata     but[NBUT];
90 } t_xhighway;
91
92 int read_input(t_x11 *x11, const char *fn, t_car **cars, t_input *ir)
93 {
94     FILE   *in;
95     int     i, n;
96     char    buf[100], b2[100];
97     t_car  *c;
98
99     in = ffopen(fn, "r");
100     if (fscanf(in, "%d %d %f %f  %d",
101                &ir->nlane, &ir->metres, &ir->dt, &ir->min_dist, &ir->sleep) != 5)
102     {
103         gmx_fatal(FARGS, "Not enough parameters in %s line 1", fn);
104     }
105     if (fscanf(in, "%d", &n) != 1)
106     {
107         gmx_fatal(FARGS, "Not enough parameters in %s line 2", fn);
108     }
109     snew(*cars, n);
110
111     for (i = 0; (i < n); i++)
112     {
113         c       = &((*cars)[i]);
114         c->id   = i;
115         c->lane = 0;
116         if (fscanf(in, "%f %f %f %f %f %s %s", &(c->x), &(c->v), &(c->vwanted),
117                    &(c->acc), &(c->brake), buf, b2) != 7)
118         {
119             gmx_fatal(FARGS, "Not enough parameters in %s line %d", fn, 3+i);
120         }
121         x11->GetNamedColor(x11, buf, &(c->col));
122         x11->GetNamedColor(x11, b2, &(c->roof));
123     }
124     ffclose(in);
125
126     return n;
127 }
128
129 static float get_dist(int ncars, t_car cars[], int which, gmx_bool bFog,
130                       int dir, int lane, int metres, int *nearest)
131 {
132     int   i, near;
133     float dist, nd;
134
135     if (dir < 0)
136     {
137         dist = -metres;
138     }
139     else
140     {
141         dist = metres;
142     }
143     near = -1;
144
145     for (i = 0; (i < ncars); i++)
146     {
147         if ((i != which) && (cars[i].oldlane == lane))
148         {
149             nd = cars[i].xold-cars[which].xold;
150             if ((nd < 0) && (dir > 0))
151             {
152                 nd += metres;
153             }
154             else if ((nd > 0) && (dir < 0))
155             {
156                 nd -= metres;
157             }
158
159             if (!bFog || (fabs(nd) < 50))
160             {
161                 if (dir < 0)
162                 {
163                     if (nd > dist)
164                     {
165                         dist = nd;
166                         near = i;
167                     }
168                 }
169                 else if (dir > 0)
170                 {
171                     if (nd < dist)
172                     {
173                         dist = nd;
174                         near = i;
175                     }
176                 }
177             }
178         }
179     }
180     *nearest = near;
181     return fabs(dist);
182 }
183
184 void simulate(t_x11 *x11, t_xhighway *xhw,
185               int ncars, t_car cars[], t_input *ir)
186 {
187     int   i, n_bef, n_bef1, n_beh;
188     float dist, distf, distb;
189
190     for (i = 0; (i < ncars); i++)
191     {
192         cars[i].xold    = cars[i].x;
193         cars[i].oldlane = cars[i].lane;
194     }
195     for (i = 0; (i < ncars); i++)
196     {
197         cars[i].bBrake = FALSE;
198         dist           = get_dist(ncars, cars, i, xhw->bFog,
199                                   1, cars[i].lane, ir->metres, &n_bef);
200         if (dist < ir->min_dist)
201         {
202             distf = get_dist(ncars, cars, i, xhw->bFog,
203                              1, cars[i].lane+1, ir->metres, &n_bef1);
204             distb = get_dist(ncars, cars, i, xhw->bFog,
205                              -1, cars[i].lane+1, ir->metres, &n_beh);
206             if ((cars[i].lane < ir->nlane-1) && (distb >= ir->min_dist) &&
207                 (distf >= ir->min_dist))
208             {
209                 cars[i].lane += 1;
210             }
211             else
212             {
213                 /* Use brakes */
214                 cars[i].v -= cars[i].brake*ir->dt;
215                 if (cars[i].v < 0)
216                 {
217                     cars[i].v = 0;
218                 }
219                 if (n_bef != -1)
220                 {
221                     if ((cars[i].v < cars[n_bef].v) && (dist > ir->min_dist/2))
222                     {
223                         cars[i].v = cars[n_bef].v;
224                     }
225                 }
226                 cars[i].bBrake = TRUE;
227             }
228         }
229         else if ((cars[i].lane > 0) && (cars[i].v == cars[i].vwanted))
230         {
231             /* Check if I can go right again */
232             dist = get_dist(ncars, cars, i, xhw->bFog,
233                             1, cars[i].lane-1, ir->metres, &n_bef);
234             distb = get_dist(ncars, cars, i, xhw->bFog,
235                              -1, cars[i].lane-1, ir->metres, &n_beh);
236             if ((dist >= ir->min_dist) && (distb >= ir->min_dist))
237             {
238                 cars[i].lane -= 1;
239             }
240         }
241
242         cars[i].x += cars[i].v*ir->dt;
243         if (cars[i].x > ir->metres)
244         {
245             cars[i].x -= ir->metres;
246         }
247         if (!cars[i].bBrake && (cars[i].v < cars[i].vwanted))
248         {
249             cars[i].v += cars[i].acc*ir->dt;
250             if (cars[i].v > cars[i].vwanted)
251             {
252                 cars[i].v = cars[i].vwanted;
253             }
254         }
255     }
256     /* Detect Crashes */
257     /* Plot */
258     usleep(xhw->ir.sleep);
259     ExposeWin(x11->disp, xhw->win.self);
260 }
261
262 static void Configure(t_xhighway *xhw)
263 {
264     Window self;
265     int    i, h, w, dh;
266     float  dw;
267
268     dh = 20;
269     h  = xhw->main.height;
270     w  = xhw->main.width;
271     dw = ((float)(w-2))/NBUT-4;
272     for (i = 0; (i < NBUT); i++)
273     {
274         t_windata *wd = &(xhw->but[i]);
275
276         self = wd->self;
277         InitWin(wd, 2+i*(dw+4), 2, dw, dh, 1, but_name[i]);
278         wd->self = self;
279     }
280     self = xhw->win.self;
281     InitWin(&xhw->win, 2, dh+6, w-6, h-dh-10, 1, xhw->main.text);
282     xhw->win.self = self;
283 }
284
285 static void draw_car(Display *disp, Window wd, GC gc,
286                      t_car *car, int w0, int h0)
287 {
288     const int w  = 30;
289     const int h  = 14;
290     const int wr = 10;
291     const int hr = 8;
292     int       j, w1, h1;
293     int       jmax, hmax;
294
295     w1 = w0-w / 2;
296     h1 = h0-h / 2;
297
298     /* Carosserie */
299     XSetForeground(disp, gc, car->col);
300     XFillRectangle(disp, wd, gc, w1, h1, w, h);
301
302     /* Dak */
303     XSetForeground(disp, gc, car->roof);
304     XFillRectangle(disp, wd, gc, w0-wr/2, h0-hr/2, wr, hr);
305
306     /* Achterlicht */
307     if (car->bBrake)
308     {
309         XSetForeground(disp, gc, YELLOW);
310         jmax = 5;
311         hmax = 5;
312     }
313     else
314     {
315         XSetForeground(disp, gc, LIGHTRED);
316         jmax = 3;
317         hmax = 3;
318     }
319     for (j = 1; (j < jmax); j++)
320     {
321         int w11 = w1-1-j;
322         int h11 = h1-1;
323         XDrawLine(disp, wd, gc, w11, h11,       w11, h11+hmax);
324         XDrawLine(disp, wd, gc, w11, h11+h-hmax, w11, h11+h);
325     }
326
327     /* Voorlicht */
328     XSetForeground(disp, gc, WHITE);
329     for (j = 1; (j < 3); j++)
330     {
331         int w11 = w1+w+j;
332         int h11 = h1-1;
333         XDrawLine(disp, wd, gc, w11, h11,    w11, h11+3);
334         XDrawLine(disp, wd, gc, w11, h11+h-3, w11, h11+h);
335     }
336 }
337
338 static gmx_bool xhwCallBack(struct t_x11 *x11, XEvent *event, Window wd, void *data)
339 {
340     t_xhighway     *xhw;
341     t_windata      *win;
342     float           sx;
343     int             i;
344     static     int  nyy = 0;
345     static     int *yy;
346
347     xhw = (t_xhighway *)data;
348     win = &(xhw->win);
349
350     if (nyy == 0)
351     {
352         nyy = 2*xhw->ir.nlane+1;
353         snew(yy, nyy);
354     }
355     for (i = 0; (i < nyy); i++)
356     {
357         yy[i] = ((float) i*win->height)/(nyy-1);
358     }
359
360     switch (event->type)
361     {
362         case Expose:
363         {
364             if (wd == win->self)
365             {
366                 sx = (float)win->width  / xhw->ir.metres;
367
368                 XClearWindow(x11->disp, win->self);
369                 XSetForeground(x11->disp, x11->gc, WHITE);
370
371                 for (i = 2; (i < nyy-1); i += 2)
372                 {
373                     XDrawLine(x11->disp, win->self, x11->gc, 0, yy[i], win->width-1, yy[i]);
374                 }
375
376                 for (i = 0; (i < xhw->ncars); i++)
377                 {
378                     t_car *car = &(xhw->cars[i]);
379                     int    w1  = car->x*sx;
380                     int    h1  = yy[1+2*(xhw->ir.nlane-1-car->lane)];
381
382                     draw_car(x11->disp, win->self, x11->gc, car, w1, h1);
383                 }
384                 if (xhw->bDriving)
385                 {
386                     simulate(x11, xhw, xhw->ncars, xhw->cars, &xhw->ir);
387                 }
388             }
389             break;
390         }
391         case ConfigureNotify:
392             if (wd == xhw->main.self)
393             {
394                 xhw->main.width  = event->xconfigure.width;
395                 xhw->main.height = event->xconfigure.height;
396                 Configure(xhw);
397                 for (i = 0; (i < NBUT); i++)
398                 {
399                     XMoveResizeWindow(x11->disp, xhw->but[i].self,
400                                       xhw->but[i].x, xhw->but[i].y,
401                                       xhw->but[i].width, xhw->but[i].height);
402                 }
403                 XMoveResizeWindow(x11->disp, win->self,
404                                   win->x, win->y, win->width, win->height);
405             }
406             else if (wd == win->self)
407             {
408                 win->width  = event->xconfigure.width;
409                 win->height = event->xconfigure.height;
410             }
411             break;
412         case ButtonPress:
413             return TRUE;
414         default:
415             break;
416     }
417     return FALSE;
418 }
419
420 static gmx_bool butCallBack(struct t_x11 *x11, XEvent *event, Window wd, void *data)
421 {
422     XSetWindowAttributes attr;
423     t_xhighway          *xhw;
424     t_windata           *win;
425     const char          *label;
426     int                  i;
427
428     xhw = (t_xhighway *)data;
429     for (i = 0; (i < NBUT); i++)
430     {
431         if (xhw->but[i].self == wd)
432         {
433             break;
434         }
435     }
436     if (i == NBUT)
437     {
438         fprintf(stderr, "Incorrect window: %x in butcallback\n", (unsigned)wd);
439         return FALSE;
440     }
441     win = &(xhw->but[i]);
442
443     switch (event->type)
444     {
445         case Expose:
446             XClearWindow(x11->disp, win->self);
447             switch (i)
448             {
449                 case StartStop:
450                     label = Driving[xhw->bDriving];
451                     break;
452                 case Fog:
453                     label = Fogs[xhw->bFog];
454                     break;
455                 default:
456                     label = win->text;
457             }
458             XSetForeground(x11->disp, x11->gc, WHITE);
459             TextInWin(x11, win, label, eXCenter, eYCenter);
460             break;
461
462         case ConfigureNotify:
463             win->width  = event->xconfigure.width;
464             win->height = event->xconfigure.height;
465             break;
466         case ButtonPress:
467             switch (i)
468             {
469                 case Quit:
470                     return TRUE;
471                 case StartStop:
472                     xhw->bDriving = 1-xhw->bDriving;
473                     ExposeWin(x11->disp, win->self);
474                     if (xhw->bDriving)
475                     {
476                         ExposeWin(x11->disp, xhw->win.self);
477                     }
478                     break;
479                 case Fog:
480                     xhw->bFog = 1-xhw->bFog;
481                     if (xhw->bFog)
482                     {
483                         attr.background_pixel = DARKGREY;
484                     }
485                     else
486                     {
487                         attr.background_pixel = BLACK;
488                     }
489                     XChangeWindowAttributes(x11->disp, xhw->win.self, CWBackPixel, &attr);
490                     /*ExposeWin(x11->disp,win->self);*/
491                     break;
492                 default:
493                     break;
494             }
495             break;
496         default:
497             break;
498     }
499     return FALSE;
500 }
501
502 t_xhighway *GetXHW(t_x11 *x11, const char *infile)
503 {
504     t_xhighway *xhw;
505     int         i, h, dh, w;
506     char        progname[STRLEN];
507
508     snew(xhw, 1);
509     xhw->ncars = read_input(x11, infile, &(xhw->cars), &xhw->ir);
510
511     h  = xhw->ir.nlane*40;
512     dh = 20;
513     w  = 752;
514     strncpy(progname, Program(), STRLEN-1);
515     InitWin(&xhw->main, 0, 0, w, h+dh+7, 1, progname);
516     xhw->main.self = XCreateSimpleWindow(x11->disp, x11->root,
517                                          xhw->main.x, xhw->main.y,
518                                          xhw->main.width, xhw->main.height,
519                                          xhw->main.bwidth, WHITE, BLACK);
520     x11->RegisterCallback(x11, xhw->main.self, 0, xhwCallBack, xhw);
521     x11->SetInputMask(x11, xhw->main.self, ButtonPressMask | ExposureMask |
522                       StructureNotifyMask);
523
524     Configure(xhw);
525
526     for (i = 0; (i < NBUT); i++)
527     {
528         t_windata *wd = &(xhw->but[i]);
529
530         wd->self = XCreateSimpleWindow(x11->disp, xhw->main.self,
531                                        wd->x, wd->y,
532                                        wd->width, wd->height,
533                                        wd->bwidth, WHITE, BLACK);
534         x11->RegisterCallback(x11, wd->self, xhw->main.self,
535                               butCallBack, xhw);
536         x11->SetInputMask(x11, wd->self, ButtonPressMask | ExposureMask |
537                           StructureNotifyMask);
538
539     }
540     xhw->win.self = XCreateSimpleWindow(x11->disp, xhw->main.self,
541                                         xhw->win.x, xhw->win.y,
542                                         xhw->win.width, xhw->win.height,
543                                         xhw->win.bwidth, WHITE, BLACK);
544     x11->RegisterCallback(x11, xhw->win.self, 0, xhwCallBack, xhw);
545     x11->SetInputMask(x11, xhw->win.self, ButtonPressMask | ExposureMask |
546                       StructureNotifyMask);
547
548     return xhw;
549 }
550
551 int main(int argc, char *argv[])
552 {
553     const char  *desc[] = {
554         "[TT]highway[tt] is the GROMCAS highway simulator. It is an X-windows",
555         "gadget that shows a (periodic) Autobahn with a user defined",
556         "number of cars. Fog can be turned on or off to increase the",
557         "number of crashes. Nice for a background CPU-eater. A sample",
558         "input file is in [TT]$GMXDATA/top/highway.dat[tt]"
559     };
560     output_env_t oenv;
561     t_x11       *x11;
562     t_xhighway  *xhw;
563     t_filenm     fnm[] = {
564         { efDAT, "-f", "highway", ffREAD }
565     };
566 #define NFILE asize(fnm)
567
568     CopyRight(stderr, argv[0]);
569     parse_common_args(&argc, argv, 0, NFILE, fnm,
570                       0, NULL, asize(desc), desc, 0, NULL, &oenv);
571
572     if ((x11 = GetX11(&argc, argv)) == NULL)
573     {
574         fprintf(stderr, "Can't connect to X Server.\n"
575                 "Check your DISPLAY environment variable\n");
576         exit(1);
577     }
578     xhw = GetXHW(x11, opt2fn("-f", NFILE, fnm));
579
580     XMapWindow(x11->disp, xhw->main.self);
581     XMapSubwindows(x11->disp, xhw->main.self);
582     x11->MainLoop(x11);
583     x11->CleanUp(x11);
584
585     thanx(stderr);
586
587     return 0;
588 }