b0cc14f81ee488ee4444366b765c23ec40a520bd
[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                        {  Quit,   StartStop,   Fog, NBUT };
76 static const char *but_name[NBUT] = { "Quit", "Start", "Fog"  };
77
78 typedef struct {
79   int       ncars;
80   t_car     *cars;
81   t_input   ir;
82   int       step;
83   gmx_bool      bDriving;       /* Are we driving ?             */
84   gmx_bool      bFog;           /* Is it foggy ?                */
85   t_windata main;
86   t_windata win;
87   t_windata but[NBUT];
88 } t_xhighway;
89
90 int read_input(t_x11 *x11,const char *fn,t_car **cars,t_input *ir)
91 {
92   FILE   *in;
93   int    i,n;
94   char   buf[100],b2[100];
95   t_car  *c;
96   
97   in=ffopen(fn,"r");
98   if (fscanf(in,"%d %d %f %f  %d",
99              &ir->nlane,&ir->metres,&ir->dt,&ir->min_dist,&ir->sleep) != 5)
100     gmx_fatal(FARGS,"Not enough parameters in %s line 1",fn);
101   if (fscanf(in,"%d",&n) != 1)
102     gmx_fatal(FARGS,"Not enough parameters in %s line 2",fn);
103   snew(*cars,n);
104
105   for(i=0; (i<n); i++) {
106     c=&((*cars)[i]);
107     c->id=i;
108     c->lane=0;
109     if (fscanf(in,"%f %f %f %f %f %s %s",&(c->x),&(c->v),&(c->vwanted),
110                &(c->acc),&(c->brake),buf,b2) != 7)
111       gmx_fatal(FARGS,"Not enough parameters in %s line %d",fn,3+i);
112     x11->GetNamedColor(x11,buf,&(c->col));
113     x11->GetNamedColor(x11,b2,&(c->roof));
114   }
115   ffclose(in);
116
117   return n;
118 }
119
120 static float get_dist(int ncars,t_car cars[],int which,gmx_bool bFog,
121                       int dir,int lane,int metres,int *nearest)
122 {
123   int   i,near;
124   float dist,nd;
125
126   if (dir < 0)
127     dist=-metres;
128   else
129     dist=metres;
130   near=-1;
131
132   for(i=0; (i<ncars); i++) 
133     if ((i != which) && (cars[i].oldlane == lane)){
134       nd=cars[i].xold-cars[which].xold;
135       if ((nd < 0) && (dir > 0))
136         nd+=metres;
137       else if ((nd > 0) && (dir < 0))
138         nd-=metres;
139
140       if (!bFog || (fabs(nd) < 50)) {
141         if (dir < 0) {
142           if (nd > dist) {
143             dist=nd;
144             near=i;
145           }
146         }
147         else if (dir > 0) {
148           if (nd < dist) {
149             dist=nd;
150             near=i;
151           }
152         }
153       }
154     }
155   *nearest=near;
156   return fabs(dist);
157 }
158
159 void simulate(t_x11 *x11,t_xhighway *xhw,
160               int ncars,t_car cars[],t_input *ir)
161 {
162   int   i,n_bef,n_bef1,n_beh;
163   float dist,distf,distb;
164
165   for(i=0; (i<ncars); i++) {
166     cars[i].xold=cars[i].x;
167     cars[i].oldlane=cars[i].lane;
168   }
169   for(i=0; (i<ncars); i++) {
170     cars[i].bBrake=FALSE;
171     dist=get_dist(ncars,cars,i,xhw->bFog,
172                   1,cars[i].lane,ir->metres,&n_bef);
173     if (dist < ir->min_dist) {
174       distf=get_dist(ncars,cars,i,xhw->bFog,
175                      1,cars[i].lane+1,ir->metres,&n_bef1);      
176       distb=get_dist(ncars,cars,i,xhw->bFog,
177                      -1,cars[i].lane+1,ir->metres,&n_beh);      
178       if ((cars[i].lane < ir->nlane-1) && (distb >= ir->min_dist) &&
179           (distf >= ir->min_dist))
180         cars[i].lane += 1;
181       else {
182         /* Use brakes */
183         cars[i].v -= cars[i].brake*ir->dt;
184         if (cars[i].v < 0)
185           cars[i].v = 0;
186         if (n_bef != -1) 
187           if ((cars[i].v < cars[n_bef].v) && (dist > ir->min_dist/2))
188             cars[i].v=cars[n_bef].v;
189         cars[i].bBrake=TRUE;
190       }
191     }
192     else if ((cars[i].lane > 0) && (cars[i].v == cars[i].vwanted)) {
193       /* Check if I can go right again */
194       dist=get_dist(ncars,cars,i,xhw->bFog,
195                     1,cars[i].lane-1,ir->metres,&n_bef);      
196       distb=get_dist(ncars,cars,i,xhw->bFog,
197                      -1,cars[i].lane-1,ir->metres,&n_beh);      
198       if ((dist >= ir->min_dist) && (distb >= ir->min_dist))
199         cars[i].lane -= 1;
200     }
201
202     cars[i].x += cars[i].v*ir->dt;
203     if (cars[i].x > ir->metres)
204       cars[i].x -= ir->metres;
205     if (!cars[i].bBrake && (cars[i].v < cars[i].vwanted)) {
206       cars[i].v += cars[i].acc*ir->dt;
207       if (cars[i].v > cars[i].vwanted)
208         cars[i].v = cars[i].vwanted;
209     }
210   }
211   /* Detect Crashes */
212   /* Plot */
213   usleep(xhw->ir.sleep);
214   ExposeWin(x11->disp,xhw->win.self);
215 }
216
217 static void Configure(t_xhighway *xhw)
218 {
219   Window self;
220   int   i,h,w,dh;
221   float dw;
222
223   dh=20;
224   h=xhw->main.height;
225   w=xhw->main.width;
226   dw=((float)(w-2))/NBUT-4;
227   for(i=0; (i<NBUT); i++) {
228     t_windata *wd=&(xhw->but[i]);
229
230     self=wd->self;
231     InitWin(wd,2+i*(dw+4),2,dw,dh,1,but_name[i]);
232     wd->self=self;
233   }
234   self=xhw->win.self;
235   InitWin(&xhw->win,2,dh+6,w-6,h-dh-10,1,xhw->main.text);
236   xhw->win.self=self;
237 }
238
239 static void draw_car(Display *disp,Window wd,GC gc,
240                      t_car *car,int w0,int h0)
241 {
242   const int w=30;
243   const int h=14;
244   const int wr=10;
245   const int hr=8;
246   int   j,w1,h1;
247   int   jmax,hmax;
248
249   w1=w0-w / 2;
250   h1=h0-h / 2;
251
252   /* Carosserie */
253   XSetForeground(disp,gc,car->col);
254   XFillRectangle(disp,wd,gc,w1,h1,w,h);
255
256   /* Dak */
257   XSetForeground(disp,gc,car->roof);
258   XFillRectangle(disp,wd,gc,w0-wr/2,h0-hr/2,wr,hr);
259
260   /* Achterlicht */
261   if (car->bBrake) {
262     XSetForeground(disp,gc,YELLOW);
263     jmax=5;
264     hmax=5;
265   }
266   else {
267     XSetForeground(disp,gc,LIGHTRED);
268     jmax=3;
269     hmax=3;
270   }
271   for(j=1; (j<jmax); j++) {
272     int w11=w1-1-j;
273     int h11=h1-1;
274     XDrawLine(disp,wd,gc,w11,h11,       w11,h11+hmax);
275     XDrawLine(disp,wd,gc,w11,h11+h-hmax,w11,h11+h);
276   }
277
278   /* Voorlicht */
279   XSetForeground(disp,gc,WHITE);
280   for(j=1; (j<3); j++) {
281     int w11=w1+w+j;
282     int h11=h1-1;
283     XDrawLine(disp,wd,gc,w11,h11,    w11,h11+3);
284     XDrawLine(disp,wd,gc,w11,h11+h-3,w11,h11+h);
285   }
286 }
287
288 static gmx_bool xhwCallBack(struct t_x11 *x11,XEvent *event, Window wd, void *data)
289 {
290   t_xhighway *xhw;
291   t_windata  *win;
292   float      sx;
293   int        i;
294   static     int nyy=0;
295   static     int *yy;
296
297   xhw = (t_xhighway *)data;
298   win = &(xhw->win); 
299
300   if (nyy == 0) {
301     nyy=2*xhw->ir.nlane+1;
302     snew(yy,nyy);
303   }
304   for(i=0; (i<nyy); i++) 
305     yy[i]=((float) i*win->height)/(nyy-1);
306
307   switch (event->type) {
308   case Expose: {
309     if (wd == win->self) {
310       sx=(float)win->width  / xhw->ir.metres;
311       
312       XClearWindow(x11->disp,win->self);
313       XSetForeground(x11->disp,x11->gc,WHITE);
314
315       for(i=2; (i<nyy-1); i+=2)
316         XDrawLine(x11->disp,win->self,x11->gc,0,yy[i],win->width-1,yy[i]);
317       
318       for(i=0; (i<xhw->ncars); i++) {
319         t_car *car=&(xhw->cars[i]);
320         int   w1=car->x*sx;
321         int   h1=yy[1+2*(xhw->ir.nlane-1-car->lane)];
322
323         draw_car(x11->disp,win->self,x11->gc,car,w1,h1);
324       }
325       if (xhw->bDriving)
326         simulate(x11,xhw,xhw->ncars,xhw->cars,&xhw->ir);
327     }
328     break;
329   }
330   case ConfigureNotify:
331     if (wd == xhw->main.self) {
332       xhw->main.width=event->xconfigure.width;
333       xhw->main.height=event->xconfigure.height;
334       Configure(xhw);
335       for(i=0; (i<NBUT); i++)
336         XMoveResizeWindow(x11->disp,xhw->but[i].self,
337                           xhw->but[i].x,xhw->but[i].y,
338                           xhw->but[i].width,xhw->but[i].height);
339       XMoveResizeWindow(x11->disp,win->self,
340                         win->x,win->y,win->width,win->height);
341     }
342     else if (wd == win->self) {
343       win->width=event->xconfigure.width;
344       win->height=event->xconfigure.height;
345     }
346     break;
347   case ButtonPress:
348     return TRUE;
349   default:
350     break;
351   }
352   return FALSE;
353 }
354
355 static gmx_bool butCallBack(struct t_x11 *x11,XEvent *event, Window wd, void *data)
356 {
357   XSetWindowAttributes attr;
358   t_xhighway *xhw;
359   t_windata  *win;
360   const char *label;
361   int        i;
362
363   xhw = (t_xhighway *)data;
364   for(i=0; (i<NBUT); i++) {
365     if (xhw->but[i].self == wd)
366       break;
367   }
368   if (i == NBUT) {
369     fprintf(stderr,"Incorrect window: %x in butcallback\n",(unsigned)wd);
370     return FALSE;
371   }
372   win=&(xhw->but[i]);
373
374   switch (event->type) {
375   case Expose: 
376     XClearWindow(x11->disp,win->self);
377     switch (i) {
378     case StartStop:
379       label=Driving[xhw->bDriving];
380       break;
381     case Fog:
382       label=Fogs[xhw->bFog];
383       break;
384     default:
385       label=win->text;
386     }
387     XSetForeground(x11->disp,x11->gc,WHITE);
388     TextInWin(x11,win,label,eXCenter,eYCenter);
389     break;
390   
391   case ConfigureNotify:
392     win->width=event->xconfigure.width;
393     win->height=event->xconfigure.height;
394     break;
395   case ButtonPress:
396     switch (i) {
397     case Quit:
398       return TRUE;
399     case StartStop:
400       xhw->bDriving=1-xhw->bDriving;
401       ExposeWin(x11->disp,win->self);
402       if (xhw->bDriving) 
403         ExposeWin(x11->disp,xhw->win.self);
404       break;
405     case Fog:
406       xhw->bFog=1-xhw->bFog;
407       if (xhw->bFog) 
408         attr.background_pixel=DARKGREY;
409       else
410         attr.background_pixel=BLACK;
411       XChangeWindowAttributes(x11->disp,xhw->win.self,CWBackPixel,&attr);
412       /*ExposeWin(x11->disp,win->self);*/
413       break;
414     default:
415       break;
416     }
417     break;
418   default:
419     break;
420   }
421   return FALSE;
422 }
423
424 t_xhighway *GetXHW(t_x11 *x11,const char *infile)
425 {
426   t_xhighway *xhw;
427   int        i,h,dh,w;
428   char       progname[STRLEN];
429
430   snew(xhw,1);
431   xhw->ncars=read_input(x11,infile,&(xhw->cars),&xhw->ir);
432   
433   h=xhw->ir.nlane*40;
434   dh=20;
435   w=752;
436   strncpy(progname,Program(),STRLEN-1);
437   InitWin(&xhw->main,0,0,w,h+dh+7,1,progname);
438   xhw->main.self=XCreateSimpleWindow(x11->disp,x11->root,
439                                      xhw->main.x,xhw->main.y,
440                                      xhw->main.width,xhw->main.height,
441                                      xhw->main.bwidth,WHITE,BLACK);
442   x11->RegisterCallback(x11,xhw->main.self,0,xhwCallBack,xhw);
443   x11->SetInputMask(x11,xhw->main.self,ButtonPressMask | ExposureMask |
444                     StructureNotifyMask);
445
446   Configure(xhw);
447
448   for(i=0; (i<NBUT); i++) {
449     t_windata *wd=&(xhw->but[i]);
450
451     wd->self=XCreateSimpleWindow(x11->disp,xhw->main.self,
452                                  wd->x,wd->y,
453                                  wd->width,wd->height,
454                                  wd->bwidth,WHITE,BLACK);
455     x11->RegisterCallback(x11,wd->self,xhw->main.self,
456                           butCallBack,xhw);
457     x11->SetInputMask(x11,wd->self,ButtonPressMask | ExposureMask |
458                       StructureNotifyMask);
459     
460   }
461   xhw->win.self=XCreateSimpleWindow(x11->disp,xhw->main.self,
462                                     xhw->win.x,xhw->win.y,
463                                     xhw->win.width,xhw->win.height,
464                                     xhw->win.bwidth,WHITE,BLACK);
465   x11->RegisterCallback(x11,xhw->win.self,0,xhwCallBack,xhw);
466   x11->SetInputMask(x11,xhw->win.self,ButtonPressMask | ExposureMask |
467                     StructureNotifyMask);
468
469   return xhw;
470 }
471
472 int main(int argc,char *argv[])
473 {
474   const char *desc[] = {
475     "[TT]highway[tt] is the GROMCAS highway simulator. It is an X-windows",
476     "gadget that shows a (periodic) Autobahn with a user defined",
477     "number of cars. Fog can be turned on or off to increase the",
478     "number of crashes. Nice for a background CPU-eater. A sample",
479     "input file is in [TT]$GMXDATA/top/highway.dat[tt]"
480   };
481   output_env_t oenv;
482   t_x11      *x11;
483   t_xhighway *xhw;
484   t_filenm fnm[] = {
485     { efDAT, "-f", "highway", ffREAD }
486   };
487 #define NFILE asize(fnm)
488
489   CopyRight(stderr,argv[0]);
490   parse_common_args(&argc,argv,0,NFILE,fnm,
491                     0,NULL,asize(desc),desc,0,NULL,&oenv);
492   
493   if ((x11=GetX11(&argc,argv))==NULL) {
494     fprintf(stderr,"Can't connect to X Server.\n"
495             "Check your DISPLAY environment variable\n");
496     exit(1);
497   }
498   xhw=GetXHW(x11,opt2fn("-f",NFILE,fnm));
499   
500   XMapWindow(x11->disp,xhw->main.self);
501   XMapSubwindows(x11->disp,xhw->main.self);
502   x11->MainLoop(x11);
503   x11->CleanUp(x11);
504
505   thanx(stderr);
506   
507   return 0;
508 }