4ca8016ab7f7c039b09c94609da24b3c5aa937f3
[alexxy/gromacs.git] / src / gromacs / math / 3dview.c
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-2004, The GROMACS development team.
6  * Copyright (c) 2010,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 "gromacs/math/3dview.h"
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #include <math.h>
44 #include "sysstuff.h"
45 #include "smalloc.h"
46 #include "macros.h"
47 #include "physics.h"
48 #include "pbc.h"
49 #include "vec.h"
50
51 #define N 4
52
53 void m4_op(mat4 m, rvec x, vec4 v)
54 {
55     int i;
56
57     for (i = 0; (i < N); i++)
58     {
59         v[i] = m[XX][i]*x[XX]+m[YY][i]*x[YY]+m[ZZ][i]*x[ZZ]+m[WW][i];
60     }
61 }
62
63 void unity_m4(mat4 m)
64 {
65     int i, j;
66
67     for (i = 0; (i < N); i++)
68     {
69         for (j = 0; (j < N); j++)
70         {
71             if (i == j)
72             {
73                 m[i][j] = 1.0;
74             }
75             else
76             {
77                 m[i][j] = 0.0;
78             }
79         }
80     }
81 }
82
83 void print_m4(FILE *fp, const char *s, mat4 A)
84 {
85     int i, j;
86
87     if (fp)
88     {
89         fprintf(fp, "%s: ", s);
90         for (i = 0; i < N; i++)
91         {
92             fprintf(fp, "\t");
93             for (j = 0; j < N; j++)
94             {
95                 fprintf(fp, "%10.5f", A[i][j]);
96             }
97             fprintf(fp, "\n");
98         }
99     }
100 }
101
102 void print_v4(FILE *fp, char *s, int dim, real *a)
103 {
104     int j;
105
106     if (fp)
107     {
108         fprintf(fp, "%s: ", s);
109         for (j = 0; j < dim; j++)
110         {
111             fprintf(fp, "%10.5f", a[j]);
112         }
113         fprintf(fp, "\n");
114     }
115 }
116
117 void mult_matrix(mat4 A, mat4 B, mat4 C)
118 {
119     int i, j, k;
120
121     for (i = 0; i < N; i++)
122     {
123         for (j = 0; j < N; j++)
124         {
125             A[i][j] = 0;
126             for (k = 0; (k < N); k++)
127             {
128                 A[i][j] += B[i][k]*C[k][j];
129             }
130         }
131     }
132 }
133
134 void rotate(int axis, real angle, mat4 A)
135 {
136     unity_m4(A);
137
138     switch (axis)
139     {
140         case XX:
141             A[YY][YY] =  cos(angle);
142             A[YY][ZZ] = -sin(angle);
143             A[ZZ][YY] =  sin(angle);
144             A[ZZ][ZZ] =  cos(angle);
145             break;
146         case YY:
147             A[XX][XX] =  cos(angle);
148             A[XX][ZZ] =  sin(angle);
149             A[ZZ][XX] = -sin(angle);
150             A[ZZ][ZZ] =  cos(angle);
151             break;
152         case ZZ:
153             A[XX][XX] =  cos(angle);
154             A[XX][YY] = -sin(angle);
155             A[YY][XX] =  sin(angle);
156             A[YY][YY] =  cos(angle);
157             break;
158         default:
159             gmx_fatal(FARGS, "Error: invalid axis: %d", axis);
160     }
161 }
162
163 void translate(real tx, real ty, real tz, mat4 A)
164 {
165     unity_m4(A);
166     A[3][XX] = tx;
167     A[3][YY] = ty;
168     A[3][ZZ] = tz;
169 }
170
171 static void set_scale(t_3dview *view, real sx, real sy)
172 {
173     view->sc_x = sx;
174     view->sc_y = sy;
175 }
176
177 void calculate_view(t_3dview *view)
178 {
179 #define SMALL 1e-6
180     mat4 To, Te, T1, T2, T3, T4, T5, N1, D1, D2, D3, D4, D5;
181     real dx, dy, dz, l, r;
182
183     /* eye center */
184     dx = view->eye[XX];
185     dy = view->eye[YY];
186     dz = view->eye[ZZ];
187     l  = sqrt(dx*dx+dy*dy+dz*dz);
188     r  = sqrt(dx*dx+dy*dy);
189 #ifdef DEBUG
190     print_v4(debug, "eye", N, view->eye);
191     printf("del: %10.5f%10.5f%10.5f l: %10.5f, r: %10.5f\n", dx, dy, dz, l, r);
192 #endif
193     if (l < SMALL)
194     {
195         gmx_fatal(FARGS, "Error: Zero Length Vector - No View Specified");
196     }
197     translate((real)(-view->origin[XX]),
198               (real)(-view->origin[YY]), (real)(-view->origin[ZZ]), To);
199     translate((real)(-view->eye[XX]),
200               (real)(-view->eye[YY]), (real)(-view->eye[ZZ]), Te);
201
202     unity_m4(T2);
203     T2[YY][YY] = 0, T2[YY][ZZ] = -1, T2[ZZ][YY] = 1, T2[ZZ][ZZ] = 0;
204
205     unity_m4(T3);
206     if (r > 0)
207     {
208         T3[XX][XX] = -dy/r, T3[XX][ZZ] = dx/r, T3[ZZ][XX] = -dx/r, T3[ZZ][ZZ] = -dy/r;
209     }
210
211     unity_m4(T4);
212     T4[YY][YY] = r/l, T4[YY][ZZ] = dz/l, T4[ZZ][YY] = -dz/l, T4[ZZ][ZZ] = r/l;
213
214     unity_m4(T5);
215     T5[ZZ][ZZ] = -1;
216
217     unity_m4(N1);
218     /* N1[XX][XX]=4,N1[YY][YY]=4; */
219
220     mult_matrix(T1, To, view->Rot);
221     mult_matrix(D1, Te, T2);
222     mult_matrix(D2, T3, T4);
223     mult_matrix(D3, T5, N1);
224     mult_matrix(D4, T1, D1);
225     mult_matrix(D5, D2, D3);
226
227     mult_matrix(view->proj, D4, D5);
228
229 #ifdef DEBUG
230     print_m4(debug, "T1", T1);
231     print_m4(debug, "T2", T2);
232     print_m4(debug, "T3", T3);
233     print_m4(debug, "T4", T4);
234     print_m4(debug, "T5", T5);
235     print_m4(debug, "N1", N1);
236     print_m4(debug, "Rot", view->Rot);
237     print_m4(debug, "Proj", view->proj);
238 #endif
239 }
240
241 gmx_bool zoom_3d(t_3dview *view, real fac)
242 {
243     real dr;
244     real bm, dr1, dr2;
245     int  i;
246
247     dr2 = 0;
248     for (i = 0; (i < DIM); i++)
249     {
250         dr   = view->eye[i];
251         dr2 += dr*dr;
252     }
253     dr1 = sqrt(dr2);
254     if (fac < 1)
255     {
256         bm = max(norm(view->box[XX]), max(norm(view->box[YY]), norm(view->box[ZZ])));
257         if (dr1*fac < 1.1*bm) /* Don't come to close */
258         {
259             return FALSE;
260         }
261     }
262
263     for (i = 0; (i < DIM); i++)
264     {
265         view->eye[i] *= fac;
266     }
267     calculate_view(view);
268     return TRUE;
269 }
270
271 void init_rotate_3d(t_3dview *view)
272 {
273     real rot = DEG2RAD*15;
274     int  i;
275
276     for (i = 0; (i < DIM); i++)
277     {
278         rotate(i,        rot, view->RotP[i]);
279         rotate(i, (real)(-rot), view->RotM[i]);
280 #ifdef DEBUG
281         print_m4(debug, "RotP", view->RotP[i]);
282         print_m4(debug, "RotM", view->RotM[i]);
283 #endif
284     }
285 }
286
287
288 void rotate_3d(t_3dview *view, int axis, gmx_bool bPositive)
289 {
290     int  i, j;
291     mat4 m4;
292
293     if (bPositive)
294     {
295         mult_matrix(m4, view->Rot, view->RotP[axis]);
296     }
297     else
298     {
299         mult_matrix(m4, view->Rot, view->RotM[axis]);
300     }
301     for (i = 0; (i < N); i++)
302     {
303         for (j = 0; (j < N); j++)
304         {
305             view->Rot[i][j] = m4[i][j];
306         }
307     }
308
309     calculate_view(view);
310 }
311
312 void translate_view(t_3dview *view, int axis, gmx_bool bPositive)
313 {
314 #ifdef DEBUG
315     printf("Translate called\n");
316 #endif
317     if (bPositive)
318     {
319         view->origin[axis] += view->box[axis][axis]/8;
320     }
321     else
322     {
323         view->origin[axis] -= view->box[axis][axis]/8;
324     }
325     calculate_view(view);
326 }
327
328 void reset_view(t_3dview *view)
329 {
330     int  i;
331
332 #ifdef DEBUG
333     printf("Reset view called\n");
334 #endif
335     set_scale(view, 4.0, 4.0);
336     clear_rvec(view->eye);
337     calc_box_center(view->ecenter, view->box, view->origin);
338     view->eye[ZZ] = 3.0*max(view->box[XX][XX], view->box[YY][YY]);
339     zoom_3d(view, 1.0);
340     view->eye[WW] = view->origin[WW] = 0.0;
341
342     /* Initiate the matrix */
343     unity_m4(view->Rot);
344     calculate_view(view);
345
346     init_rotate_3d(view);
347 }
348
349 t_3dview *init_view(matrix box)
350 {
351     t_3dview *view;
352     int       i, j;
353
354     snew(view, 1);
355
356     /* Copy parameters into variables */
357     for (i = 0; (i < DIM); i++)
358     {
359         for (j = 0; (j < DIM); j++)
360         {
361             view->box[i][j] = box[i][j];
362         }
363     }
364
365     view->ecenter = ecenterDEF;
366
367     reset_view(view);
368
369     return view;
370 }