1 // viewer.cxx -- class for managing a viewer in the flightgear world.
3 // Written by Curtis Olson, started August 1997.
4 // overhaul started October 2000.
6 // Copyright (C) 1997 - 2000 Curtis L. Olson - curt@flightgear.org
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.
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.
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.
25 #include <simgear/compiler.h>
31 #include <simgear/debug/logstream.hxx>
32 #include <simgear/constants.h>
33 #include <simgear/math/point3d.hxx>
34 #include <simgear/math/polar3d.hxx>
35 #include <simgear/math/sg_geodesy.hxx>
37 #include <Scenery/scenery.hxx>
43 ////////////////////////////////////////////////////////////////////////
44 // Implementation of FGViewPoint.
45 ////////////////////////////////////////////////////////////////////////
47 FGViewPoint::FGViewPoint ()
55 FGViewPoint::~FGViewPoint ()
60 FGViewPoint::setPosition (double lon_deg, double lat_deg, double alt_ft)
69 FGViewPoint::getAbsoluteViewPos () const
73 return _absolute_view_pos;
77 FGViewPoint::getRelativeViewPos () const
81 return _relative_view_pos;
85 FGViewPoint::getZeroElevViewPos () const
89 return _zero_elev_view_pos;
93 FGViewPoint::recalc () const
95 double sea_level_radius_m;
98 // Convert from geodetic to geocentric
100 sgGeodToGeoc(_lat_deg * SGD_DEGREES_TO_RADIANS,
101 _alt_ft * SG_FEET_TO_METER,
105 // Calculate the cartesian coordinates
106 // of point directly below at sea level.
107 Point3D p = Point3D(_lon_deg * SG_DEGREES_TO_RADIANS,
110 Point3D tmp = sgPolarToCart3d(p) - scenery.get_center();
111 sgSetVec3(_zero_elev_view_pos, tmp[0], tmp[1], tmp[2]);
113 // Calculate the absolute view position
114 // in fgfs coordinates.
115 p.setz(p.radius() + _alt_ft * SG_FEET_TO_METER);
116 tmp = sgPolarToCart3d(p);
117 sgdSetVec3(_absolute_view_pos, tmp[0], tmp[1], tmp[2]);
119 // Calculate the relative view position
120 // from the scenery center.
121 sgdVec3 scenery_center;
122 sgdSetVec3(scenery_center,
123 scenery.get_center().x(),
124 scenery.get_center().y(),
125 scenery.get_center().z());
127 sgdSubVec3(view_pos, _absolute_view_pos, scenery_center);
128 sgSetVec3(_relative_view_pos, view_pos);
133 ////////////////////////////////////////////////////////////////////////
134 // Implementation of FGViewer.
135 ////////////////////////////////////////////////////////////////////////
138 FGViewer::FGViewer( void ):
139 scalingType(FG_SCALING_MAX),
142 goal_view_offset(0.0),
146 sgSetVec3( pilot_offset, 0.0, 0.0, 0.0 );
147 sgdZeroVec3(geod_view_pos);
148 sgdZeroVec3(abs_view_pos);
149 sea_level_radius = SG_EQUATORIAL_RADIUS_M;
150 //a reasonable guess for init, so that the math doesn't blow up
155 FGViewer::~FGViewer( void ) {
174 FGViewer::get_h_fov()
176 switch (scalingType) {
177 case FG_SCALING_WIDTH: // h_fov == fov
180 if (aspect_ratio < 1.0) {
185 return atan(tan(fov/2 * SG_DEGREES_TO_RADIANS) / aspect_ratio) *
186 SG_RADIANS_TO_DEGREES * 2;
194 FGViewer::get_v_fov()
196 switch (scalingType) {
197 case FG_SCALING_WIDTH: // h_fov == fov
198 return atan(tan(fov/2 * SG_DEGREES_TO_RADIANS) * aspect_ratio) *
199 SG_RADIANS_TO_DEGREES * 2;
201 if (aspect_ratio < 1.0) {
203 return atan(tan(fov/2 * SG_DEGREES_TO_RADIANS) * aspect_ratio) *
204 SG_RADIANS_TO_DEGREES * 2;
215 FGViewer::update (int dt)
218 for ( i = 0; i < dt; i++ ) {
219 if ( fabs(get_goal_view_offset() - get_view_offset()) < 0.05 ) {
220 set_view_offset( get_goal_view_offset() );
223 // move current_view.view_offset towards
224 // current_view.goal_view_offset
225 if ( get_goal_view_offset() > get_view_offset() )
227 if ( get_goal_view_offset() - get_view_offset() < SGD_PI ){
228 inc_view_offset( 0.01 );
230 inc_view_offset( -0.01 );
233 if ( get_view_offset() - get_goal_view_offset() < SGD_PI ){
234 inc_view_offset( -0.01 );
236 inc_view_offset( 0.01 );
239 if ( get_view_offset() > SGD_2PI ) {
240 inc_view_offset( -SGD_2PI );
241 } else if ( get_view_offset() < 0 ) {
242 inc_view_offset( SGD_2PI );
247 for ( i = 0; i < dt; i++ ) {
248 if ( fabs(get_goal_view_tilt() - get_view_tilt()) < 0.05 ) {
249 set_view_tilt( get_goal_view_tilt() );
252 // move current_view.view_tilt towards
253 // current_view.goal_view_tilt
254 if ( get_goal_view_tilt() > get_view_tilt() )
256 if ( get_goal_view_tilt() - get_view_tilt() < SGD_PI ){
257 inc_view_tilt( 0.01 );
259 inc_view_tilt( -0.01 );
262 if ( get_view_tilt() - get_goal_view_tilt() < SGD_PI ){
263 inc_view_tilt( -0.01 );
265 inc_view_tilt( 0.01 );
268 if ( get_view_tilt() > SGD_2PI ) {
269 inc_view_tilt( -SGD_2PI );
270 } else if ( get_view_tilt() < 0 ) {
271 inc_view_tilt( SGD_2PI );