]> git.mxchange.org Git - flightgear.git/blob - src/Main/views.cxx
Fiddling around with views, fdm data passing and management to try to be
[flightgear.git] / src / Main / views.cxx
1 // views.cxx -- data structures and routines for managing and view
2 //               parameters.
3 //
4 // Written by Curtis Olson, started August 1997.
5 //
6 // Copyright (C) 1997  Curtis L. Olson  - curt@infoplane.com
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 //
22 // $Id$
23
24
25 #ifdef HAVE_CONFIG_H
26 #  include <config.h>
27 #endif
28
29 #include <ssg.h>                // plib include
30
31 #include <Aircraft/aircraft.hxx>
32 #include <Cockpit/panel.hxx>
33 #include <Debug/logstream.hxx>
34 #include <Include/fg_constants.h>
35 #include <Math/mat3.h>
36 #include <Math/point3d.hxx>
37 #include <Math/polar3d.hxx>
38 #include <Math/vector.hxx>
39 #include <Scenery/scenery.hxx>
40 #include <Time/fg_time.hxx>
41
42 #include "options.hxx"
43 #include "views.hxx"
44
45
46 // Define following to extract various vectors directly
47 // from matrices we have allready computed
48 // rather then performing 'textbook algebra' to rederive them
49 // Norman Vine -- nhv@yahoo.com
50 // #define FG_VIEW_INLINE_OPTIMIZATIONS
51
52 // temporary (hopefully) hack
53 static int panel_hist = 0;
54
55
56 // specify code paths ... these are done as variable rather than
57 // #define's because down the road we may want to choose between them
58 // on the fly for different flight models ... this way magic carpet
59 // and external modes wouldn't need to recreate the LaRCsim matrices
60 // themselves.
61
62 static const bool use_larcsim_local_to_body = false;
63
64
65 // This is a record containing current view parameters for the current
66 // aircraft position
67 FGView pilot_view;
68
69 // This is a record containing current view parameters for the current
70 // view position
71 FGView current_view;
72
73
74 // Constructor
75 FGView::FGView( void ) {
76 }
77
78
79 // Initialize a view structure
80 void FGView::Init( void ) {
81     FG_LOG( FG_VIEW, FG_INFO, "Initializing View parameters" );
82
83     view_offset = 0.0;
84     goal_view_offset = 0.0;
85
86     winWidth = current_options.get_xsize();
87     winHeight = current_options.get_ysize();
88
89     if ( ! current_options.get_panel_status() ) {
90         current_view.set_win_ratio( (GLfloat) winWidth / (GLfloat) winHeight );
91     } else {
92         current_view.set_win_ratio( (GLfloat) winWidth / 
93                                     ((GLfloat) (winHeight)*0.4232) );
94     }
95
96     force_update_fov_math();
97 }
98
99
100 // Update the field of view coefficients
101 void FGView::UpdateFOV( const fgOPTIONS& o ) {
102     ssgSetFOV( o.get_fov(), 0.0 );
103
104     double fov, theta_x, theta_y;
105
106     fov = o.get_fov();
107         
108     // printf("win_ratio = %.2f\n", win_ratio);
109     // calculate sin() and cos() of fov / 2 in X direction;
110     theta_x = (fov * win_ratio * DEG_TO_RAD) / 2.0;
111     // printf("theta_x = %.2f\n", theta_x);
112     sin_fov_x = sin(theta_x);
113     cos_fov_x = cos(theta_x);
114     slope_x =  -cos_fov_x / sin_fov_x;
115     // printf("slope_x = %.2f\n", slope_x);
116
117     // fov_x_clip and fov_y_clip convoluted algebraic simplification
118     // see code executed in tilemgr.cxx when USE_FAST_FOV_CLIP not
119     // defined Norman Vine -- nhv@yahoo.com
120 #if defined( USE_FAST_FOV_CLIP )
121     fov_x_clip = slope_x*cos_fov_x - sin_fov_x;
122 #endif // defined( USE_FAST_FOV_CLIP )
123
124     // calculate sin() and cos() of fov / 2 in Y direction;
125     theta_y = (fov * DEG_TO_RAD) / 2.0;
126     // printf("theta_y = %.2f\n", theta_y);
127     sin_fov_y = sin(theta_y);
128     cos_fov_y = cos(theta_y);
129     slope_y = cos_fov_y / sin_fov_y;
130     // printf("slope_y = %.2f\n", slope_y);
131
132 #if defined( USE_FAST_FOV_CLIP )
133     fov_y_clip = -(slope_y*cos_fov_y + sin_fov_y);      
134 #endif // defined( USE_FAST_FOV_CLIP )
135 }
136
137
138 // Update the view volume, position, and orientation
139 void FGView::UpdateViewParams( const FGInterface& f ) {
140     UpdateViewMath(f);
141     
142     if ((current_options.get_panel_status() != panel_hist) &&                          (current_options.get_panel_status()))
143     {
144         FGPanel::OurPanel->ReInit( 0, 0, 1024, 768);
145     }
146
147     if ( ! current_options.get_panel_status() ) {
148         xglViewport(0, 0 , (GLint)(winWidth), (GLint)(winHeight) );
149     } else {
150         xglViewport(0, (GLint)((winHeight)*0.5768), (GLint)(winWidth), 
151                     (GLint)((winHeight)*0.4232) );
152     }
153
154     panel_hist = current_options.get_panel_status();
155 }
156
157
158 void getRotMatrix(double* out, MAT3vec vec, double radians)
159 {
160     /* This function contributed by Erich Boleyn (erich@uruk.org) */
161     /* This function used from the Mesa OpenGL code (matrix.c)  */
162     double s, c; // mag,
163     double vx, vy, vz, xy, yz, zx, xs, ys, zs, one_c; //, xx, yy, zz
164   
165     MAT3identity(out);
166     s = sin(radians);
167     c = cos(radians);
168   
169     //  mag = getMagnitude();
170   
171     vx = vec[0];
172     vy = vec[1];
173     vz = vec[2];
174   
175 #define M(row,col)  out[row*4 + col]
176   
177     /*
178      *     Arbitrary axis rotation matrix.
179      *
180      *  This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
181      *  like so:  Rz * Ry * T * Ry' * Rz'.  T is the final rotation
182      *  (which is about the X-axis), and the two composite transforms
183      *  Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
184      *  from the arbitrary axis to the X-axis then back.  They are
185      *  all elementary rotations.
186      *
187      *  Rz' is a rotation about the Z-axis, to bring the axis vector
188      *  into the x-z plane.  Then Ry' is applied, rotating about the
189      *  Y-axis to bring the axis vector parallel with the X-axis.  The
190      *  rotation about the X-axis is then performed.  Ry and Rz are
191      *  simply the respective inverse transforms to bring the arbitrary
192      *  axis back to it's original orientation.  The first transforms
193      *  Rz' and Ry' are considered inverses, since the data from the
194      *  arbitrary axis gives you info on how to get to it, not how
195      *  to get away from it, and an inverse must be applied.
196      *
197      *  The basic calculation used is to recognize that the arbitrary
198      *  axis vector (x, y, z), since it is of unit length, actually
199      *  represents the sines and cosines of the angles to rotate the
200      *  X-axis to the same orientation, with theta being the angle about
201      *  Z and phi the angle about Y (in the order described above)
202      *  as follows:
203      *
204      *  cos ( theta ) = x / sqrt ( 1 - z^2 )
205      *  sin ( theta ) = y / sqrt ( 1 - z^2 )
206      *
207      *  cos ( phi ) = sqrt ( 1 - z^2 )
208      *  sin ( phi ) = z
209      *
210      *  Note that cos ( phi ) can further be inserted to the above
211      *  formulas:
212      *
213      *  cos ( theta ) = x / cos ( phi )
214      *  sin ( theta ) = y / cos ( phi )
215      *
216      *  ...etc.  Because of those relations and the standard trigonometric
217      *  relations, it is pssible to reduce the transforms down to what
218      *  is used below.  It may be that any primary axis chosen will give the
219      *  same results (modulo a sign convention) using thie method.
220      *
221      *  Particularly nice is to notice that all divisions that might
222      *  have caused trouble when parallel to certain planes or
223      *  axis go away with care paid to reducing the expressions.
224      *  After checking, it does perform correctly under all cases, since
225      *  in all the cases of division where the denominator would have
226      *  been zero, the numerator would have been zero as well, giving
227      *  the expected result.
228      */
229     
230     one_c = 1.0F - c;
231     
232     //  xx = vx * vx;
233     //  yy = vy * vy;
234     //  zz = vz * vz;
235   
236     //  xy = vx * vy;
237     //  yz = vy * vz;
238     //  zx = vz * vx;
239   
240   
241     M(0,0) = (one_c * vx * vx) + c;  
242     xs = vx * s;
243     yz = vy * vz * one_c;
244     M(1,2) = yz + xs;
245     M(2,1) = yz - xs;
246
247     M(1,1) = (one_c * vy * vy) + c;
248     ys = vy * s;
249     zx = vz * vx * one_c;
250     M(0,2) = zx - ys;
251     M(2,0) = zx + ys;
252   
253     M(2,2) = (one_c * vz *vz) + c;
254     zs = vz * s;
255     xy = vx * vy * one_c;
256     M(0,1) = xy + zs;
257     M(1,0) = xy - zs;
258   
259     //  M(0,0) = (one_c * xx) + c;
260     //  M(1,0) = (one_c * xy) - zs;
261     //  M(2,0) = (one_c * zx) + ys;
262   
263     //  M(0,1) = (one_c * xy) + zs;
264     //  M(1,1) = (one_c * yy) + c;
265     //  M(2,1) = (one_c * yz) - xs;
266   
267     //  M(0,2) = (one_c * zx) - ys;
268     //  M(1,2) = (one_c * yz) + xs;
269     //  M(2,2) = (one_c * zz) + c;
270   
271 #undef M
272 }
273
274
275 // Update the view parameters
276 void FGView::UpdateViewMath( const FGInterface& f ) {
277     Point3D p;
278     MAT3vec vec, forward, v0, minus_z;
279     MAT3mat R, TMP, UP, LOCAL, VIEW;
280     double ntmp;
281
282     if ( update_fov ) {
283         // printf("Updating fov\n");
284         UpdateFOV( current_options );
285         update_fov = false;
286     }
287                 
288     scenery.center = scenery.next_center;
289
290 #if !defined(FG_VIEW_INLINE_OPTIMIZATIONS)
291     // printf("scenery center = %.2f %.2f %.2f\n", scenery.center.x,
292     //        scenery.center.y, scenery.center.z);
293
294     // calculate the cartesion coords of the current lat/lon/0 elev
295     p = Point3D( f.get_Longitude(), 
296                  f.get_Lat_geocentric(), 
297                  f.get_Sea_level_radius() * FEET_TO_METER );
298
299     cur_zero_elev = fgPolarToCart3d(p) - scenery.center;
300
301     // calculate view position in current FG view coordinate system
302     // p.lon & p.lat are already defined earlier, p.radius was set to
303     // the sea level radius, so now we add in our altitude.
304     if ( f.get_Altitude() * FEET_TO_METER > 
305          (scenery.cur_elev + 0.5 * METER_TO_FEET) ) {
306         p.setz( p.radius() + f.get_Altitude() * FEET_TO_METER );
307     } else {
308         p.setz( p.radius() + scenery.cur_elev + 0.5 * METER_TO_FEET );
309     }
310
311     abs_view_pos = fgPolarToCart3d(p);
312         
313 #else // FG_VIEW_INLINE_OPTIMIZATIONS
314         
315     double tmp_radius = f.get_Sea_level_radius() * FEET_TO_METER;
316     double tmp = f.get_cos_lat_geocentric() * tmp_radius;
317         
318     cur_zero_elev.setx(f.get_cos_longitude()*tmp - scenery.center.x());
319     cur_zero_elev.sety(f.get_sin_longitude()*tmp - scenery.center.y());
320     cur_zero_elev.setz(f.get_sin_lat_geocentric()*tmp_radius - scenery.center.z());
321
322     // calculate view position in current FG view coordinate system
323     // p.lon & p.lat are already defined earlier, p.radius was set to
324     // the sea level radius, so now we add in our altitude.
325     if ( f.get_Altitude() * FEET_TO_METER > 
326          (scenery.cur_elev + 0.5 * METER_TO_FEET) ) {
327         tmp_radius += f.get_Altitude() * FEET_TO_METER;
328     } else {
329         tmp_radius += scenery.cur_elev + 0.5 * METER_TO_FEET ;
330     }
331     tmp = f.get_cos_lat_geocentric() * tmp_radius;
332     abs_view_pos.setx(f.get_cos_longitude()*tmp);
333     abs_view_pos.sety(f.get_sin_longitude()*tmp);
334     abs_view_pos.setz(f.get_sin_lat_geocentric()*tmp_radius);
335         
336 #endif // FG_VIEW_INLINE_OPTIMIZATIONS
337         
338     view_pos = abs_view_pos - scenery.center;
339
340     FG_LOG( FG_VIEW, FG_DEBUG, "Polar view pos = " << p );
341     FG_LOG( FG_VIEW, FG_DEBUG, "Absolute view pos = " << abs_view_pos );
342     FG_LOG( FG_VIEW, FG_DEBUG, "Relative view pos = " << view_pos );
343
344     // Derive the LOCAL aircraft rotation matrix (roll, pitch, yaw)
345     // from FG_T_local_to_body[3][3]
346
347     if ( use_larcsim_local_to_body ) {
348
349         // Question: Why is the LaRCsim matrix arranged so differently
350         // than the one we need???
351
352         // Answer (I think): The LaRCsim matrix is generated in a
353         // different reference frame than we've set up for our world
354
355         LOCAL[0][0] = f.get_T_local_to_body_33();
356         LOCAL[0][1] = -f.get_T_local_to_body_32();
357         LOCAL[0][2] = -f.get_T_local_to_body_31();
358         LOCAL[0][3] = 0.0;
359         LOCAL[1][0] = -f.get_T_local_to_body_23();
360         LOCAL[1][1] = f.get_T_local_to_body_22();
361         LOCAL[1][2] = f.get_T_local_to_body_21();
362         LOCAL[1][3] = 0.0;
363         LOCAL[2][0] = -f.get_T_local_to_body_13();
364         LOCAL[2][1] = f.get_T_local_to_body_12();
365         LOCAL[2][2] = f.get_T_local_to_body_11();
366         LOCAL[2][3] = 0.0;
367         LOCAL[3][0] = LOCAL[3][1] = LOCAL[3][2] = LOCAL[3][3] = 0.0;
368         LOCAL[3][3] = 1.0;
369
370         // printf("LaRCsim LOCAL matrix\n");
371         // MAT3print(LOCAL, stdout);
372
373     } else {
374
375         // calculate the transformation matrix to go from LaRCsim to ssg
376         sgVec3 vec1;
377         sgSetVec3( vec1, 0.0, 1.0, 0.0 );
378         sgMat4 mat1;
379         sgMakeRotMat4( mat1, 90, vec1 );
380
381         sgVec3 vec2;
382         sgSetVec3( vec2, 1.0, 0.0, 0.0 );
383         sgMat4 mat2;
384         sgMakeRotMat4( mat2, 90, vec2 );
385
386         sgMultMat4( sgLARC_TO_SSG, mat1, mat2 );
387
388         /*
389         cout << "LaRCsim to SSG:" << endl;
390         MAT3mat print;
391         int i;
392         int j;
393         for ( i = 0; i < 4; i++ ) {
394             for ( j = 0; j < 4; j++ ) {
395                 print[i][j] = sgLARC_TO_SSG[i][j];
396             }
397         }
398         MAT3print( print, stdout);
399         */
400
401         // code to calculate LOCAL matrix calculated from Phi, Theta, and
402         // Psi (roll, pitch, yaw) in case we aren't running LaRCsim as our
403         // flight model
404
405         MAT3_SET_VEC(vec, 0.0, 0.0, 1.0);
406         MAT3rotate(R, vec, f.get_Phi());
407         // cout << "Roll matrix" << endl;
408         // MAT3print(R, stdout);
409
410         sgVec3 sgrollvec;
411         sgSetVec3( sgrollvec, 0.0, 0.0, 1.0 );
412         sgMat4 sgPHI;           // roll
413         sgMakeRotMat4( sgPHI, f.get_Phi() * RAD_TO_DEG, sgrollvec );
414
415
416         MAT3_SET_VEC(vec, 0.0, 1.0, 0.0);
417         MAT3rotate(TMP, vec, f.get_Theta());
418         // cout << "Pitch matrix" << endl;;
419         // MAT3print(TMP, stdout);
420         MAT3mult(R, R, TMP);
421         // cout << "tmp rotation matrix, R:" << endl;;
422         // MAT3print(R, stdout);
423
424         sgVec3 sgpitchvec;
425         sgSetVec3( sgpitchvec, 0.0, 1.0, 0.0 );
426         sgMat4 sgTHETA;         // pitch
427         sgMakeRotMat4( sgTHETA, f.get_Theta() * RAD_TO_DEG,
428                        sgpitchvec );
429
430         sgMat4 sgROT;
431         sgMultMat4( sgROT, sgPHI, sgTHETA );
432
433
434         MAT3_SET_VEC(vec, 1.0, 0.0, 0.0);
435         MAT3rotate(TMP, vec, -f.get_Psi());
436         // cout << "Yaw matrix" << endl;
437         // MAT3print(TMP, stdout);
438         MAT3mult(LOCAL, R, TMP);
439         // cout << "LOCAL matrix:" << endl;
440         // MAT3print(LOCAL, stdout);
441
442         sgVec3 sgyawvec;
443         sgSetVec3( sgyawvec, 1.0, 0.0, 0.0 );
444         sgMat4 sgPSI;           // pitch
445         sgMakeRotMat4( sgPSI, -f.get_Psi() * RAD_TO_DEG, sgyawvec );
446
447         sgMultMat4( sgLOCAL, sgROT, sgPSI );
448
449         /*
450         MAT3mat print;
451         int i;
452         int j;
453         for ( i = 0; i < 4; i++ ) {
454             for ( j = 0; j < 4; j++ ) {
455                 print[i][j] = sgLOCAL[i][j];
456             }
457         }
458         MAT3print( print, stdout);
459         */
460     } // if ( use_larcsim_local_to_body ) 
461
462 #if !defined(FG_VIEW_INLINE_OPTIMIZATIONS)
463         
464     // Derive the local UP transformation matrix based on *geodetic*
465     // coordinates
466     MAT3_SET_VEC(vec, 0.0, 0.0, 1.0);
467     MAT3rotate(R, vec, f.get_Longitude());     // R = rotate about Z axis
468     // printf("Longitude matrix\n");
469     // MAT3print(R, stdout);
470
471     MAT3_SET_VEC(vec, 0.0, 1.0, 0.0);
472     MAT3mult_vec(vec, vec, R);
473     MAT3rotate(TMP, vec, -f.get_Latitude());  // TMP = rotate about X axis
474     // printf("Latitude matrix\n");
475     // MAT3print(TMP, stdout);
476
477     MAT3mult(UP, R, TMP);
478     // cout << "Local up matrix" << endl;;
479     // MAT3print(UP, stdout);
480
481     sgMakeRotMat4( sgUP, 
482                    f.get_Longitude() * RAD_TO_DEG,
483                    0.0,
484                    -f.get_Latitude() * RAD_TO_DEG );
485     /*
486     cout << "FG derived UP matrix using sg routines" << endl;
487     MAT3mat print;
488     int i;
489     int j;
490     for ( i = 0; i < 4; i++ ) {
491         for ( j = 0; j < 4; j++ ) {
492             print[i][j] = sgUP[i][j];
493         }
494     }
495     MAT3print( print, stdout);
496     */
497
498     MAT3_SET_VEC(local_up, 1.0, 0.0, 0.0);
499     MAT3mult_vec(local_up, local_up, UP);
500
501     // printf( "Local Up = (%.4f, %.4f, %.4f)\n",
502     //         local_up[0], local_up[1], local_up[2]);
503     
504     // Alternative method to Derive local up vector based on
505     // *geodetic* coordinates
506     // alt_up = fgPolarToCart(FG_Longitude, FG_Latitude, 1.0);
507     // printf( "    Alt Up = (%.4f, %.4f, %.4f)\n", 
508     //         alt_up.x, alt_up.y, alt_up.z);
509
510     // Calculate the VIEW matrix
511     MAT3mult(VIEW, LOCAL, UP);
512     // cout << "VIEW matrix" << endl;;
513     // MAT3print(VIEW, stdout);
514
515     sgMat4 sgTMP, sgTMP2;
516     sgMultMat4( sgTMP, sgLOCAL, sgUP );
517
518     // generate the sg view up vector
519     sgVec3 vec1;
520     sgSetVec3( vec1, 1.0, 0.0, 0.0 );
521     sgXformVec3( sgview_up, vec1, sgTMP );
522
523     // generate the view offset matrix
524     sgMakeRotMat4( sgVIEW_OFFSET, view_offset * RAD_TO_DEG, sgview_up );
525
526     /*
527     cout << "sg VIEW_OFFSET matrix" << endl;
528     MAT3mat print;
529     int i;
530     int j;
531     for ( i = 0; i < 4; i++ ) {
532         for ( j = 0; j < 4; j++ ) {
533             print[i][j] = sgVIEW_OFFSET[i][j];
534         }
535     }
536     MAT3print( print, stdout);
537     */
538
539     sgMultMat4( sgTMP2, sgTMP, sgVIEW_OFFSET );
540     sgMultMat4( sgVIEW_ROT, sgLARC_TO_SSG, sgTMP2 );
541
542     sgMakeTransMat4( sgTRANS, view_pos.x(), view_pos.y(), view_pos.z() );
543
544     sgMultMat4( sgVIEW, sgVIEW_ROT, sgTRANS );
545
546     // FGMat4Wrapper tmp;
547     // sgCopyMat4( tmp.m, sgVIEW );
548     // follow.push_back( tmp );
549
550     // generate the current up, forward, and fwrd-view vectors
551     MAT3_SET_VEC(vec, 1.0, 0.0, 0.0);
552     MAT3mult_vec(view_up, vec, VIEW);
553
554     /*
555     cout << "FG derived VIEW matrix using sg routines" << endl;
556     MAT3mat print;
557     int i;
558     int j;
559     for ( i = 0; i < 4; i++ ) {
560         for ( j = 0; j < 4; j++ ) {
561             print[i][j] = sgVIEW[i][j];
562         }
563     }
564     MAT3print( print, stdout);
565     */
566
567     MAT3_SET_VEC(vec, 0.0, 0.0, 1.0);
568     MAT3mult_vec(forward, vec, VIEW);
569     // printf( "Forward vector is (%.2f,%.2f,%.2f)\n", forward[0], forward[1], 
570     //         forward[2]);
571
572     MAT3rotate(TMP, view_up, view_offset);
573     MAT3mult_vec(view_forward, forward, TMP);
574
575     // make a vector to the current view position
576     MAT3_SET_VEC(v0, view_pos.x(), view_pos.y(), view_pos.z());
577
578     // Given a vector pointing straight down (-Z), map into onto the
579     // local plane representing "horizontal".  This should give us the
580     // local direction for moving "south".
581     MAT3_SET_VEC(minus_z, 0.0, 0.0, -1.0);
582     map_vec_onto_cur_surface_plane(local_up, v0, minus_z, surface_south);
583     MAT3_NORMALIZE_VEC(surface_south, ntmp);
584     // printf( "Surface direction directly south %.2f %.2f %.2f\n",
585     //         surface_south[0], surface_south[1], surface_south[2]);
586
587     // now calculate the surface east vector
588     MAT3rotate(TMP, view_up, FG_PI_2);
589     MAT3mult_vec(surface_east, surface_south, TMP);
590     // printf( "Surface direction directly east %.2f %.2f %.2f\n",
591     //         surface_east[0], surface_east[1], surface_east[2]);
592     // printf( "Should be close to zero = %.2f\n", 
593     //         MAT3_DOT_PRODUCT(surface_south, surface_east));
594         
595 #else // FG_VIEW_INLINE_OPTIMIZATIONS
596          
597     //  // Build spherical to cartesian transform matrix directly
598     double cos_lat = f.get_cos_latitude(); // cos(-f.get_Latitude());
599     double sin_lat = -f.get_sin_latitude(); // sin(-f.get_Latitude());
600     double cos_lon = f.get_cos_longitude(); //cos(f.get_Longitude());
601     double sin_lon = f.get_sin_longitude(); //sin(f.get_Longitude());
602
603     double *mat = (double *)UP;
604         
605     mat[0] =  cos_lat*cos_lon;
606     mat[1] =  cos_lat*sin_lon;
607     mat[2] = -sin_lat;
608     mat[3] =  0.0;
609     mat[4] =  -sin_lon;
610     mat[5] =  cos_lon;
611     mat[6] =  0.0;
612     mat[7] =  0.0;
613     mat[8]  =  sin_lat*cos_lon;
614     mat[9]  =  sin_lat*sin_lon;
615     mat[10] =  cos_lat;
616     mat[11] =  mat[12] = mat[13] = mat[14] = 0.0;
617     mat[15] =  1.0;
618
619     MAT3mult(VIEW, LOCAL, UP);
620         
621     // THESE COULD JUST BE POINTERS !!!
622     MAT3_SET_VEC(local_up, mat[0],     mat[1],     mat[2]);
623     MAT3_SET_VEC(view_up,  VIEW[0][0], VIEW[0][1], VIEW[0][2]);
624     MAT3_SET_VEC(forward,  VIEW[2][0], VIEW[2][1], VIEW[2][2]);
625
626     getRotMatrix((double *)TMP, view_up, view_offset);
627     MAT3mult_vec(view_forward, forward, TMP);
628
629     // make a vector to the current view position
630     MAT3_SET_VEC(v0, view_pos.x(), view_pos.y(), view_pos.z());
631
632     // Given a vector pointing straight down (-Z), map into onto the
633     // local plane representing "horizontal".  This should give us the
634     // local direction for moving "south".
635     MAT3_SET_VEC(minus_z, 0.0, 0.0, -1.0);
636     map_vec_onto_cur_surface_plane(local_up, v0, minus_z, surface_south);
637
638     MAT3_NORMALIZE_VEC(surface_south, ntmp);
639     // printf( "Surface direction directly south %.6f %.6f %.6f\n",
640     //         surface_south[0], surface_south[1], surface_south[2]);
641
642     // now calculate the surface east vector
643     getRotMatrix((double *)TMP, view_up, FG_PI_2);
644     MAT3mult_vec(surface_east, surface_south, TMP);
645     // printf( "Surface direction directly east %.6f %.6f %.6f\n",
646     //         surface_east[0], surface_east[1], surface_east[2]);
647     // printf( "Should be close to zero = %.6f\n", 
648     //         MAT3_DOT_PRODUCT(surface_south, surface_east));
649 #endif // !defined(FG_VIEW_INLINE_OPTIMIZATIONS)
650 }
651
652
653 // Destructor
654 FGView::~FGView( void ) {
655 }