0feffee32693d8cef8421f2871f22c84de184b0e
[alexxy/gromacs.git] / src / ngmx / highway.c
1 /*
2  * $Id$
3  * 
4  *       This source code is part of
5  * 
6  *        G   R   O   M   A   C   S
7  * 
8  * GROningen MAchine for Chemical Simulations
9  * 
10  *               VERSION 2.0
11  * 
12  * Copyright (c) 1991-1999
13  * BIOSON Research Institute, Dept. of Biophysical Chemistry
14  * University of Groningen, The Netherlands
15  * 
16  * Please refer to:
17  * GROMACS: A message-passing parallel molecular dynamics implementation
18  * H.J.C. Berendsen, D. van der Spoel and R. van Drunen
19  * Comp. Phys. Comm. 91, 43-56 (1995)
20  * 
21  * Also check out our WWW page:
22  * http://md.chem.rug.nl/~gmx
23  * or e-mail to:
24  * gromacs@chem.rug.nl
25  * 
26  * And Hey:
27  * Great Red Oystrich Makes All Chemists Sane
28  */
29 static char *SRCID_highway_c = "$Id$";
30
31 #include <stdio.h>
32 #include <math.h>
33 #include "futil.h"
34 #include "macros.h"
35 #include "smalloc.h"
36 #include "xutil.h"
37 #include "copyrite.h"
38 #include "statutil.h"
39
40 /* Units are meter and second   */
41
42 typedef struct {
43   int   id;             /* Identification               */
44   int   x,xold;
45   float v;              /* Position and velocity        */
46   float vwanted;        /* Wants to drive at this speed */
47   float acc;            /* Acceleration                 */
48   float brake;          /* Break                        */
49   int   lane,oldlane;   /* Currently in lane            */
50   bool  bBrake;         /* Currently on the brakes      */
51   unsigned long col;            /* Colour                       */
52   unsigned long roof;           /* Roof Colour                  */
53 } t_car;
54
55 typedef struct {
56   int   nlane;          /* Number of lanes on highway   */
57   int   metres;         /* Road length                  */
58   float dt;             /* Time step                    */
59   float min_dist;       /* Min distance cars can come   */
60 } t_input;
61
62 static char *Driving[]      = { "Start","Stop"   };
63 static char *Fogs[]         = { "Fog",  "No Fog" };
64 enum buttons                  {  Quit,   StartStop,   Fog, NBUT };
65 static char *but_name[NBUT] = { "Quit", "Start", "Fog"  };
66
67 typedef struct {
68   int       ncars;
69   t_car     *cars;
70   t_input   *ir;
71   int       step;
72   bool      bDriving;   /* Are we driving ?             */
73   bool      bFog;               /* Is it foggy ?                */
74   t_windata main;
75   t_windata win;
76   t_windata but[NBUT];
77 } t_xhighway;
78
79 int read_cars(t_x11 *x11,char *fn,t_car **cars)
80 {
81   FILE   *in;
82   int    i,n;
83   char   buf[100],b2[100];
84   t_car  *c;
85
86   in=ffopen(fn,"r");
87   fscanf(in,"%d",&n);
88   snew(*cars,n);
89
90   for(i=0; (i<n); i++) {
91     c=&((*cars)[i]);
92     c->id=i;
93     c->lane=0;
94     fscanf(in,"%d %f %f %f %f %s %s",
95            &(c->x),&(c->v),&(c->vwanted),&(c->acc),&(c->brake),buf,b2);
96     x11->GetNamedColor(x11,buf,&(c->col));
97     x11->GetNamedColor(x11,b2,&(c->roof));
98   }
99   fclose(in);
100
101   return n;
102 }
103
104 t_input *read_input(char *fn)
105 {
106   FILE    *in;
107   t_input *ir;
108
109   snew(ir,1);
110   in=ffopen(fn,"r");
111
112   fscanf(in,"%d %d %f %f",&ir->nlane,&ir->metres,&ir->dt,&ir->min_dist);
113
114   fclose(in);
115   return ir;
116 }
117
118 static float get_dist(int ncars,t_car cars[],int which,bool bFog,
119                       int dir,int lane,int metres,int *nearest)
120 {
121   int   i,near;
122   float dist,nd;
123
124   if (dir < 0)
125     dist=-metres;
126   else
127     dist=metres;
128   near=-1;
129
130   for(i=0; (i<ncars); i++) 
131     if ((i != which) && (cars[i].oldlane == lane)){
132       nd=cars[i].xold-cars[which].xold;
133       if ((nd < 0) && (dir > 0))
134         nd+=metres;
135       else if ((nd > 0) && (dir < 0))
136         nd-=metres;
137
138       if (!bFog || (fabs(nd) < 50)) {
139         if (dir < 0) {
140           if (nd > dist) {
141             dist=nd;
142             near=i;
143           }
144         }
145         else if (dir > 0) {
146           if (nd < dist) {
147             dist=nd;
148             near=i;
149           }
150         }
151       }
152     }
153   *nearest=near;
154   return fabs(dist);
155 }
156
157 void simulate(t_x11 *x11,t_xhighway *xhw,
158               int ncars,t_car cars[],t_input *ir)
159 {
160   int   i,n_bef,n_bef1,n_beh;
161   float dist,distf,distb;
162
163   for(i=0; (i<ncars); i++) {
164     cars[i].xold=cars[i].x;
165     cars[i].oldlane=cars[i].lane;
166   }
167   for(i=0; (i<ncars); i++) {
168     cars[i].bBrake=FALSE;
169     dist=get_dist(ncars,cars,i,xhw->bFog,
170                   1,cars[i].lane,ir->metres,&n_bef);
171     if (dist < ir->min_dist) {
172       distf=get_dist(ncars,cars,i,xhw->bFog,
173                      1,cars[i].lane+1,ir->metres,&n_bef1);      
174       distb=get_dist(ncars,cars,i,xhw->bFog,
175                      -1,cars[i].lane+1,ir->metres,&n_beh);      
176       if ((cars[i].lane < ir->nlane-1) && (distb >= ir->min_dist) &&
177           (distf >= ir->min_dist))
178         cars[i].lane += 1;
179       else {
180         /* Use brakes */
181         cars[i].v -= cars[i].brake*ir->dt;
182         if (cars[i].v < 0)
183           cars[i].v = 0;
184         if (n_bef != -1) 
185           if ((cars[i].v < cars[n_bef].v) && (dist > ir->min_dist/2))
186             cars[i].v=cars[n_bef].v;
187         cars[i].bBrake=TRUE;
188       }
189     }
190     else if ((cars[i].lane > 0) && (cars[i].v == cars[i].vwanted)) {
191       /* Check if I can go right again */
192       dist=get_dist(ncars,cars,i,xhw->bFog,
193                     1,cars[i].lane-1,ir->metres,&n_bef);      
194       distb=get_dist(ncars,cars,i,xhw->bFog,
195                      -1,cars[i].lane-1,ir->metres,&n_beh);      
196       if ((dist >= ir->min_dist) && (distb >= ir->min_dist))
197         cars[i].lane -= 1;
198     }
199
200     cars[i].x += cars[i].v*ir->dt;
201     if (cars[i].x > ir->metres)
202       cars[i].x -= ir->metres;
203     if (!cars[i].bBrake && (cars[i].v < cars[i].vwanted)) {
204       cars[i].v += cars[i].acc*ir->dt;
205       if (cars[i].v > cars[i].vwanted)
206         cars[i].v = cars[i].vwanted;
207     }
208   }
209   /* Detect Crashes */
210   /* Plot */
211   ExposeWin(x11->disp,xhw->win.self);
212 }
213
214 static void Configure(t_xhighway *xhw)
215 {
216   Window self;
217   int   i,h,w,dh;
218   float dw;
219
220   dh=20;
221   h=xhw->main.height;
222   w=xhw->main.width;
223   dw=((float)(w-2))/NBUT-4;
224   for(i=0; (i<NBUT); i++) {
225     t_windata *wd=&(xhw->but[i]);
226
227     self=wd->self;
228     InitWin(wd,2+i*(dw+4),2,dw,dh,1,but_name[i]);
229     wd->self=self;
230   }
231   self=xhw->win.self;
232   InitWin(&xhw->win,2,dh+6,w-6,h-dh-10,1,xhw->main.text);
233   xhw->win.self=self;
234 }
235
236 static void draw_car(Display *disp,Window wd,GC gc,
237                      t_car *car,int w0,int h0)
238 {
239   const int w=30;
240   const int h=14;
241   const int wr=10;
242   const int hr=8;
243   int   j,w1,h1;
244   int   jmax,hmax;
245
246   w1=w0-w / 2;
247   h1=h0-h / 2;
248
249   /* Carosserie */
250   XSetForeground(disp,gc,car->col);
251   XFillRectangle(disp,wd,gc,w1,h1,w,h);
252
253   /* Dak */
254   XSetForeground(disp,gc,car->roof);
255   XFillRectangle(disp,wd,gc,w0-wr/2,h0-hr/2,wr,hr);
256
257   /* Achterlicht */
258   if (car->bBrake) {
259     XSetForeground(disp,gc,YELLOW);
260     jmax=5;
261     hmax=5;
262   }
263   else {
264     XSetForeground(disp,gc,LIGHTRED);
265     jmax=3;
266     hmax=3;
267   }
268   for(j=1; (j<jmax); j++) {
269     int w11=w1-1-j;
270     int h11=h1-1;
271     XDrawLine(disp,wd,gc,w11,h11,       w11,h11+hmax);
272     XDrawLine(disp,wd,gc,w11,h11+h-hmax,w11,h11+h);
273   }
274
275   /* Voorlicht */
276   XSetForeground(disp,gc,WHITE);
277   for(j=1; (j<3); j++) {
278     int w11=w1+w+j;
279     int h11=h1-1;
280     XDrawLine(disp,wd,gc,w11,h11,    w11,h11+3);
281     XDrawLine(disp,wd,gc,w11,h11+h-3,w11,h11+h);
282   }
283 }
284
285 static bool xhwCallBack(struct t_x11 *x11,XEvent *event, Window wd, void *data)
286 {
287   t_xhighway *xhw;
288   t_windata  *win;
289   float      sx;
290   int        i;
291   static     int nyy=0;
292   static     int *yy;
293
294   xhw = (t_xhighway *)data;
295   win = &(xhw->win); 
296
297   if (nyy == 0) {
298     nyy=2*xhw->ir->nlane+1;
299     snew(yy,nyy);
300   }
301   for(i=0; (i<nyy); i++) 
302     yy[i]=((float) i*win->height)/(nyy-1);
303
304   switch (event->type) {
305   case Expose: {
306     if (wd == win->self) {
307       sx=(float)win->width  / xhw->ir->metres;
308       
309       XClearWindow(x11->disp,win->self);
310       XSetForeground(x11->disp,x11->gc,WHITE);
311
312       for(i=2; (i<nyy-1); i+=2)
313         XDrawLine(x11->disp,win->self,x11->gc,0,yy[i],win->width-1,yy[i]);
314       
315       for(i=0; (i<xhw->ncars); i++) {
316         t_car *car=&(xhw->cars[i]);
317         int   w1=car->x*sx;
318         int   h1=yy[1+2*(xhw->ir->nlane-1-car->lane)];
319
320         draw_car(x11->disp,win->self,x11->gc,car,w1,h1);
321       }
322       if (xhw->bDriving)
323         simulate(x11,xhw,xhw->ncars,xhw->cars,xhw->ir);
324     }
325     break;
326   }
327   case ConfigureNotify:
328     if (wd == xhw->main.self) {
329       xhw->main.width=event->xconfigure.width;
330       xhw->main.height=event->xconfigure.height;
331       Configure(xhw);
332       for(i=0; (i<NBUT); i++)
333         XMoveResizeWindow(x11->disp,xhw->but[i].self,
334                           xhw->but[i].x,xhw->but[i].y,
335                           xhw->but[i].width,xhw->but[i].height);
336       XMoveResizeWindow(x11->disp,win->self,
337                         win->x,win->y,win->width,win->height);
338     }
339     else if (wd == win->self) {
340       win->width=event->xconfigure.width;
341       win->height=event->xconfigure.height;
342     }
343     break;
344   case ButtonPress:
345     return TRUE;
346   default:
347     break;
348   }
349   return FALSE;
350 }
351
352 static bool butCallBack(struct t_x11 *x11,XEvent *event, Window wd, void *data)
353 {
354   XSetWindowAttributes attr;
355   t_xhighway *xhw;
356   t_windata  *win;
357   char       *label;
358   int        i;
359
360   xhw = (t_xhighway *)data;
361   for(i=0; (i<NBUT); i++) {
362     if (xhw->but[i].self == wd)
363       break;
364   }
365   if (i == NBUT) {
366     fprintf(stderr,"Incorrect window: %x in butcallback\n",(unsigned)wd);
367     return FALSE;
368   }
369   win=&(xhw->but[i]);
370
371   switch (event->type) {
372   case Expose: 
373     XClearWindow(x11->disp,win->self);
374     switch (i) {
375     case StartStop:
376       label=Driving[xhw->bDriving];
377       break;
378     case Fog:
379       label=Fogs[xhw->bFog];
380       break;
381     default:
382       label=win->text;
383     }
384     XSetForeground(x11->disp,x11->gc,WHITE);
385     TextInWin(x11,win,label,eXCenter,eYCenter);
386     break;
387   
388   case ConfigureNotify:
389     win->width=event->xconfigure.width;
390     win->height=event->xconfigure.height;
391     break;
392   case ButtonPress:
393     switch (i) {
394     case Quit:
395       return TRUE;
396     case StartStop:
397       xhw->bDriving=1-xhw->bDriving;
398       ExposeWin(x11->disp,win->self);
399       if (xhw->bDriving) 
400         ExposeWin(x11->disp,xhw->win.self);
401       break;
402     case Fog:
403       xhw->bFog=1-xhw->bFog;
404       if (xhw->bFog) 
405         attr.background_pixel=DARKGREY;
406       else
407         attr.background_pixel=BLACK;
408       XChangeWindowAttributes(x11->disp,xhw->win.self,CWBackPixel,&attr);
409       /*ExposeWin(x11->disp,win->self);*/
410       break;
411     default:
412       break;
413     }
414     break;
415   default:
416     break;
417   }
418   return FALSE;
419 }
420
421 t_xhighway *GetXHW(t_x11 *x11,char *infile,char *carfile)
422 {
423   t_xhighway *xhw;
424   int        i,h,dh,w;
425
426   snew(xhw,1);
427
428   xhw->ir=read_input(infile);
429   xhw->ncars=read_cars(x11,carfile,&(xhw->cars));
430   
431   h=xhw->ir->nlane*40;
432   dh=20;
433   w=752;
434   InitWin(&xhw->main,0,0,w,h+dh+7,1,Program());
435   xhw->main.self=XCreateSimpleWindow(x11->disp,x11->root,
436                                      xhw->main.x,xhw->main.y,
437                                      xhw->main.width,xhw->main.height,
438                                      xhw->main.bwidth,WHITE,BLACK);
439   x11->RegisterCallback(x11,xhw->main.self,0,xhwCallBack,xhw);
440   x11->SetInputMask(x11,xhw->main.self,ButtonPressMask | ExposureMask |
441                     StructureNotifyMask);
442
443   Configure(xhw);
444
445   for(i=0; (i<NBUT); i++) {
446     t_windata *wd=&(xhw->but[i]);
447
448     wd->self=XCreateSimpleWindow(x11->disp,xhw->main.self,
449                                  wd->x,wd->y,
450                                  wd->width,wd->height,
451                                  wd->bwidth,WHITE,BLACK);
452     x11->RegisterCallback(x11,wd->self,xhw->main.self,
453                           butCallBack,xhw);
454     x11->SetInputMask(x11,wd->self,ButtonPressMask | ExposureMask |
455                       StructureNotifyMask);
456     
457   }
458   xhw->win.self=XCreateSimpleWindow(x11->disp,xhw->main.self,
459                                     xhw->win.x,xhw->win.y,
460                                     xhw->win.width,xhw->win.height,
461                                     xhw->win.bwidth,WHITE,BLACK);
462   x11->RegisterCallback(x11,xhw->win.self,0,xhwCallBack,xhw);
463   x11->SetInputMask(x11,xhw->win.self,ButtonPressMask | ExposureMask |
464                     StructureNotifyMask);
465
466   return xhw;
467 }
468
469 int main(int argc,char *argv[])
470 {
471   static char *desc[] = {
472     "highway is the gromacs highway simulator. It is an X-windows",
473     "gadget that shows a (periodic) autobahn with a user defined",
474     "number of cars. Fog can be turned on or off to increase the",
475     "number of crashes. Nice for a background CPU-eater"
476   };
477   t_x11      *x11;
478   t_xhighway *xhw;
479   t_filenm fnm[] = {
480     { efDAT, "-f", "highway", ffREAD },
481     { efDAT, "-a", "auto",    ffREAD }
482   };
483 #define NFILE asize(fnm)
484
485   CopyRight(stdout,argv[0]);
486   parse_common_args(&argc,argv,PCA_CAN_TIME,FALSE,NFILE,fnm,
487                     0,NULL,asize(desc),desc,0,NULL);
488   
489   if ((x11=GetX11(&argc,argv))==NULL) {
490     fprintf(stderr,"Can't connect to X Server.\n"
491             "Check your DISPLAY environment variable\n");
492     exit(1);
493   }
494   xhw=GetXHW(x11,opt2fn("-f",NFILE,fnm),opt2fn("-a",NFILE,fnm));
495
496   XMapWindow(x11->disp,xhw->main.self);
497   XMapSubwindows(x11->disp,xhw->main.self);
498   x11->MainLoop(x11);
499   x11->CleanUp(x11);
500
501   thanx(stderr);
502   
503   return 0;
504 }