]> git.mxchange.org Git - flightgear.git/blob - src/Main/viewmgr.cxx
Latest changes to the viewer code from Melchior FRANZ
[flightgear.git] / src / Main / viewmgr.cxx
1 // viewmgr.cxx -- class for managing all the views in the flightgear world.
2 //
3 // Written by Curtis Olson, started October 2000.
4 //   partially rewritten by Jim Wilson March 2002
5 //
6 // Copyright (C) 2000  Curtis L. Olson  - curt@flightgear.org
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 #include <string.h>             // strcmp
25
26 #include <plib/sg.h>
27
28 #include "viewmgr.hxx"
29 #include "fg_props.hxx"
30
31
32 // Constructor
33 FGViewMgr::FGViewMgr( void ) :
34   axis_long(0),
35   axis_lat(0),
36   current(0)
37 {
38 }
39
40
41 // Destructor
42 FGViewMgr::~FGViewMgr( void ) {
43 }
44
45 void
46 FGViewMgr::init ()
47 {
48   char stridx [ 20 ];
49   string viewpath, nodepath, strdata;
50   bool from_model = false;
51   bool at_model = false;
52   int from_model_index = 0;
53   int at_model_index = 0;
54   double at_model_damping;
55   double x_offset_m, y_offset_m, z_offset_m, fov_deg;
56   double heading_offset_deg, pitch_offset_deg, roll_offset_deg;
57   double target_x_offset_m, target_y_offset_m, target_z_offset_m;
58   double near_m;
59
60   for (int i = 0; i < fgGetInt("/sim/number-views"); i++) {
61     viewpath = "/sim/view";
62     sprintf(stridx, "[%d]", i);
63     viewpath += stridx;
64
65     // find out what type of view this is...
66     nodepath = viewpath;
67     nodepath += "/type";
68     strdata = fgGetString(nodepath.c_str());
69
70     // FIXME:
71     // this is assumed to be an aircraft model...we will need to read
72     // model-from-type as well.
73     // find out if this is a model we are looking from...
74     nodepath = viewpath;
75     nodepath += "/config/from-model";
76     from_model = fgGetBool(nodepath.c_str());
77
78     // get model index (which model)
79     if (from_model) {
80       nodepath = viewpath;
81       nodepath += "/config/from-model-idx";
82       from_model_index = fgGetInt(nodepath.c_str());     
83     }
84
85     if ( strcmp("lookat",strdata.c_str()) == 0 ) {
86       // find out if this is a model we are looking at...
87       nodepath = viewpath;
88       nodepath += "/config/at-model";
89       at_model = fgGetBool(nodepath.c_str());
90
91       // get model index (which model)
92       if (at_model) {
93         nodepath = viewpath;
94         nodepath += "/config/at-model-idx";
95         at_model_index = fgGetInt(nodepath.c_str());
96
97         // view damping (0.0: no damping; <0.0: all but alt; >0.0: damp all)
98         nodepath = viewpath;
99         nodepath += "/config/at-model-damping";
100         at_model_damping = fgGetDouble(nodepath.c_str(), 0.0);
101       }
102     }
103
104     nodepath = viewpath;
105     nodepath += "/config/x-offset-m";
106     x_offset_m = fgGetDouble(nodepath.c_str());
107     nodepath = viewpath;
108     nodepath += "/config/y-offset-m";
109     y_offset_m = fgGetDouble(nodepath.c_str());
110     nodepath = viewpath;
111     nodepath += "/config/z-offset-m";
112     z_offset_m = fgGetDouble(nodepath.c_str());
113     nodepath = viewpath;
114     nodepath += "/config/pitch-offset-deg";
115     pitch_offset_deg = fgGetDouble(nodepath.c_str());
116     fgSetDouble(nodepath.c_str(),pitch_offset_deg);
117     nodepath = viewpath;
118     nodepath += "/config/heading-offset-deg";
119     heading_offset_deg = fgGetDouble(nodepath.c_str());
120     fgSetDouble(nodepath.c_str(),heading_offset_deg);
121     nodepath = viewpath;
122     nodepath += "/config/roll-offset-deg";
123     roll_offset_deg = fgGetDouble(nodepath.c_str());
124     fgSetDouble(nodepath.c_str(),roll_offset_deg);
125     nodepath = viewpath;
126     nodepath += "/config/default-field-of-view-deg";
127     fov_deg = fgGetDouble(nodepath.c_str());
128
129     // target offsets for lookat mode only...
130     nodepath = viewpath;
131     nodepath += "/config/target-x-offset-m";
132     target_x_offset_m = fgGetDouble(nodepath.c_str());
133     nodepath = viewpath;
134     nodepath += "/config/target-y-offset-m";
135     target_y_offset_m = fgGetDouble(nodepath.c_str());
136     nodepath = viewpath;
137     nodepath += "/config/target-z-offset-m";
138     target_z_offset_m = fgGetDouble(nodepath.c_str());
139
140     nodepath = viewpath;
141     nodepath += "/config/ground-level-nearplane-m";
142     near_m = fgGetDouble(nodepath.c_str());
143
144     // supporting two types now "lookat" = 1 and "lookfrom" = 0
145     if ( strcmp("lookat",strdata.c_str()) == 0 )
146       add_view(new FGViewer ( FG_LOOKAT, from_model, from_model_index,
147                               at_model, at_model_index, at_model_damping,
148                               x_offset_m, y_offset_m,z_offset_m,
149                               heading_offset_deg, pitch_offset_deg,
150                               roll_offset_deg, fov_deg,
151                               target_x_offset_m, target_y_offset_m,
152                               target_z_offset_m, near_m ));
153     else
154       add_view(new FGViewer ( FG_LOOKFROM, from_model, from_model_index, false,
155                               0, 0.0, x_offset_m, y_offset_m, z_offset_m,
156                               heading_offset_deg, pitch_offset_deg,
157                               roll_offset_deg, fov_deg, 0, 0, 0, near_m ));
158   }
159
160   copyToCurrent();
161   
162 }
163
164 void
165 FGViewMgr::reinit ()
166 {
167   char stridx [ 20 ];
168   string viewpath, nodepath, strdata;
169   double fov_deg;
170
171   // reset offsets and fov to configuration defaults
172
173   for (int i = 0; i < fgGetInt("/sim/number-views"); i++) {
174     viewpath = "/sim/view";
175     sprintf(stridx, "[%d]", i);
176     viewpath += stridx;
177
178     setView(i);
179
180     nodepath = viewpath;
181     nodepath += "/config/x-offset-m";
182     fgSetDouble("/sim/current-view/x-offset-m",fgGetDouble(nodepath.c_str()));
183
184     nodepath = viewpath;
185     nodepath += "/config/y-offset-m";
186     fgSetDouble("/sim/current-view/y-offset-m",fgGetDouble(nodepath.c_str()));
187
188     nodepath = viewpath;
189     nodepath += "/config/z-offset-m";
190     fgSetDouble("/sim/current-view/z-offset-m",fgGetDouble(nodepath.c_str()));
191
192     nodepath = viewpath;
193     nodepath += "/config/pitch-offset-deg";
194     fgSetDouble("/sim/current-view/pitch-offset-deg",
195                 fgGetDouble(nodepath.c_str()));
196
197     nodepath = viewpath;
198     nodepath += "/config/heading-offset-deg";
199     fgSetDouble("/sim/current-view/heading-offset-deg",
200                 fgGetDouble(nodepath.c_str()));
201
202     nodepath = viewpath;
203     nodepath += "/config/roll-offset-deg";
204     fgSetDouble("/sim/current-view/roll-offset-deg",
205                 fgGetDouble(nodepath.c_str()));
206
207     nodepath = viewpath;
208     nodepath += "/config/default-field-of-view-deg";
209     fov_deg = fgGetDouble(nodepath.c_str());
210     if (fov_deg < 10.0) {
211       fov_deg = 55.0;
212     }
213     fgSetDouble("/sim/current-view/field-of-view",fov_deg);
214
215     // target offsets for lookat mode only...
216     nodepath = viewpath;
217     nodepath += "/config/target-x-offset-m";
218     fgSetDouble("/sim/current-view/target-x-offset-deg",
219                 fgGetDouble(nodepath.c_str()));
220
221     nodepath = viewpath;
222     nodepath += "/config/target-y-offset-m";
223     fgSetDouble("/sim/current-view/target-y-offset-deg",
224                 fgGetDouble(nodepath.c_str()));
225
226     nodepath = viewpath;
227     nodepath += "/config/target-z-offset-m";
228     fgSetDouble("/sim/current-view/target-z-offset-deg",
229                 fgGetDouble(nodepath.c_str()));
230
231  }
232
233     setView(0);
234
235 }
236
237 typedef double (FGViewMgr::*double_getter)() const;
238
239 void
240 FGViewMgr::bind ()
241 {
242   // these are bound to the current view properties
243   fgTie("/sim/current-view/heading-offset-deg", this,
244         &FGViewMgr::getViewHeadingOffset_deg,
245         &FGViewMgr::setViewHeadingOffset_deg);
246   fgSetArchivable("/sim/current-view/heading-offset-deg");
247   fgTie("/sim/current-view/goal-heading-offset-deg", this,
248         &FGViewMgr::getViewGoalHeadingOffset_deg,
249         &FGViewMgr::setViewGoalHeadingOffset_deg);
250   fgSetArchivable("/sim/current-view/goal-heading-offset-deg");
251   fgTie("/sim/current-view/pitch-offset-deg", this,
252         &FGViewMgr::getViewPitchOffset_deg,
253         &FGViewMgr::setViewPitchOffset_deg);
254   fgSetArchivable("/sim/current-view/pitch-offset-deg");
255   fgTie("/sim/current-view/goal-pitch-offset-deg", this,
256         &FGViewMgr::getGoalViewPitchOffset_deg,
257         &FGViewMgr::setGoalViewPitchOffset_deg);
258   fgSetArchivable("/sim/current-view/goal-pitch-offset-deg");
259
260   fgTie("/sim/current-view/view-number", this, 
261                       &FGViewMgr::getView, &FGViewMgr::setView);
262   fgSetArchivable("/sim/current-view/view-number", FALSE);
263
264   fgTie("/sim/current-view/axes/long", this,
265         (double_getter)0, &FGViewMgr::setViewAxisLong);
266   fgSetArchivable("/sim/current-view/axes/long");
267
268   fgTie("/sim/current-view/axes/lat", this,
269         (double_getter)0, &FGViewMgr::setViewAxisLat);
270   fgSetArchivable("/sim/current-view/axes/lat");
271
272   fgTie("/sim/current-view/field-of-view", this,
273         &FGViewMgr::getFOV_deg, &FGViewMgr::setFOV_deg);
274   fgSetArchivable("/sim/current-view/field-of-view");
275
276   fgTie("/sim/current-view/ground-level-nearplane-m", this,
277         &FGViewMgr::getNear_m, &FGViewMgr::setNear_m);
278   fgSetArchivable("/sim/current-view/ground-level-nearplane-m");
279
280 }
281
282 void
283 FGViewMgr::unbind ()
284 {
285   // FIXME:
286   // need to redo these bindings to the new locations (move to viewer?)
287   fgUntie("/sim/current-view/heading-offset-deg");
288   fgUntie("/sim/current-view/goal-heading-offset-deg");
289   fgUntie("/sim/current-view/pitch-offset-deg");
290   fgUntie("/sim/current-view/goal-pitch-offset-deg");
291   fgUntie("/sim/field-of-view");
292   fgUntie("/sim/current-view/view-number");
293   fgUntie("/sim/current-view/axes/long");
294   fgUntie("/sim/current-view/axes/lat");
295   fgUntie("/sim/current-view/ground-level-nearplane-m");
296 }
297
298 void
299 FGViewMgr::update (double dt)
300 {
301   char stridx [20];
302   string viewpath, nodepath;
303   double lon_deg, lat_deg, alt_ft, roll_deg, pitch_deg, heading_deg;
304
305   FGViewer * view = get_current_view();
306   if (view == 0)
307     return;
308
309   // 
310   int i = current;
311   viewpath = "/sim/view";
312   sprintf(stridx, "[%d]", i);
313   viewpath += stridx;
314
315   FGViewer *loop_view = (FGViewer *)get_view( i );
316
317                 // Set up view location and orientation
318
319   nodepath = viewpath;
320   nodepath += "/config/from-model";
321   if (!fgGetBool(nodepath.c_str())) {
322     nodepath = viewpath;
323     nodepath += "/config/eye-lon-deg-path";
324     lon_deg = fgGetDouble(fgGetString(nodepath.c_str()));
325     nodepath = viewpath;
326     nodepath += "/config/eye-lat-deg-path";
327     lat_deg = fgGetDouble(fgGetString(nodepath.c_str()));
328     nodepath = viewpath;
329     nodepath += "/config/eye-alt-ft-path";
330     alt_ft = fgGetDouble(fgGetString(nodepath.c_str()));
331     nodepath = viewpath;
332     nodepath += "/config/eye-roll-deg-path";
333     roll_deg = fgGetDouble(fgGetString(nodepath.c_str()));
334     nodepath = viewpath;
335     nodepath += "/config/eye-pitch-deg-path";
336     pitch_deg = fgGetDouble(fgGetString(nodepath.c_str()));
337     nodepath = viewpath;
338     nodepath += "/config/eye-heading-deg-path";
339     heading_deg = fgGetDouble(fgGetString(nodepath.c_str()));
340     loop_view->setPosition(lon_deg, lat_deg, alt_ft);
341     loop_view->setOrientation(roll_deg, pitch_deg, heading_deg);
342   } else {
343     // force recalc in viewer
344     loop_view->set_dirty();
345   }
346
347   // if lookat (type 1) then get target data...
348   if (loop_view->getType() == FG_LOOKAT) {
349     nodepath = viewpath;
350     nodepath += "/config/from-model";
351     if (!fgGetBool(nodepath.c_str())) {
352       nodepath = viewpath;
353       nodepath += "/config/target-lon-deg-path";
354       lon_deg = fgGetDouble(fgGetString(nodepath.c_str()));
355       nodepath = viewpath;
356       nodepath += "/config/target-lat-deg-path";
357       lat_deg = fgGetDouble(fgGetString(nodepath.c_str()));
358       nodepath = viewpath;
359       nodepath += "/config/target-alt-ft-path";
360       alt_ft = fgGetDouble(fgGetString(nodepath.c_str()));
361       nodepath = viewpath;
362       nodepath += "/config/target-roll-deg-path";
363       roll_deg = fgGetDouble(fgGetString(nodepath.c_str()));
364       nodepath = viewpath;
365       nodepath += "/config/target-pitch-deg-path";
366       pitch_deg = fgGetDouble(fgGetString(nodepath.c_str()));
367       nodepath = viewpath;
368       nodepath += "/config/target-heading-deg-path";
369       heading_deg = fgGetDouble(fgGetString(nodepath.c_str()));
370   
371       loop_view ->setTargetPosition(lon_deg, lat_deg, alt_ft);
372       loop_view->setTargetOrientation(roll_deg, pitch_deg, heading_deg);
373     } else {
374       loop_view->set_dirty();
375     }
376   }
377
378   setViewXOffset_m(fgGetDouble("/sim/current-view/x-offset-m"));
379   setViewYOffset_m(fgGetDouble("/sim/current-view/y-offset-m"));
380   setViewZOffset_m(fgGetDouble("/sim/current-view/z-offset-m"));
381
382   setViewTargetXOffset_m(fgGetDouble("/sim/current-view/target-x-offset-m"));
383   setViewTargetYOffset_m(fgGetDouble("/sim/current-view/target-y-offset-m"));
384   setViewTargetZOffset_m(fgGetDouble("/sim/current-view/target-z-offset-m"));
385
386                                 // Update the current view
387   do_axes();
388   view->update(dt);
389 }
390
391 void
392 FGViewMgr::copyToCurrent()
393 {
394     char stridx [20];
395     string viewpath, nodepath;
396
397     int i = current;
398     viewpath = "/sim/view";
399     sprintf(stridx, "[%d]", i);
400     viewpath += stridx;
401
402     // copy certain view config data for default values
403     nodepath = viewpath;
404     nodepath += "/config/default-heading-offset-deg";
405     fgSetDouble("/sim/current-view/config/heading-offset-deg",
406                 fgGetDouble(nodepath.c_str()));
407
408     nodepath = viewpath;
409     nodepath += "/config/pitch-offset-deg";
410     fgSetDouble("/sim/current-view/config/pitch-offset-deg",
411                 fgGetDouble(nodepath.c_str()));
412
413     nodepath = viewpath;
414     nodepath += "/config/roll-offset-deg";
415     fgSetDouble("/sim/current-view/config/roll-offset-deg",
416                 fgGetDouble(nodepath.c_str()));
417
418     nodepath = viewpath;
419     nodepath += "/config/default-field-of-view-deg";
420     fgSetDouble("/sim/current-view/config/default-field-of-view-deg",
421                 fgGetDouble(nodepath.c_str()));
422
423     // copy view data
424     fgSetDouble("/sim/current-view/x-offset-m", getViewXOffset_m());
425     fgSetDouble("/sim/current-view/y-offset-m", getViewYOffset_m());
426     fgSetDouble("/sim/current-view/z-offset-m", getViewZOffset_m());
427     fgSetDouble("/sim/current-view/goal-heading-offset-deg",
428                 get_current_view()->getGoalHeadingOffset_deg());
429     fgSetDouble("/sim/current-view/goal-pitch-offset-deg",
430                 get_current_view()->getGoalPitchOffset_deg());
431     fgSetDouble("/sim/current-view/goal-roll-offset-deg",
432                 get_current_view()->getRollOffset_deg());
433     fgSetDouble("/sim/current-view/heading-offset-deg",
434                 get_current_view()->getHeadingOffset_deg());
435     fgSetDouble("/sim/current-view/pitch-offset-deg",
436                 get_current_view()->getPitchOffset_deg());
437     fgSetDouble("/sim/current-view/roll-offset-deg",
438                 get_current_view()->getRollOffset_deg());
439     fgSetDouble("/sim/current-view/target-x-offset-m",
440                 get_current_view()->getTargetXOffset_m());
441     fgSetDouble("/sim/current-view/target-y-offset-m",
442                 get_current_view()->getTargetYOffset_m());
443     fgSetDouble("/sim/current-view/target-z-offset-m",
444                 get_current_view()->getTargetZOffset_m());
445 }
446
447
448 double
449 FGViewMgr::getViewHeadingOffset_deg () const
450 {
451   const FGViewer * view = get_current_view();
452   return (view == 0 ? 0 : view->getHeadingOffset_deg());
453 }
454
455 void
456 FGViewMgr::setViewHeadingOffset_deg (double offset)
457 {
458   FGViewer * view = get_current_view();
459   if (view != 0) {
460     view->setGoalHeadingOffset_deg(offset);
461     view->setHeadingOffset_deg(offset);
462   }
463 }
464
465 double
466 FGViewMgr::getViewGoalHeadingOffset_deg () const
467 {
468   const FGViewer * view = get_current_view();
469   return (view == 0 ? 0 : view->getGoalHeadingOffset_deg());
470 }
471
472 void
473 FGViewMgr::setViewGoalHeadingOffset_deg (double offset)
474 {
475   FGViewer * view = get_current_view();
476   if (view != 0)
477     view->setGoalHeadingOffset_deg(offset);
478 }
479
480 double
481 FGViewMgr::getViewPitchOffset_deg () const
482 {
483   const FGViewer * view = get_current_view();
484   return (view == 0 ? 0 : view->getPitchOffset_deg());
485 }
486
487 void
488 FGViewMgr::setViewPitchOffset_deg (double tilt)
489 {
490   FGViewer * view = get_current_view();
491   if (view != 0) {
492     view->setGoalPitchOffset_deg(tilt);
493     view->setPitchOffset_deg(tilt);
494   }
495 }
496
497 double
498 FGViewMgr::getGoalViewPitchOffset_deg () const
499 {
500   const FGViewer * view = get_current_view();
501   return (view == 0 ? 0 : view->getGoalPitchOffset_deg());
502 }
503
504 void
505 FGViewMgr::setGoalViewPitchOffset_deg (double tilt)
506 {
507   FGViewer * view = get_current_view();
508   if (view != 0)
509     view->setGoalPitchOffset_deg(tilt);
510 }
511
512 double
513 FGViewMgr::getViewXOffset_m () const
514 {
515   const FGViewer * view = get_current_view();
516   if (view != 0) {
517     return ((FGViewer *)view)->getXOffset_m();
518   } else {
519     return 0;
520   }
521 }
522
523 void
524 FGViewMgr::setViewXOffset_m (double x)
525 {
526   FGViewer * view = get_current_view();
527   if (view != 0) {
528     view->setXOffset_m(x);
529   }
530 }
531
532 double
533 FGViewMgr::getViewYOffset_m () const
534 {
535   const FGViewer * view = get_current_view();
536   if (view != 0) {
537     return ((FGViewer *)view)->getYOffset_m();
538   } else {
539     return 0;
540   }
541 }
542
543 void
544 FGViewMgr::setViewYOffset_m (double y)
545 {
546   FGViewer * view = get_current_view();
547   if (view != 0) {
548     view->setYOffset_m(y);
549   }
550 }
551
552 double
553 FGViewMgr::getViewZOffset_m () const
554 {
555   const FGViewer * view = get_current_view();
556   if (view != 0) {
557     return ((FGViewer *)view)->getZOffset_m();
558   } else {
559     return 0;
560   }
561 }
562
563 void
564 FGViewMgr::setViewZOffset_m (double z)
565 {
566   FGViewer * view = get_current_view();
567   if (view != 0) {
568     view->setZOffset_m(z);
569   }
570 }
571
572 double
573 FGViewMgr::getViewTargetXOffset_m () const
574 {
575   const FGViewer * view = get_current_view();
576   if (view != 0) {
577     return ((FGViewer *)view)->getTargetXOffset_m();
578   } else {
579     return 0;
580   }
581 }
582
583 void
584 FGViewMgr::setViewTargetXOffset_m (double x)
585 {
586   FGViewer * view = get_current_view();
587   if (view != 0) {
588     view->setTargetXOffset_m(x);
589   }
590 }
591
592 double
593 FGViewMgr::getViewTargetYOffset_m () const
594 {
595   const FGViewer * view = get_current_view();
596   if (view != 0) {
597     return ((FGViewer *)view)->getTargetYOffset_m();
598   } else {
599     return 0;
600   }
601 }
602
603 void
604 FGViewMgr::setViewTargetYOffset_m (double y)
605 {
606   FGViewer * view = get_current_view();
607   if (view != 0) {
608     view->setTargetYOffset_m(y);
609   }
610 }
611
612 double
613 FGViewMgr::getViewTargetZOffset_m () const
614 {
615   const FGViewer * view = get_current_view();
616   if (view != 0) {
617     return ((FGViewer *)view)->getTargetZOffset_m();
618   } else {
619     return 0;
620   }
621 }
622
623 void
624 FGViewMgr::setViewTargetZOffset_m (double z)
625 {
626   FGViewer * view = get_current_view();
627   if (view != 0) {
628     view->setTargetZOffset_m(z);
629   }
630 }
631
632 int
633 FGViewMgr::getView () const
634 {
635   return ( current );
636 }
637
638 void
639 FGViewMgr::setView (int newview )
640 {
641   // if newview number too low wrap to last view...
642   if ( newview < 0 ) {
643     newview = (int)views.size() -1;
644   }
645   // if newview number to high wrap to zero...
646   if ( newview > ((int)views.size() -1) ) {
647     newview = 0;
648   }
649   // set new view
650   set_view( newview );
651   // copy in view data
652   copyToCurrent ();
653 }
654
655
656 double
657 FGViewMgr::getFOV_deg () const
658 {
659   const FGViewer * view = get_current_view();
660   return (view == 0 ? 0 : view->get_fov());
661 }
662
663 void
664 FGViewMgr::setFOV_deg (double fov)
665 {
666   FGViewer * view = get_current_view();
667   if (view != 0)
668     view->set_fov(fov);
669 }
670
671 double
672 FGViewMgr::getNear_m () const
673 {
674   const FGViewer * view = get_current_view();
675   return (view == 0 ? 0.5f : view->getNear_m());
676 }
677
678 void
679 FGViewMgr::setNear_m (double near_m)
680 {
681   FGViewer * view = get_current_view();
682   if (view != 0)
683     view->setNear_m(near_m);
684 }
685
686 void
687 FGViewMgr::setViewAxisLong (double axis)
688 {
689   axis_long = axis;
690 }
691
692 void
693 FGViewMgr::setViewAxisLat (double axis)
694 {
695   axis_lat = axis;
696 }
697
698 void
699 FGViewMgr::do_axes ()
700 {
701                                 // Take no action when hat is centered
702   if ( ( axis_long <  0.01 ) &&
703        ( axis_long > -0.01 ) &&
704        ( axis_lat  <  0.01 ) &&
705        ( axis_lat  > -0.01 )
706      )
707     return;
708
709   double viewDir = 999;
710
711   /* Do all the quick and easy cases */
712   if (axis_long < 0) {          // Longitudinal axis forward
713     if (axis_lat == axis_long)
714       viewDir = fgGetDouble("/sim/view/config/front-left-direction-deg");
715     else if (axis_lat == - axis_long)
716       viewDir = fgGetDouble("/sim/view/config/front-right-direction-deg");
717     else if (axis_lat == 0)
718       viewDir = fgGetDouble("/sim/view/config/front-direction-deg");
719   } else if (axis_long > 0) {   // Longitudinal axis backward
720     if (axis_lat == - axis_long)
721       viewDir = fgGetDouble("/sim/view/config/back-left-direction-deg");
722     else if (axis_lat == axis_long)
723       viewDir = fgGetDouble("/sim/view/config/back-right-direction-deg");
724     else if (axis_lat == 0)
725       viewDir = fgGetDouble("/sim/view/config/back-direction-deg");
726   } else if (axis_long == 0) {  // Longitudinal axis neutral
727     if (axis_lat < 0)
728       viewDir = fgGetDouble("/sim/view/config/left-direction-deg");
729     else if (axis_lat > 0)
730       viewDir = fgGetDouble("/sim/view/config/right-direction-deg");
731     else return; /* And assertion failure maybe? */
732   }
733
734                                 // Do all the difficult cases
735   if ( viewDir > 900 )
736     viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
737   if ( viewDir < -1 ) viewDir += 360;
738
739   get_current_view()->setGoalHeadingOffset_deg(viewDir);
740 }