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