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