Moved ngmx to C++, renamed it to view.
[gromacs.git] / src / programs / view / nmol.cpp
blob8851f6c5fa5a63edc8fed432d10566de46c542a8
1 /*
3 * This source code is part of
5 * G R O M A C S
7 * GROningen MAchine for Chemical Simulations
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-2013, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
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.
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.
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.
30 * For more info, check our website at http://www.gromacs.org
32 * And Hey:
33 * Gyas ROwers Mature At Cryogenic Speed
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
39 #include <math.h>
40 #include "sysstuff.h"
41 #include <string.h>
42 #include "smalloc.h"
43 #include "macros.h"
44 #include "xutil.h"
45 #include "3dview.h"
46 #include "gmx_fatal.h"
47 #include "buttons.h"
48 #include "manager.h"
49 #include "nmol.h"
50 #include "vec.h"
51 #include "txtdump.h"
52 #include "pbc.h"
54 #define MSIZE 4
56 static bool MWCallBack(t_x11 *x11, XEvent *event, Window w, void *data)
58 t_molwin *mw;
59 Window To;
60 XEvent letter;
62 mw = (t_molwin *)data;
63 To = mw->wd.Parent;
64 letter.type = ClientMessage;
65 letter.xclient.display = x11->disp;
66 letter.xclient.window = To;
67 letter.xclient.message_type = 0;
68 letter.xclient.format = 32;
69 switch (event->type)
71 case Expose:
72 /* Do Not draw anything, but signal parent instead, he will
73 * coordinate drawing.
75 letter.xclient.data.l[0] = IDDRAWMOL;
76 letter.xclient.data.l[1] = Button1;
77 XSendEvent(x11->disp, To, True, 0, &letter);
78 break;
79 case ButtonPress:
80 #ifdef DEBUG
81 printf("Molwindow: Buttonpress\n");
82 #endif
83 letter.xclient.data.l[0] = IDLABEL;
84 letter.xclient.data.l[1] = (long)event->xbutton.button;
85 letter.xclient.data.l[2] = event->xbutton.x;
86 letter.xclient.data.l[3] = event->xbutton.y;
87 XSendEvent(x11->disp, To, True, 0, &letter);
88 break;
89 case ConfigureNotify:
90 mw->wd.width = event->xconfigure.width;
91 mw->wd.height = event->xconfigure.height;
92 break;
93 default:
94 break;
96 return false;
99 void set_def (t_molwin *mw, int ePBC, matrix box)
101 mw->bShowHydrogen = true;
102 mw->bond_type = eBFat;
103 mw->ePBC = ePBC;
104 mw->boxtype = esbRect;
105 mw->realbox = TRICLINIC(box) ? esbTri : esbRect;
108 t_molwin *init_mw(t_x11 *x11, Window Parent,
109 int x, int y, int width, int height,
110 unsigned long fg, unsigned long bg,
111 int ePBC, matrix box)
113 t_molwin *mw;
115 snew(mw, 1);
116 set_def(mw, ePBC, box);
118 InitWin(&mw->wd, x, y, width, height, 1, "Mol Window");
120 mw->wd.Parent = Parent;
121 mw->wd.self = XCreateSimpleWindow(x11->disp, Parent, x, y, width, height, 1, fg, bg);
122 x11->RegisterCallback(x11, mw->wd.self, Parent, MWCallBack, mw);
123 x11->SetInputMask(x11, mw->wd.self,
124 ExposureMask | StructureNotifyMask |
125 ButtonPressMask);
126 return mw;
129 void map_mw(t_x11 *x11, t_molwin *mw)
131 XMapWindow(x11->disp, mw->wd.self);
134 bool toggle_hydrogen(t_x11 *x11, t_molwin *mw)
136 mw->bShowHydrogen = !mw->bShowHydrogen;
137 ExposeWin(x11->disp, mw->wd.self);
139 return mw->bShowHydrogen;
142 void set_bond_type(t_x11 *x11, t_molwin *mw, int bt)
144 if (bt != mw->bond_type)
146 mw->bond_type = bt;
147 ExposeWin(x11->disp, mw->wd.self);
151 void set_box_type (t_x11 *x11, t_molwin *mw, int bt)
153 #ifdef DEBUG
154 fprintf(stderr, "mw->boxtype = %d, bt = %d\n", mw->boxtype, bt);
155 #endif
156 if (bt != mw->boxtype)
158 if ((bt == esbTrunc && mw->realbox == esbTri) || bt == esbTri || bt == esbNone)
160 mw->boxtype = bt;
161 ExposeWin(x11->disp, mw->wd.self);
163 else
165 fprintf(stderr, "Can not change rectangular box to truncated octahedron\n");
170 void done_mw(t_x11 *x11, t_molwin *mw)
172 x11->UnRegisterCallback(x11, mw->wd.self);
173 sfree(mw);
176 static void draw_atom(Display *disp, Window w, GC gc,
177 atom_id ai, iv2 vec2[], unsigned long col[], int size[],
178 bool bBall, bool bPlus)
180 int xi, yi;
182 xi = vec2[ai][XX];
183 yi = vec2[ai][YY];
184 XSetForeground(disp, gc, col[ai]);
185 if (bBall)
187 XFillCircle(disp, w, gc, xi, yi, size[ai]-1);
188 XSetForeground(disp, gc, BLACK);
189 XDrawCircle(disp, w, gc, xi, yi, size[ai]);
190 /* XSetForeground(disp,gc,WHITE);
191 XFillCircle(disp,w,gc,xi+4,yi-4,4); */
193 else if (bPlus)
195 XDrawLine(disp, w, gc, xi-MSIZE, yi, xi+MSIZE+1, yi);
196 XDrawLine(disp, w, gc, xi, yi-MSIZE, xi, yi+MSIZE+1);
198 else
200 XDrawLine(disp, w, gc, xi-1, yi, xi+1, yi);
205 /* Global variables */
206 static rvec gl_fbox, gl_hbox, gl_mhbox;
208 static void my_init_pbc(matrix box)
210 int i;
212 for (i = 0; (i < DIM); i++)
214 gl_fbox[i] = box[i][i];
215 gl_hbox[i] = gl_fbox[i]*0.5;
216 gl_mhbox[i] = -gl_hbox[i];
220 static bool local_pbc_dx(rvec x1, rvec x2)
222 int i;
223 real dx;
225 for (i = 0; (i < DIM); i++)
227 dx = x1[i]-x2[i];
228 if (dx > gl_hbox[i])
230 return false;
232 else if (dx <= gl_mhbox[i])
234 return false;
237 return true;
240 static void draw_bond(Display *disp, Window w, GC gc,
241 atom_id ai, atom_id aj, iv2 vec2[],
242 rvec x[], unsigned long col[], int size[], bool bBalls)
244 unsigned long ic, jc;
245 int xi, yi, xj, yj;
246 int xm, ym;
248 if (bBalls)
250 draw_atom(disp, w, gc, ai, vec2, col, size, true, false);
251 draw_atom(disp, w, gc, aj, vec2, col, size, true, false);
253 else
255 if (local_pbc_dx(x[ai], x[aj]))
257 ic = col[ai];
258 jc = col[aj];
259 xi = vec2[ai][XX];
260 yi = vec2[ai][YY];
261 xj = vec2[aj][XX];
262 yj = vec2[aj][YY];
264 if (ic != jc)
266 xm = (xi+xj) >> 1;
267 ym = (yi+yj) >> 1;
269 XSetForeground(disp, gc, ic);
270 XDrawLine(disp, w, gc, xi, yi, xm, ym);
271 XSetForeground(disp, gc, jc);
272 XDrawLine(disp, w, gc, xm, ym, xj, yj);
274 else
276 XSetForeground(disp, gc, ic);
277 XDrawLine(disp, w, gc, xi, yi, xj, yj);
283 int compare_obj(const void *a, const void *b)
285 t_object *oa, *ob;
286 real z;
288 oa = (t_object *)a;
289 ob = (t_object *)b;
291 z = oa->z-ob->z;
293 if (z < 0)
295 return 1;
297 else if (z > 0)
299 return -1;
301 else
303 return 0;
307 void create_visibility(t_manager *man)
309 t_object *obj;
310 int i;
312 for (i = 0, obj = man->obj; (i < man->nobj); i++, obj++)
314 if (obj->eV != eVHidden)
316 man->bVis[obj->ai] = true;
317 switch (obj->eO)
319 case eOBond:
320 case eOHBond:
321 man->bVis[obj->aj] = true;
322 break;
323 default:
324 break;
330 void z_fill(t_manager *man, real *zz)
332 t_object *obj;
333 int i;
335 for (i = 0, obj = man->obj; (i < man->nobj); i++, obj++)
337 switch (obj->eO)
339 case eOSingle:
340 obj->z = zz[obj->ai];
341 break;
342 case eOBond:
343 case eOHBond:
344 obj->z = (zz[obj->ai] + zz[obj->aj]) * 0.5;
345 break;
346 default:
347 break;
352 int filter_vis(t_manager *man)
354 int i, nobj, nvis, nhide;
355 atom_id ai;
356 bool bAdd, *bVis;
357 t_object *obj;
358 t_object *newobj;
360 nobj = man->nobj;
361 snew(newobj, nobj);
362 obj = man->obj;
363 bVis = man->bVis;
364 nvis = 0;
365 nhide = nobj-1;
366 for (i = 0; (i < nobj); i++, obj++)
368 ai = obj->ai;
369 bAdd = bVis[ai];
370 if (bAdd)
372 if (obj->eO != eOSingle)
374 bAdd = bVis[obj->aj];
377 if (bAdd)
379 newobj[nvis++] = *obj;
381 else
383 newobj[nhide--] = *obj;
386 sfree(man->obj);
387 man->obj = newobj;
389 return nvis;
392 void draw_objects(Display *disp, Window w, GC gc, int nobj,
393 t_object objs[], iv2 vec2[], rvec x[],
394 unsigned long col[], int size[], bool bShowHydro, int bond_type,
395 bool bPlus)
397 bool bBalls;
398 int i;
399 t_object *obj;
401 bBalls = false;
402 switch (bond_type)
404 case eBThin:
405 XSetLineAttributes(disp, gc, 1, LineSolid, CapNotLast, JoinRound);
406 break;
407 case eBFat:
408 XSetLineAttributes(disp, gc, 3, LineSolid, CapNotLast, JoinRound);
409 break;
410 case eBVeryFat:
411 XSetLineAttributes(disp, gc, 5, LineSolid, CapNotLast, JoinRound);
412 break;
413 case eBSpheres:
414 bBalls = true;
415 bPlus = false;
416 break;
417 default:
418 gmx_fatal(FARGS, "Invalid bond_type selected: %d\n", bond_type);
419 break;
421 for (i = 0; (i < nobj); i++)
423 obj = &(objs[i]);
424 switch (obj->eO)
426 case eOSingle:
427 draw_atom(disp, w, gc, obj->ai, vec2, col, size, bBalls, bPlus);
428 break;
429 case eOBond:
430 draw_bond(disp, w, gc, obj->ai, obj->aj, vec2, x, col, size, bBalls);
431 break;
432 case eOHBond:
433 if (bShowHydro)
435 draw_bond(disp, w, gc, obj->ai, obj->aj, vec2, x, col, size, bBalls);
437 break;
438 default:
439 break;
442 XSetLineAttributes(disp, gc, 1, LineSolid, CapNotLast, JoinRound);
445 static void v4_to_iv2(vec4 x4, iv2 v2, int x0, int y0, real sx, real sy)
447 real inv_z;
449 inv_z = 1.0/x4[ZZ];
450 v2[XX] = x0+sx*x4[XX]*inv_z;
451 v2[YY] = y0-sy*x4[YY]*inv_z;
454 static void draw_box(t_x11 *x11, Window w, t_3dview *view, matrix box,
455 int x0, int y0, real sx, real sy, int boxtype)
457 rvec rect_tri[8] = {
458 { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 },
459 { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 }
461 int tr_bonds[12][2] = {
462 { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 },
463 { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 },
464 { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 }
466 static int *edge = NULL;
467 int i, j, k, i0, i1;
468 rvec corner[NCUCEDGE], box_center;
469 vec4 x4;
470 iv2 vec2[NCUCEDGE], tv2;
472 calc_box_center(view->ecenter, box, box_center);
473 if (boxtype == esbTrunc)
475 calc_compact_unitcell_vertices(view->ecenter, box, corner);
476 if (edge == NULL)
478 edge = compact_unitcell_edges();
481 for (i = 0; (i < NCUCEDGE); i++)
483 m4_op(view->proj, corner[i], x4);
484 v4_to_iv2(x4, vec2[i], x0, y0, sx, sy);
486 XSetForeground(x11->disp, x11->gc, YELLOW);
487 for (i = 0; i < NCUCEDGE; i++)
489 i0 = edge[2*i];
490 i1 = edge[2*i+1];
491 XDrawLine(x11->disp, w, x11->gc,
492 vec2[i0][XX], vec2[i0][YY], vec2[i1][XX], vec2[i1][YY]);
495 else
497 if (boxtype == esbRect)
499 for (j = 0; (j < DIM); j++)
501 box_center[j] -= 0.5*box[j][j];
504 else
506 for (i = 0; (i < DIM); i++)
508 for (j = 0; (j < DIM); j++)
510 box_center[j] -= 0.5*box[i][j];
514 for (i = 0; (i < 8); i++)
516 clear_rvec(corner[i]);
517 for (j = 0; (j < DIM); j++)
519 if (boxtype == esbTri)
521 for (k = 0; (k < DIM); k++)
523 corner[i][k] += rect_tri[i][j]*box[j][k];
526 else
528 corner[i][j] = rect_tri[i][j]*box[j][j];
531 rvec_inc(corner[i], box_center);
532 m4_op(view->proj, corner[i], x4);
533 v4_to_iv2(x4, vec2[i], x0, y0, sx, sy);
535 if (debug)
537 pr_rvecs(debug, 0, "box", box, DIM);
538 pr_rvecs(debug, 0, "corner", corner, 8);
540 XSetForeground(x11->disp, x11->gc, YELLOW);
541 for (i = 0; (i < 12); i++)
543 i0 = tr_bonds[i][0];
544 i1 = tr_bonds[i][1];
545 XDrawLine(x11->disp, w, x11->gc,
546 vec2[i0][XX], vec2[i0][YY], vec2[i1][XX], vec2[i1][YY]);
551 void set_sizes(t_manager *man, real sx, real sy)
553 int i;
555 for (i = 0; (i < man->natom); i++)
557 if (man->bVis[i])
559 man->size[i] = 180*man->vdw[i];
564 void draw_mol(t_x11 *x11, t_manager *man)
566 static char tstr[2][20];
567 static int ntime = 0;
568 t_windata *win;
569 t_3dview *view;
570 t_molwin *mw;
571 int i, x0, y0, nvis;
572 iv2 *vec2;
573 real sx, sy;
574 vec4 x4;
576 if (!man->status)
578 return;
581 view = man->view;
582 mw = man->molw;
584 win = &(mw->wd);
586 vec2 = man->ix;
587 x0 = win->width/2;
588 y0 = win->height/2;
589 sx = win->width/2*view->sc_x;
590 sy = win->height/2*view->sc_y;
592 my_init_pbc(man->box);
594 /* create_visibility(man); */
596 for (i = 0; (i < man->natom); i++)
598 if (man->bVis[i])
600 m4_op(view->proj, man->x[i], x4);
601 man->zz[i] = x4[ZZ];
602 v4_to_iv2(x4, vec2[i], x0, y0, sx, sy);
605 set_sizes(man, sx, sy);
607 z_fill (man, man->zz);
609 /* Start drawing */
610 XClearWindow(x11->disp, win->self);
612 /* Draw Time */
613 sprintf(tstr[ntime], "Time: %.3f ps", man->time);
614 if (strcmp(tstr[ntime], tstr[1-ntime]) != 0)
616 set_vbtime(x11, man->vbox, tstr[ntime]);
617 ntime = 1-ntime;
620 if (mw->boxtype != esbNone)
622 draw_box(x11, win->self, view, man->box, x0, y0, sx, sy, mw->boxtype);
625 /* Should sort on Z-Coordinates here! */
626 nvis = filter_vis(man);
627 if (nvis && man->bSort)
629 qsort(man->obj, nvis, sizeof(man->obj[0]), compare_obj);
632 /* Draw the objects */
633 draw_objects(x11->disp, win->self, x11->gc,
634 nvis, man->obj, man->ix, man->x, man->col, man->size,
635 mw->bShowHydrogen, mw->bond_type, man->bPlus);
637 /* Draw the labels */
638 XSetForeground(x11->disp, x11->gc, WHITE);
639 for (i = 0; (i < man->natom); i++)
641 if (man->bLabel[i] && man->bVis[i])
643 XDrawString(x11->disp, win->self, x11->gc, vec2[i][XX]+2, vec2[i][YY]-2,
644 man->szLab[i], strlen(man->szLab[i]));
648 XSetForeground(x11->disp, x11->gc, x11->fg);