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