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