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