1
0
Fork 0
flightgear/src/Network/native_gui.cxx
ehofman 7b824755ee Mathias Fröhlich:
I have prepared a patch that:
- Introduces a FGTileMgr::scenery_available method which asks the tilemanager
  if scenery for a given range around a lat/lon pair is already loaded and make
  use of that method at some -9999 meter checks.
- Introduces a FGScenery::get_elevation_m method which queries the altitude at
  a given position. In constrast to the groundcache functions this is the best
  choice if you ask for one *single* altitude value. Make use of that thing in
  AI/ATC classes and for the current views ground level. At the current views
  part the groundcache is reused if possible.
- The computation of the 'current groundlevel' is no longer done on the
  tilemanagers update since the required functions are now better seperated.

Alltogether it eliminates somehow redundant terrain level computations which
are now superseeded by that more finegrained functions and the existence of
the groundcache. Additionally it introduces an api to commonly required
functions which was very complex to do prevously.
2005-08-14 12:57:12 +00:00

369 lines
11 KiB
C++

// native_gui.cxx -- FGFS external gui data export class
//
// Written by Curtis Olson, started January 2002.
//
// Copyright (C) 2002 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/debug/logstream.hxx>
#include <simgear/io/lowlevel.hxx> // endian tests
#include <simgear/io/iochannel.hxx>
#include <simgear/timing/sg_time.hxx>
#include <FDM/flight.hxx>
#include <Time/tmp.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>
#include "native_gui.hxx"
// FreeBSD works better with this included last ... (?)
#if defined(WIN32) && !defined(__CYGWIN__)
# include <windows.h>
#else
# include <netinet/in.h> // htonl() ntohl()
#endif
// #define FG_USE_NETWORK_BYTE_ORDER
#if defined( FG_USE_NETWORK_BYTE_ORDER )
// The function htond is defined this way due to the way some
// processors and OSes treat floating point values. Some will raise
// an exception whenever a "bad" floating point value is loaded into a
// floating point register. Solaris is notorious for this, but then
// so is LynxOS on the PowerPC. By translating the data in place,
// there is no need to load a FP register with the "corruped" floating
// point value. By doing the BIG_ENDIAN test, I can optimize the
// routine for big-endian processors so it can be as efficient as
// possible
static void htond (double &x)
{
if ( sgIsLittleEndian() ) {
int *Double_Overlay;
int Holding_Buffer;
Double_Overlay = (int *) &x;
Holding_Buffer = Double_Overlay [0];
Double_Overlay [0] = htonl (Double_Overlay [1]);
Double_Overlay [1] = htonl (Holding_Buffer);
} else {
return;
}
}
static void htonf (float &x)
{
if ( sgIsLittleEndian() ) {
int *Float_Overlay;
int Holding_Buffer;
Float_Overlay = (int *) &x;
Holding_Buffer = Float_Overlay [0];
Float_Overlay [0] = htonl (Holding_Buffer);
} else {
return;
}
}
#endif
FGNativeGUI::FGNativeGUI() {
}
FGNativeGUI::~FGNativeGUI() {
}
// open hailing frequencies
bool FGNativeGUI::open() {
if ( is_enabled() ) {
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
<< "is already in use, ignoring" );
return false;
}
SGIOChannel *io = get_io_channel();
if ( ! io->open( get_direction() ) ) {
SG_LOG( SG_IO, SG_ALERT, "Error opening channel communication layer." );
return false;
}
set_enabled( true );
cur_fdm_state->_set_Sea_level_radius( SG_EQUATORIAL_RADIUS_FT );
return true;
}
void FGProps2NetGUI( FGNetGUI *net ) {
static SGPropertyNode *nav_freq
= fgGetNode("/instrumentation/nav/frequencies/selected-mhz", true);
static SGPropertyNode *nav_target_radial
= fgGetNode("/instrumentation/nav/radials/target-radial-deg", true);
static SGPropertyNode *nav_inrange
= fgGetNode("/instrumentation/nav/in-range", true);
static SGPropertyNode *nav_loc
= fgGetNode("/instrumentation/nav/nav-loc", true);
static SGPropertyNode *nav_gs_dist_signed
= fgGetNode("/instrumentation/nav/gs-distance", true);
static SGPropertyNode *nav_loc_dist
= fgGetNode("/instrumentation/nav/nav-distance", true);
static SGPropertyNode *nav_reciprocal_radial
= fgGetNode("/instrumentation/nav/radials/reciprocal-radial-deg", true);
static SGPropertyNode *nav_gs_deflection
= fgGetNode("/instrumentation/nav/gs-needle-deflection", true);
unsigned int i;
// Version sanity checking
net->version = FG_NET_GUI_VERSION;
// Aero parameters
net->longitude = cur_fdm_state->get_Longitude();
net->latitude = cur_fdm_state->get_Latitude();
net->altitude = cur_fdm_state->get_Altitude() * SG_FEET_TO_METER;
net->phi = cur_fdm_state->get_Phi();
net->theta = cur_fdm_state->get_Theta();
net->psi = cur_fdm_state->get_Psi();
// Velocities
net->vcas = cur_fdm_state->get_V_calibrated_kts();
net->climb_rate = cur_fdm_state->get_Climb_Rate();
// Consumables
net->num_tanks = FGNetGUI::FG_MAX_TANKS;
for ( i = 0; i < net->num_tanks; ++i ) {
SGPropertyNode *node = fgGetNode("/consumables/fuel/tank", i, true);
net->fuel_quantity[i] = node->getDoubleValue("level-gal_us");
}
// Environment
net->cur_time = globals->get_time_params()->get_cur_time();
net->warp = globals->get_warp();
net->ground_elev = cur_fdm_state->get_Runway_altitude_m();
// Approach
net->tuned_freq = nav_freq->getDoubleValue();
net->nav_radial = nav_target_radial->getDoubleValue();
net->in_range = nav_inrange->getBoolValue();
if ( nav_loc->getBoolValue() ) {
// is an ILS
net->dist_nm
= nav_gs_dist_signed->getDoubleValue()
* SG_METER_TO_NM;
} else {
// is a VOR
net->dist_nm = nav_loc_dist->getDoubleValue()
* SG_METER_TO_NM;
}
net->course_deviation_deg
= nav_reciprocal_radial->getDoubleValue()
- nav_target_radial->getDoubleValue();
if ( net->course_deviation_deg < -1000.0
|| net->course_deviation_deg > 1000.0 )
{
// Sanity check ...
net->course_deviation_deg = 0.0;
}
while ( net->course_deviation_deg > 180.0 ) {
net->course_deviation_deg -= 360.0;
}
while ( net->course_deviation_deg < -180.0 ) {
net->course_deviation_deg += 360.0;
}
if ( fabs(net->course_deviation_deg) > 90.0 )
net->course_deviation_deg
= ( net->course_deviation_deg<0.0
? -net->course_deviation_deg - 180.0
: -net->course_deviation_deg + 180.0 );
if ( nav_loc->getBoolValue() ) {
// is an ILS
net->gs_deviation_deg
= nav_gs_deflection->getDoubleValue()
/ 5.0;
} else {
// is an ILS
net->gs_deviation_deg = -9999.0;
}
#if defined( FG_USE_NETWORK_BYTE_ORDER )
// Convert the net buffer to network format
net->version = htonl(net->version);
htond(net->longitude);
htond(net->latitude);
htonf(net->altitude);
htonf(net->phi);
htonf(net->theta);
htonf(net->psi);
htonf(net->vcas);
htonf(net->climb_rate);
for ( i = 0; i < net->num_tanks; ++i ) {
htonf(net->fuel_quantity[i]);
}
net->num_tanks = htonl(net->num_tanks);
net->cur_time = htonl( net->cur_time );
net->warp = htonl( net->warp );
net->ground_elev = htonl( net->ground_elev );
htonf(net->tuned_freq);
htonf(net->nav_radial);
net->in_range = htonl( net->in_range );
htonf(net->dist_nm);
htonf(net->course_deviation_deg);
htonf(net->gs_deviation_deg);
#endif
}
void FGNetGUI2Props( FGNetGUI *net ) {
unsigned int i;
#if defined( FG_USE_NETWORK_BYTE_ORDER )
// Convert to the net buffer from network format
net->version = ntohl(net->version);
htond(net->longitude);
htond(net->latitude);
htonf(net->altitude);
htonf(net->phi);
htonf(net->theta);
htonf(net->psi);
htonf(net->vcas);
htonf(net->climb_rate);
net->num_tanks = htonl(net->num_tanks);
for ( i = 0; i < net->num_tanks; ++i ) {
htonf(net->fuel_quantity[i]);
}
net->cur_time = ntohl(net->cur_time);
net->warp = ntohl(net->warp);
net->ground_elev = htonl( net->ground_elev );
htonf(net->tuned_freq);
htonf(net->nav_radial);
net->in_range = htonl( net->in_range );
htonf(net->dist_nm);
htonf(net->course_deviation_deg);
htonf(net->gs_deviation_deg);
#endif
if ( net->version == FG_NET_GUI_VERSION ) {
// cout << "pos = " << net->longitude << " " << net->latitude << endl;
// cout << "sea level rad = " << cur_fdm_state->get_Sea_level_radius()
// << endl;
cur_fdm_state->_updateGeodeticPosition( net->latitude,
net->longitude,
net->altitude
* SG_METER_TO_FEET );
cur_fdm_state->_set_Euler_Angles( net->phi,
net->theta,
net->psi );
cur_fdm_state->_set_V_calibrated_kts( net->vcas );
cur_fdm_state->_set_Climb_Rate( net->climb_rate );
for (i = 0; i < net->num_tanks; ++i ) {
SGPropertyNode * node
= fgGetNode("/consumables/fuel/tank", i, true);
node->setDoubleValue("level-gal_us", net->fuel_quantity[i] );
}
if ( net->cur_time ) {
fgSetLong("/sim/time/cur-time-override", net->cur_time);
}
globals->set_warp( net->warp );
// Approach
fgSetDouble( "/instrumentation/nav[0]/frequencies/selected-mhz",
net->tuned_freq );
fgSetBool( "/instrumentation/nav[0]/in-range", net->in_range );
fgSetDouble( "/instrumentation/dme/distance-nm", net->dist_nm );
fgSetDouble( "/instrumentation/nav[0]/heading-needle-deflection",
net->course_deviation_deg );
fgSetDouble( "/instrumentation/nav[0]/gs-needle-deflection",
net->gs_deviation_deg );
} else {
SG_LOG( SG_IO, SG_ALERT,
"Error: version mismatch in FGNetNativeGUI2Props()" );
SG_LOG( SG_IO, SG_ALERT,
"\tread " << net->version << " need " << FG_NET_GUI_VERSION );
SG_LOG( SG_IO, SG_ALERT,
"\tNeed to upgrade net_fdm.hxx and recompile." );
}
}
// process work for this port
bool FGNativeGUI::process() {
SGIOChannel *io = get_io_channel();
int length = sizeof(buf);
if ( get_direction() == SG_IO_OUT ) {
// cout << "size of cur_fdm_state = " << length << endl;
FGProps2NetGUI( &buf );
if ( ! io->write( (char *)(& buf), length ) ) {
SG_LOG( SG_IO, SG_ALERT, "Error writing data." );
return false;
}
} else if ( get_direction() == SG_IO_IN ) {
if ( io->get_type() == sgFileType ) {
if ( io->read( (char *)(& buf), length ) == length ) {
SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
FGNetGUI2Props( &buf );
}
} else {
while ( io->read( (char *)(& buf), length ) == length ) {
SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
FGNetGUI2Props( &buf );
}
}
}
return true;
}
// close the channel
bool FGNativeGUI::close() {
SGIOChannel *io = get_io_channel();
set_enabled( false );
if ( ! io->close() ) {
return false;
}
return true;
}