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