Remove unnecessary config.h includes
[alexxy/gromacs.git] / src / programs / view / nmol.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2013, The GROMACS development team.
6  * Copyright (c) 2013,2014, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include <math.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #include "gromacs/legacyheaders/macros.h"
44 #include "gromacs/legacyheaders/txtdump.h"
45 #include "gromacs/pbcutil/pbc.h"
46
47 #include "gromacs/math/vec.h"
48 #include "gromacs/utility/fatalerror.h"
49 #include "gromacs/utility/smalloc.h"
50
51 #include "3dview.h"
52 #include "buttons.h"
53 #include "manager.h"
54 #include "nmol.h"
55 #include "xutil.h"
56
57 #define MSIZE 4
58
59 static bool MWCallBack(t_x11 *x11, XEvent *event, Window /*w*/, void *data)
60 {
61     t_molwin *mw;
62     Window    To;
63     XEvent    letter;
64
65     mw                          = (t_molwin *)data;
66     To                          = mw->wd.Parent;
67     letter.type                 = ClientMessage;
68     letter.xclient.display      = x11->disp;
69     letter.xclient.window       = To;
70     letter.xclient.message_type = 0;
71     letter.xclient.format       = 32;
72     switch (event->type)
73     {
74         case Expose:
75             /* Do Not draw anything, but signal parent instead, he will
76              * coordinate drawing.
77              */
78             letter.xclient.data.l[0] = IDDRAWMOL;
79             letter.xclient.data.l[1] = Button1;
80             XSendEvent(x11->disp, To, True, 0, &letter);
81             break;
82         case ButtonPress:
83 #ifdef DEBUG
84             printf("Molwindow: Buttonpress\n");
85 #endif
86             letter.xclient.data.l[0] = IDLABEL;
87             letter.xclient.data.l[1] = (long)event->xbutton.button;
88             letter.xclient.data.l[2] = event->xbutton.x;
89             letter.xclient.data.l[3] = event->xbutton.y;
90             XSendEvent(x11->disp, To, True, 0, &letter);
91             break;
92         case ConfigureNotify:
93             mw->wd.width  = event->xconfigure.width;
94             mw->wd.height = event->xconfigure.height;
95             break;
96         default:
97             break;
98     }
99     return false;
100 }
101
102 void set_def (t_molwin *mw, int ePBC, matrix box)
103 {
104     mw->bShowHydrogen = true;
105     mw->bond_type     = eBFat;
106     mw->ePBC          = ePBC;
107     mw->boxtype       = esbRect;
108     mw->realbox       = TRICLINIC(box) ? esbTri : esbRect;
109 }
110
111 t_molwin *init_mw(t_x11 *x11, Window Parent,
112                   int x, int y, int width, int height,
113                   unsigned long fg, unsigned long bg,
114                   int ePBC, matrix box)
115 {
116     t_molwin *mw;
117
118     snew(mw, 1);
119     set_def(mw, ePBC, box);
120
121     InitWin(&mw->wd, x, y, width, height, 1, "Mol Window");
122
123     mw->wd.Parent = Parent;
124     mw->wd.self   = XCreateSimpleWindow(x11->disp, Parent, x, y, width, height, 1, fg, bg);
125     x11->RegisterCallback(x11, mw->wd.self, Parent, MWCallBack, mw);
126     x11->SetInputMask(x11, mw->wd.self,
127                       ExposureMask | StructureNotifyMask |
128                       ButtonPressMask);
129     return mw;
130 }
131
132 void map_mw(t_x11 *x11, t_molwin *mw)
133 {
134     XMapWindow(x11->disp, mw->wd.self);
135 }
136
137 bool toggle_hydrogen(t_x11 *x11, t_molwin *mw)
138 {
139     mw->bShowHydrogen = !mw->bShowHydrogen;
140     ExposeWin(x11->disp, mw->wd.self);
141
142     return mw->bShowHydrogen;
143 }
144
145 void set_bond_type(t_x11 *x11, t_molwin *mw, int bt)
146 {
147     if (bt != mw->bond_type)
148     {
149         mw->bond_type = bt;
150         ExposeWin(x11->disp, mw->wd.self);
151     }
152 }
153
154 void set_box_type (t_x11 *x11, t_molwin *mw, int bt)
155 {
156 #ifdef DEBUG
157     fprintf(stderr, "mw->boxtype = %d, bt = %d\n", mw->boxtype, bt);
158 #endif
159     if (bt != mw->boxtype)
160     {
161         if ((bt == esbTrunc && mw->realbox == esbTri) || bt == esbTri || bt == esbNone)
162         {
163             mw->boxtype = bt;
164             ExposeWin(x11->disp, mw->wd.self);
165         }
166         else
167         {
168             fprintf(stderr, "Can not change rectangular box to truncated octahedron\n");
169         }
170     }
171 }
172
173 void done_mw(t_x11 *x11, t_molwin *mw)
174 {
175     x11->UnRegisterCallback(x11, mw->wd.self);
176     sfree(mw);
177 }
178
179 static void draw_atom(Display *disp, Window w, GC gc,
180                       atom_id ai, iv2 vec2[], unsigned long col[], int size[],
181                       bool bBall, bool bPlus)
182 {
183     int xi, yi;
184
185     xi = vec2[ai][XX];
186     yi = vec2[ai][YY];
187     XSetForeground(disp, gc, col[ai]);
188     if (bBall)
189     {
190         XFillCircle(disp, w, gc, xi, yi, size[ai]-1);
191         XSetForeground(disp, gc, BLACK);
192         XDrawCircle(disp, w, gc, xi, yi, size[ai]);
193         /*    XSetForeground(disp,gc,WHITE);
194            XFillCircle(disp,w,gc,xi+4,yi-4,4); */
195     }
196     else if (bPlus)
197     {
198         XDrawLine(disp, w, gc, xi-MSIZE, yi, xi+MSIZE+1, yi);
199         XDrawLine(disp, w, gc, xi, yi-MSIZE, xi, yi+MSIZE+1);
200     }
201     else
202     {
203         XDrawLine(disp, w, gc, xi-1, yi, xi+1, yi);
204     }
205
206 }
207
208 /* Global variables */
209 static rvec gl_fbox, gl_hbox, gl_mhbox;
210
211 static void my_init_pbc(matrix box)
212 {
213     int i;
214
215     for (i = 0; (i < DIM); i++)
216     {
217         gl_fbox[i]  =  box[i][i];
218         gl_hbox[i]  =  gl_fbox[i]*0.5;
219         gl_mhbox[i] = -gl_hbox[i];
220     }
221 }
222
223 static bool local_pbc_dx(rvec x1, rvec x2)
224 {
225     int  i;
226     real dx;
227
228     for (i = 0; (i < DIM); i++)
229     {
230         dx = x1[i]-x2[i];
231         if (dx > gl_hbox[i])
232         {
233             return false;
234         }
235         else if (dx <= gl_mhbox[i])
236         {
237             return false;
238         }
239     }
240     return true;
241 }
242
243 static void draw_bond(Display *disp, Window w, GC gc,
244                       atom_id ai, atom_id aj, iv2 vec2[],
245                       rvec x[], unsigned long col[], int size[], bool bBalls)
246 {
247     unsigned long   ic, jc;
248     int             xi, yi, xj, yj;
249     int             xm, ym;
250
251     if (bBalls)
252     {
253         draw_atom(disp, w, gc, ai, vec2, col, size, true, false);
254         draw_atom(disp, w, gc, aj, vec2, col, size, true, false);
255     }
256     else
257     {
258         if (local_pbc_dx(x[ai], x[aj]))
259         {
260             ic = col[ai];
261             jc = col[aj];
262             xi = vec2[ai][XX];
263             yi = vec2[ai][YY];
264             xj = vec2[aj][XX];
265             yj = vec2[aj][YY];
266
267             if (ic != jc)
268             {
269                 xm = (xi+xj) >> 1;
270                 ym = (yi+yj) >> 1;
271
272                 XSetForeground(disp, gc, ic);
273                 XDrawLine(disp, w, gc, xi, yi, xm, ym);
274                 XSetForeground(disp, gc, jc);
275                 XDrawLine(disp, w, gc, xm, ym, xj, yj);
276             }
277             else
278             {
279                 XSetForeground(disp, gc, ic);
280                 XDrawLine(disp, w, gc, xi, yi, xj, yj);
281             }
282         }
283     }
284 }
285
286 int compare_obj(const void *a, const void *b)
287 {
288     t_object *oa, *ob;
289     real      z;
290
291     oa = (t_object *)a;
292     ob = (t_object *)b;
293
294     z = oa->z-ob->z;
295
296     if (z < 0)
297     {
298         return 1;
299     }
300     else if (z > 0)
301     {
302         return -1;
303     }
304     else
305     {
306         return 0;
307     }
308 }
309
310 void z_fill(t_manager *man, real *zz)
311 {
312     t_object *obj;
313     int       i;
314
315     for (i = 0, obj = man->obj; (i < man->nobj); i++, obj++)
316     {
317         switch (obj->eO)
318         {
319             case eOSingle:
320                 obj->z = zz[obj->ai];
321                 break;
322             case eOBond:
323             case eOHBond:
324                 obj->z = (zz[obj->ai] + zz[obj->aj]) * 0.5;
325                 break;
326             default:
327                 break;
328         }
329     }
330 }
331
332 int filter_vis(t_manager *man)
333 {
334     int          i, nobj, nvis, nhide;
335     atom_id      ai;
336     bool         bAdd, *bVis;
337     t_object    *obj;
338     t_object    *newobj;
339
340     nobj = man->nobj;
341     snew(newobj, nobj);
342     obj   = man->obj;
343     bVis  = man->bVis;
344     nvis  = 0;
345     nhide = nobj-1;
346     for (i = 0; (i < nobj); i++, obj++)
347     {
348         ai   = obj->ai;
349         bAdd = bVis[ai];
350         if (bAdd)
351         {
352             if (obj->eO != eOSingle)
353             {
354                 bAdd = bVis[obj->aj];
355             }
356         }
357         if (bAdd)
358         {
359             newobj[nvis++] = *obj;
360         }
361         else
362         {
363             newobj[nhide--] = *obj;
364         }
365     }
366     sfree(man->obj);
367     man->obj = newobj;
368
369     return nvis;
370 }
371
372 void draw_objects(Display *disp, Window w, GC gc, int nobj,
373                   t_object objs[], iv2 vec2[], rvec x[],
374                   unsigned long col[], int size[], bool bShowHydro, int bond_type,
375                   bool bPlus)
376 {
377     bool         bBalls;
378     int          i;
379     t_object    *obj;
380
381     bBalls = false;
382     switch (bond_type)
383     {
384         case eBThin:
385             XSetLineAttributes(disp, gc, 1, LineSolid, CapNotLast, JoinRound);
386             break;
387         case eBFat:
388             XSetLineAttributes(disp, gc, 3, LineSolid, CapNotLast, JoinRound);
389             break;
390         case eBVeryFat:
391             XSetLineAttributes(disp, gc, 5, LineSolid, CapNotLast, JoinRound);
392             break;
393         case eBSpheres:
394             bBalls = true;
395             bPlus  = false;
396             break;
397         default:
398             gmx_fatal(FARGS, "Invalid bond_type selected: %d\n", bond_type);
399             break;
400     }
401     for (i = 0; (i < nobj); i++)
402     {
403         obj = &(objs[i]);
404         switch (obj->eO)
405         {
406             case eOSingle:
407                 draw_atom(disp, w, gc, obj->ai, vec2, col, size, bBalls, bPlus);
408                 break;
409             case eOBond:
410                 draw_bond(disp, w, gc, obj->ai, obj->aj, vec2, x, col, size, bBalls);
411                 break;
412             case eOHBond:
413                 if (bShowHydro)
414                 {
415                     draw_bond(disp, w, gc, obj->ai, obj->aj, vec2, x, col, size, bBalls);
416                 }
417                 break;
418             default:
419                 break;
420         }
421     }
422     XSetLineAttributes(disp, gc, 1, LineSolid, CapNotLast, JoinRound);
423 }
424
425 static void v4_to_iv2(vec4 x4, iv2 v2, int x0, int y0, real sx, real sy)
426 {
427     real inv_z;
428
429     inv_z  = 1.0/x4[ZZ];
430     v2[XX] = x0+sx*x4[XX]*inv_z;
431     v2[YY] = y0-sy*x4[YY]*inv_z;
432 }
433
434 static void draw_box(t_x11 *x11, Window w, t_3dview *view, matrix box,
435                      int x0, int y0, real sx, real sy, int boxtype)
436 {
437     rvec        rect_tri[8] =  {
438         { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 },
439         { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 }
440     };
441     int         tr_bonds[12][2] = {
442         { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 },
443         { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 },
444         { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 }
445     };
446     static int *edge = NULL;
447     int         i, j, k, i0, i1;
448     rvec        corner[NCUCEDGE], box_center;
449     vec4        x4;
450     iv2         vec2[NCUCEDGE];
451
452     calc_box_center(view->ecenter, box, box_center);
453     if (boxtype == esbTrunc)
454     {
455         calc_compact_unitcell_vertices(view->ecenter, box, corner);
456         if (edge == NULL)
457         {
458             edge = compact_unitcell_edges();
459         }
460
461         for (i = 0; (i < NCUCEDGE); i++)
462         {
463             gmx_mat4_transform_point(view->proj, corner[i], x4);
464             v4_to_iv2(x4, vec2[i], x0, y0, sx, sy);
465         }
466         XSetForeground(x11->disp, x11->gc, YELLOW);
467         for (i = 0; i < NCUCEDGE; i++)
468         {
469             i0 = edge[2*i];
470             i1 = edge[2*i+1];
471             XDrawLine(x11->disp, w, x11->gc,
472                       vec2[i0][XX], vec2[i0][YY], vec2[i1][XX], vec2[i1][YY]);
473         }
474     }
475     else
476     {
477         if (boxtype == esbRect)
478         {
479             for (j = 0; (j < DIM); j++)
480             {
481                 box_center[j] -= 0.5*box[j][j];
482             }
483         }
484         else
485         {
486             for (i = 0; (i < DIM); i++)
487             {
488                 for (j = 0; (j < DIM); j++)
489                 {
490                     box_center[j] -= 0.5*box[i][j];
491                 }
492             }
493         }
494         for (i = 0; (i < 8); i++)
495         {
496             clear_rvec(corner[i]);
497             for (j = 0; (j < DIM); j++)
498             {
499                 if (boxtype == esbTri)
500                 {
501                     for (k = 0; (k < DIM); k++)
502                     {
503                         corner[i][k] += rect_tri[i][j]*box[j][k];
504                     }
505                 }
506                 else
507                 {
508                     corner[i][j] = rect_tri[i][j]*box[j][j];
509                 }
510             }
511             rvec_inc(corner[i], box_center);
512             gmx_mat4_transform_point(view->proj, corner[i], x4);
513             v4_to_iv2(x4, vec2[i], x0, y0, sx, sy);
514         }
515         if (debug)
516         {
517             pr_rvecs(debug, 0, "box", box, DIM);
518             pr_rvecs(debug, 0, "corner", corner, 8);
519         }
520         XSetForeground(x11->disp, x11->gc, YELLOW);
521         for (i = 0; (i < 12); i++)
522         {
523             i0 = tr_bonds[i][0];
524             i1 = tr_bonds[i][1];
525             XDrawLine(x11->disp, w, x11->gc,
526                       vec2[i0][XX], vec2[i0][YY], vec2[i1][XX], vec2[i1][YY]);
527         }
528     }
529 }
530
531 void set_sizes(t_manager *man)
532 {
533     for (int i = 0; i < man->natom; i++)
534     {
535         if (man->bVis[i])
536         {
537             man->size[i] = 180*man->vdw[i];
538         }
539     }
540 }
541
542 void draw_mol(t_x11 *x11, t_manager *man)
543 {
544     static char tstr[2][20];
545     static int  ntime = 0;
546     t_windata  *win;
547     t_3dview   *view;
548     t_molwin   *mw;
549     int         i, x0, y0, nvis;
550     iv2        *vec2;
551     real        sx, sy;
552     vec4        x4;
553
554     if (!man->status)
555     {
556         return;
557     }
558
559     view = man->view;
560     mw   = man->molw;
561
562     win = &(mw->wd);
563
564     vec2 = man->ix;
565     x0   = win->width/2;
566     y0   = win->height/2;
567     sx   = win->width/2*view->sc_x;
568     sy   = win->height/2*view->sc_y;
569
570     my_init_pbc(man->box);
571
572     for (i = 0; (i < man->natom); i++)
573     {
574         if (man->bVis[i])
575         {
576             gmx_mat4_transform_point(view->proj, man->x[i], x4);
577             man->zz[i] = x4[ZZ];
578             v4_to_iv2(x4, vec2[i], x0, y0, sx, sy);
579         }
580     }
581     set_sizes(man);
582
583     z_fill (man, man->zz);
584
585     /* Start drawing */
586     XClearWindow(x11->disp, win->self);
587
588     /* Draw Time */
589     sprintf(tstr[ntime], "Time: %.3f ps", man->time);
590     if (strcmp(tstr[ntime], tstr[1-ntime]) != 0)
591     {
592         set_vbtime(x11, man->vbox, tstr[ntime]);
593         ntime = 1-ntime;
594     }
595
596     if (mw->boxtype != esbNone)
597     {
598         draw_box(x11, win->self, view, man->box, x0, y0, sx, sy, mw->boxtype);
599     }
600
601     /* Should sort on Z-Coordinates here! */
602     nvis = filter_vis(man);
603     if (nvis && man->bSort)
604     {
605         qsort(man->obj, nvis, sizeof(man->obj[0]), compare_obj);
606     }
607
608     /* Draw the objects */
609     draw_objects(x11->disp, win->self, x11->gc,
610                  nvis, man->obj, man->ix, man->x, man->col, man->size,
611                  mw->bShowHydrogen, mw->bond_type, man->bPlus);
612
613     /* Draw the labels */
614     XSetForeground(x11->disp, x11->gc, WHITE);
615     for (i = 0; (i < man->natom); i++)
616     {
617         if (man->bLabel[i] && man->bVis[i])
618         {
619             XDrawString(x11->disp, win->self, x11->gc, vec2[i][XX]+2, vec2[i][YY]-2,
620                         man->szLab[i], strlen(man->szLab[i]));
621         }
622     }
623
624     XSetForeground(x11->disp, x11->gc, x11->fg);
625 }