1
0
Fork 0

Finish 2021-carriers-and-ai-part-1-towers

Carrier improvements

- Calculate lineup deviation (degrees left/right)
- Position for touchdown added (for more accurate lineup and glideslope deviation checks)
- LSO position and Tower position added (for views)
- Better logic for controlling the FLOLS
- Added ability to start on a specific course (works better
  with the launcher if the carrier starts on a recovery course
  when positioning in air for recovery (approach)
- Support for normal, tower, LSO views (via controls/view-index)
- Aircraft can define offset for FLOLS in sim/model/reference-offset-{xyz}

Added the ability to find the nearest carrier to use as a tower

Rework of the tower position so that it updates frequently to support moving towers.

TODO: Need to review how to better implement/integrate 'sub-views' i.e. ai/models/carrier[]/controls/view-index which is actually a sub index for the tower view.
This commit is contained in:
Richard Harrison 2021-04-16 22:02:11 +02:00
parent 303e518e87
commit 522d7e8450
13 changed files with 552 additions and 178 deletions

View file

@ -897,6 +897,22 @@ bool FGAIBase::getGroundElevationM(const SGGeod& pos, double& elev,
_model.get());
}
SGPropertyNode* FGAIBase::getPositionFromNode(SGPropertyNode* scFileNode, const std::string &key, SGVec3d &position) {
SGPropertyNode* positionNode = scFileNode->getChild(key);
if (positionNode) {
// Transform to the right coordinate frame, configuration is done in
// the usual x-back, y-right, z-up coordinates, computations
// in the simulation usual body x-forward, y-right, z-down coordinates
position(0) = -positionNode->getDoubleValue("x-offset-m", 0);
position(1) = positionNode->getDoubleValue("y-offset-m", 0);
position(2) = -positionNode->getDoubleValue("z-offset-m", 0);
return positionNode;
}
else
position = SGVec3d::zeros();
return nullptr;
}
double FGAIBase::_getCartPosX() const {
SGVec3d cartPos = getCartPos();
return cartPos.x();

View file

@ -136,6 +136,7 @@ public:
bool getGroundElevationM(const SGGeod& pos, double& elev,
const simgear::BVHMaterial** material) const;
SGPropertyNode* getPositionFromNode(SGPropertyNode* scFileNode, const std::string& key, SGVec3d& position);
double getTrueHeadingDeg() const
{

View file

@ -30,16 +30,59 @@
#include <Main/util.hxx>
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Main/util.hxx>
#include "AICarrier.hxx"
#include "AINotifications.hxx"
FGAICarrier::FGAICarrier() :
FGAIShip(otCarrier),
deck_altitude(65.0065)
FGAICarrier::FGAICarrier() : FGAIShip(otCarrier),
deck_altitude_ft(65.0065),
AIControl(false),
MPControl(false),
angle(0),
base_course(0),
base_speed(0),
dist(0),
elevators(false),
in_to_wind(false),
jbd(false),
jbd_pos_norm(0),
jbd_time_constant(0),
jbd_transition_time(0),
lineup(0),
max_lat(0),
max_long(0),
min_lat(0),
min_long(0),
pos_norm(0),
raw_jbd_pos_norm(0),
raw_pos_norm(0),
rel_wind(0),
rel_wind_from_deg(0),
rel_wind_speed_kts(0),
returning(false),
source(0),
time_constant(0),
transition_time(0),
turn_to_base_course(true),
turn_to_recovery_hdg(true),
turn_to_launch_hdg(true),
view_index(0),
wave_off_lights_demand(false),
wind_from_deg(0),
wind_from_east(0),
wind_from_north(0),
wind_speed_kts(0)
{
simgear::Emesary::GlobalTransmitter::instance()->Register(this);
}
FGAICarrier::~FGAICarrier() = default;
FGAICarrier::~FGAICarrier()
{
simgear::Emesary::GlobalTransmitter::instance()->DeRegister(this);
}
void FGAICarrier::readFromScenario(SGPropertyNode* scFileNode) {
if (!scFileNode)
@ -49,7 +92,7 @@ void FGAICarrier::readFromScenario(SGPropertyNode* scFileNode) {
setRadius(scFileNode->getDoubleValue("turn-radius-ft", 2000));
setSign(scFileNode->getStringValue("pennant-number"));
setDeckAltitude(scFileNode->getDoubleValue("deck-altitude"));
setDeckAltitudeFt(scFileNode->getDoubleValue("deck-altitude"));
setWind_from_east(scFileNode->getDoubleValue("wind_from_east", 0));
setWind_from_north(scFileNode->getDoubleValue("wind_from_north", 0));
setTACANChannelID(scFileNode->getStringValue("TACAN-channel-ID", "029Y"));
@ -60,21 +103,35 @@ void FGAICarrier::readFromScenario(SGPropertyNode* scFileNode) {
setMPControl(scFileNode->getBoolValue("mp-control", false));
setAIControl(scFileNode->getBoolValue("ai-control", false));
setCallSign(scFileNode->getStringValue("callsign", ""));
angled_deck_degrees = scFileNode->getDoubleValue("angled-deck-degrees", -8.5);
SGPropertyNode* flolsNode = getPositionFromNode(scFileNode, "flols-pos", _flolsPosOffset);
if (flolsNode) {
_flolsHeadingOffsetDeg = flolsNode->getDoubleValue("heading-offset-deg", 0.0);
_flolsApproachAngle = flolsNode->getDoubleValue("glidepath-angle-deg", 3.5);
}
else {
_flolsPosOffset(2) = -(deck_altitude_ft * SG_FEET_TO_METER + 10);
}
//// the FLOLS (or IFLOLS) position doesn't produce an accurate angle;
//// so to fix this we can definition the touchdown position which
//// is the centreline of the 3rd wire
SGPropertyNode* flols = scFileNode->getChild("flols-pos");
if (flols) {
// Transform to the right coordinate frame, configuration is done in
// the usual x-back, y-right, z-up coordinates, computations
// in the simulation usual body x-forward, y-right, z-down coordinates
_flolsPosOffset(0) = - flols->getDoubleValue("x-offset-m", 0);
_flolsPosOffset(1) = flols->getDoubleValue("y-offset-m", 0);
_flolsPosOffset(2) = - flols->getDoubleValue("z-offset-m", 0);
_flolsTouchdownPosition = _flolsPosOffset; // default to the flolsPosition
getPositionFromNode(scFileNode, "flols-touchdown-position", _flolsTouchdownPosition);
if (!getPositionFromNode(scFileNode, "tower-position", _towerPosition)) {
_towerPosition(2) = -(deck_altitude_ft * SG_FEET_TO_METER + 10);
SG_LOG(SG_AI, SG_INFO, "AICarrier: tower-position not defined - using default");
}
if (!getPositionFromNode(scFileNode, "lso-position", _lsoPosition)){
_lsoPosition(2) = -(deck_altitude_ft * SG_FEET_TO_METER + 10);
SG_LOG(SG_AI, SG_INFO, "AICarrier: lso-position not defined - using default");
}
_flolsHeadingOffsetDeg = flols->getDoubleValue("heading-offset-deg", 0.0);
_flolsApproachAngle = flols->getDoubleValue("glidepath-angle-deg", 3.5);
} else
_flolsPosOffset = SGVec3d::zeros();
std::vector<SGPropertyNode_ptr> props = scFileNode->getChildren("parking-pos");
std::vector<SGPropertyNode_ptr>::const_iterator it;
@ -117,8 +174,8 @@ void FGAICarrier::setMinLong(double deg) {
}
void FGAICarrier::setDeckAltitude(const double altitude_feet) {
deck_altitude = altitude_feet;
void FGAICarrier::setDeckAltitudeFt(const double altitude_feet) {
deck_altitude_ft = altitude_feet;
}
void FGAICarrier::setSign(const string& s) {
@ -171,12 +228,12 @@ void FGAICarrier::update(double dt) {
SGQuatd hl2body = SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
// and postrotate the orientation of the AIModel wrt the horizontal
// local frame
SGQuatd ec2body = ec2hl*hl2body;
SGQuatd ec2body = ec2hl * hl2body;
// The cartesian position of the carrier in the wgs84 world
SGVec3d cartPos = SGVec3d::fromGeod(pos);
// The position of the eyepoint - at least near that ...
SGVec3d eyePos(globals->get_view_position_cart());
SGVec3d eyePos(globals->get_ownship_reference_position_cart());
// Add the position offset of the AIModel to gain the earth
// centered position
SGVec3d eyeWrtCarrier = eyePos - cartPos;
@ -185,16 +242,71 @@ void FGAICarrier::update(double dt) {
// the eyepoints vector wrt the flols position
SGVec3d eyeWrtFlols = eyeWrtCarrier - _flolsPosOffset;
SGVec3d flols_location = getCartPosAt(_flolsPosOffset);
// the distance from the eyepoint to the flols
dist = norm(eyeWrtFlols);
// lineup (left/right) - stern lights and Carrier landing system (Aircraft/Generic/an_spn_46.nas)
double lineup_hdg, lineup_az2, lineup_s;
SGGeod g_eyePos = SGGeod::fromCart(eyePos);
SGGeod g_carrier = SGGeod::fromCart(cartPos);
//
// set the view as requested by control/view-index.
SGGeod viewPosition;
switch (view_index) {
default:
case 0:
viewPosition = SGGeod::fromCart(getCartPosAt(_towerPosition));
break;
case 1:
viewPosition = SGGeod::fromCart(getCartPosAt(_flolsTouchdownPosition));
break;
case 2:
viewPosition = SGGeod::fromCart(getCartPosAt(_lsoPosition));
break;
}
_view_position_lat_deg_node->setDoubleValue(viewPosition.getLatitudeDeg());
_view_position_lon_deg_node->setDoubleValue(viewPosition.getLongitudeDeg());
_view_position_alt_ft_node->setDoubleValue(viewPosition.getElevationFt());
SGGeodesy::inverse(g_carrier, g_eyePos, lineup_hdg, lineup_az2, lineup_s);
double target_lineup = _getHeading() + angled_deck_degrees + 180.0;
SG_NORMALIZE_RANGE(target_lineup, 0.0, 360.0);
lineup = lineup_hdg - target_lineup;
// now the angle, positive angles are upwards
if (fabs(dist) < SGLimits<double>::min()) {
angle = 0;
angle = 0;
} else {
double sAngle = -eyeWrtFlols(2)/dist;
sAngle = SGMiscd::min(1, SGMiscd::max(-1, sAngle));
angle = SGMiscd::rad2deg(asin(sAngle));
double sAngle = -eyeWrtFlols(2) / dist;
sAngle = SGMiscd::min(1, SGMiscd::max(-1, sAngle));
angle = SGMiscd::rad2deg(asin(sAngle));
}
if (dist < 8000){
SGVec3d eyeWrtFlols_tdp = eyeWrtCarrier - _flolsTouchdownPosition;
// the distance from the eyepoint to the flols
double dist_tdp = norm(eyeWrtFlols_tdp);
double angle_tdp = 0;
// now the angle, positive angles are upwards
if (fabs(dist_tdp) < SGLimits<double>::min()) {
angle_tdp = 0;
}
else {
double sAngle = -eyeWrtFlols_tdp(2) / dist_tdp;
sAngle = SGMiscd::min(1, SGMiscd::max(-1, sAngle));
angle_tdp = SGMiscd::rad2deg(asin(sAngle));
}
// printf("angle %5.2f td angle %5.2f \n", angle, angle_tdp);
//angle += 1.481; // adjust for FLOLS offset (measured on Nimitz class)
}
// set the value of source
@ -212,6 +324,28 @@ void FGAICarrier::update(double dt) {
source = 6;
else
source = 0;
// only bother with waveoff FLOLS when ownship within a reasonable range.
// red ball is <= 3.075 to 2.65, below this is off. above this is orange.
// only do this when within ~1.8nm
if (dist < 3200) {
if (dist > 100) {
bool new_wave_off_lights_demand = (angle <= 3.0);
if (new_wave_off_lights_demand != wave_off_lights_demand) {
// start timing when the lights come up.
wave_off_lights_demand = new_wave_off_lights_demand;
}
//// below 1degrees close in is to low to continue; wave them off.
if (angle < 2 && dist < 800) {
wave_off_lights_demand = true;
}
}
}
else {
wave_off_lights_demand = true; // sensible default when very far away.
}
} //end update
bool FGAICarrier::init(ModelSearchOrder searchOrder) {
@ -230,9 +364,24 @@ bool FGAICarrier::init(ModelSearchOrder searchOrder) {
fgGetNode("/environment/config/boundary/entry[0]/wind-speed-kt", true);
turn_to_launch_hdg = false;
turn_to_recovery_hdg = false;
turn_to_base_course = true;
int dmd_course = fgGetInt("/sim/presets/carrier-course");
if (dmd_course == 2) {
// launch
turn_to_launch_hdg = true;
turn_to_recovery_hdg = false;
turn_to_base_course = false;
} else if (dmd_course == 3) {
// recovery
turn_to_launch_hdg = false;
turn_to_recovery_hdg = true;
turn_to_base_course = false;
} else {
// default to base
turn_to_launch_hdg = false;
turn_to_recovery_hdg = false;
turn_to_base_course = true;
}
returning = false;
in_to_wind = false;
@ -251,12 +400,12 @@ bool FGAICarrier::init(ModelSearchOrder searchOrder) {
return true;
}
void FGAICarrier::bind() {
void FGAICarrier::bind(){
FGAIShip::bind();
props->untie("velocities/true-airspeed-kt");
props->getNode("position/deck-altitude-feet", true)->setDoubleValue(deck_altitude);
props->getNode("position/deck-altitude-feet", true)->setDoubleValue(deck_altitude_ft);
tie("controls/flols/source-lights",
SGRawValuePointer<int>(&source));
@ -264,6 +413,8 @@ void FGAICarrier::bind() {
SGRawValuePointer<double>(&dist));
tie("controls/flols/angle-degs",
SGRawValuePointer<double>(&angle));
tie("controls/flols/lineup-degs",
SGRawValuePointer<double>(&lineup));
tie("controls/turn-to-launch-hdg",
SGRawValuePointer<bool>(&turn_to_launch_hdg));
tie("controls/in-to-wind",
@ -292,8 +443,8 @@ void FGAICarrier::bind() {
SGRawValuePointer<double>(&rel_wind_speed_kts));
tie("environment/in-to-wind",
SGRawValuePointer<bool>(&in_to_wind));
//tie("controls/flols/wave-off-lights",
// SGRawValuePointer<bool>(&wave_off_lights));
tie("controls/flols/wave-off-lights-demand",
SGRawValuePointer<bool>(&wave_off_lights_demand));
tie("controls/elevators",
SGRawValuePointer<bool>(&elevators));
tie("surface-positions/elevators-pos-norm",
@ -315,8 +466,11 @@ void FGAICarrier::bind() {
tie("controls/turn-to-base-course",
SGRawValuePointer<bool>(&turn_to_base_course));
tie("controls/view-index", SGRawValuePointer<int>(&view_index));
props->setBoolValue("controls/flols/cut-lights", false);
props->setBoolValue("controls/flols/wave-off-lights", false);
props->setBoolValue("controls/flols/wave-off-lights-emergency", false);
props->setBoolValue("controls/flols/cond-datum-lights", true);
props->setBoolValue("controls/crew", false);
props->setStringValue("navaids/tacan/channel-ID", TACAN_channel_id.c_str());
@ -324,6 +478,14 @@ void FGAICarrier::bind() {
props->setBoolValue("controls/lighting/deck-lights", false);
props->setDoubleValue("controls/lighting/flood-lights-red-norm", 0);
_flols_x_node = props->getNode("position/flols-x", true);
_flols_y_node = props->getNode("position/flols-y", true);
_flols_z_node = props->getNode("position/flols-z", true);
_view_position_lat_deg_node = props->getNode("position/view-position-lat", true);
_view_position_lon_deg_node = props->getNode("position/view-position-lon", true);
_view_position_alt_ft_node = props->getNode("position/view-position-alt", true);
// Write out a list of the parking positions - useful for the UI to select
// from
for (const auto& ppos : ppositions) {
@ -709,3 +871,23 @@ void FGAICarrier::extractCarriersFromScenario(SGPropertyNode_ptr xmlNode, SGProp
}
}
}
simgear::Emesary::ReceiptStatus FGAICarrier::Receive(simgear::Emesary::INotificationPtr n)
{
auto nctn = dynamic_pointer_cast<NearestCarrierToNotification>(n);
if (nctn) {
if (!nctn->GetCarrier() || nctn->GetDistanceMeters() > nctn->GetDistanceToMeters(pos)) {
nctn->SetCarrier(this, &pos);
nctn->SetViewPositionLatNode(_view_position_lat_deg_node);
nctn->SetViewPositionLonNode(_view_position_lon_deg_node);
nctn->SetViewPositionAltNode(_view_position_alt_ft_node);
nctn->SetDeckheight(deck_altitude_ft);
nctn->SetHeading(hdg);
nctn->SetVckts(speed);
nctn->SetCarrierIdent(this->_getName());
}
return simgear::Emesary::ReceiptStatus::OK;
}
return simgear::Emesary::ReceiptStatus::NotProcessed;
}

View file

@ -25,6 +25,7 @@
#include <list>
#include <simgear/compiler.h>
#include <simgear/emesary/Emesary.hxx>
using std::string;
using std::list;
@ -37,7 +38,8 @@ using std::list;
class FGAIManager;
class FGAICarrier;
class FGAICarrier : public FGAIShip {
class FGAICarrier : public FGAIShip, simgear::Emesary::IReceiver
{
public:
FGAICarrier();
@ -46,7 +48,7 @@ public:
void readFromScenario(SGPropertyNode* scFileNode) override;
void setSign(const string& );
void setDeckAltitude(const double altitude_feet);
void setDeckAltitudeFt(const double altitude_feet);
void setTACANChannelID(const string &);
double getDefaultModelRadius() override { return 350.0; }
@ -91,6 +93,9 @@ public:
bool getFLOLSPositionHeading(SGGeod &pos, double &heading) const;
double getFLOLFSGlidepathAngleDeg() const;
double getDeckAltitudeFt() const { return deck_altitude_ft; }
virtual simgear::Emesary::ReceiptStatus Receive(simgear::Emesary::INotificationPtr n) override;
private:
/// Is sufficient to be private, stores a possible position to place an
/// aircraft on start
@ -116,16 +121,20 @@ private:
string sign; // The sign of this carrier.
// these describe the flols
SGVec3d _flolsPosOffset;
SGVec3d _flolsPosOffset, _flolsTouchdownPosition, _towerPosition, _lsoPosition;
double _flolsHeadingOffsetDeg = 0.0; ///< angle in degrees offset from the carrier centerline
double _flolsApproachAngle = 3.0; ///< glidepath angle for the FLOLS
double dist; // the distance of the eyepoint from the flols
double angle;
double deck_altitude;
double deck_altitude_ft;
double lineup; // lineup angle deviation from carrier;
int source; // the flols light which is visible at the moment
bool in_to_wind;
// when waveoff should be requested.
bool wave_off_lights_demand;
// these are for maneuvering the carrier
SGGeod mOpBoxPos;
@ -134,6 +143,7 @@ private:
double rel_wind;
double max_lat, min_lat, max_long, min_long;
double base_course, base_speed;
double angled_deck_degrees; // angled deck offset from carrier heading. usually negative
bool turn_to_launch_hdg;
bool turn_to_recovery_hdg;
@ -142,6 +152,7 @@ private:
bool InToWind(); // set if the carrier is in to wind
bool MPControl, AIControl;
int view_index;
SGPropertyNode_ptr _longitude_node;
SGPropertyNode_ptr _latitude_node;
@ -149,10 +160,18 @@ private:
SGPropertyNode_ptr _surface_wind_from_deg_node;
SGPropertyNode_ptr _surface_wind_speed_node;
SGPropertyNode_ptr _launchbar_state_node;
SGPropertyNode_ptr _flols_x_node;
SGPropertyNode_ptr _flols_y_node;
SGPropertyNode_ptr _flols_z_node;
// this is for tacan
string TACAN_channel_id;
SGPropertyNode_ptr _view_position_lat_deg_node;
SGPropertyNode_ptr _view_position_lon_deg_node;
SGPropertyNode_ptr _view_position_alt_ft_node;
// these are for moving the elevators
void UpdateElevator( double dt, double transition_time);
double pos_norm, raw_pos_norm;

View file

@ -0,0 +1,102 @@
// Emesary notifications for AI system.
//
// Richard Harrison; April 2020.
//
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef _FG_AINOTIFICATIONS_HXX
#define _FG_AINOTIFICATIONS_HXX
#include <simgear/emesary/Emesary.hxx>
#include <simgear/math/SGMath.hxx>
class NearestCarrierToNotification : public simgear::Emesary::INotification
{
public:
NearestCarrierToNotification(SGGeod _comparisonPosition) : position(),
comparisonPosition(_comparisonPosition),
distanceMeters(std::numeric_limits<double>::max()),
carrier(0),
deckheight(0),
heading(0),
vckts(0)
{
}
/*virtual ~NearestCarrierToNotification()
{
if (position)
delete position;
position = 0;
}*/
const char* GetType() override { return "NearestCarrierToNotification"; }
const SGGeod* GetPosition() const { return position; }
double GetHeading() const { return heading; }
double GetVckts() const { return vckts; }
double GetDeckheight() const { return deckheight; }
const class FGAICarrier* GetCarrier() const { return carrier; }
double GetDistanceMeters() const { return distanceMeters; }
std::string GetCarrierIdent() const { return carrierIdent; }
double GetDistanceToMeters(const SGGeod& pos) const
{
if (carrier)
return SGGeodesy::distanceM(comparisonPosition, pos);
else
return std::numeric_limits<double>::max()-1;
}
void SetPosition(SGGeod* _position) { position = _position; }
void SetHeading(double _heading) { heading = _heading; }
void SetVckts(double _vckts) { vckts = _vckts; }
void SetDeckheight(double _deckheight) { deckheight = _deckheight; }
void SetCarrier(FGAICarrier* _carrier, SGGeod *_position)
{
carrier = _carrier;
distanceMeters = SGGeodesy::distanceM(comparisonPosition, *_position);
position = _position;
}
void SetDistanceMeters(double _distanceMeters) { distanceMeters = _distanceMeters; }
void SetCarrierIdent(std::string _carrierIdent) { carrierIdent = _carrierIdent; }
SGPropertyNode_ptr GetViewPositionLatNode() { return viewPositionLatDegNode; }
SGPropertyNode_ptr GetViewPositionLonNode() { return viewPositionLonDegNode; }
SGPropertyNode_ptr GetViewPositionAltNode() { return viewPositionAltFtNode; }
void SetViewPositionLatNode(SGPropertyNode_ptr _viewPositionLatNode) { viewPositionLatDegNode = _viewPositionLatNode; }
void SetViewPositionLonNode(SGPropertyNode_ptr _viewPositionLonNode) { viewPositionLonDegNode = _viewPositionLonNode; }
void SetViewPositionAltNode(SGPropertyNode_ptr _viewPositionAltNode) { viewPositionAltFtNode = _viewPositionAltNode; }
protected:
SGGeod *position;
SGGeod comparisonPosition;
SGPropertyNode_ptr viewPositionLatDegNode;
SGPropertyNode_ptr viewPositionLonDegNode;
SGPropertyNode_ptr viewPositionAltFtNode;
double heading;
double vckts;
double deckheight;
double distanceMeters;
std::string carrierIdent;
class FGAICarrier* carrier;
};
#endif

View file

@ -36,6 +36,7 @@ set(HEADERS
AIGroundVehicle.hxx
AIManager.hxx
AIMultiplayer.hxx
AINotifications.hxx
AIShip.hxx
AIStatic.hxx
AIStorm.hxx

View file

@ -51,6 +51,8 @@
#include "climate.hxx"
#include "magvarmanager.hxx"
#include "AIModel/AINotifications.hxx"
class FG3DCloudsListener : public SGPropertyChangeListener {
public:
FG3DCloudsListener( FGClouds * fgClouds );
@ -275,74 +277,139 @@ FGEnvironmentMgr::update (double dt)
_cloudLayersDirty = false;
fgClouds->set_update_event( fgClouds->get_update_event()+1 );
}
updateTowerPosition();
fgSetDouble( "/environment/gravitational-acceleration-mps2",
Environment::Gravity::instance()->getGravity(aircraftPos));
}
void
FGEnvironmentMgr::updateClosestAirport()
void FGEnvironmentMgr::updateTowerPosition()
{
SG_LOG(SG_ENVIRONMENT, SG_DEBUG, "FGEnvironmentMgr::update: updating closest airport");
if (towerViewPositionLatDegNode != nullptr && towerViewPositionLonDegNode != nullptr && towerViewPositionAltFtNode != nullptr) {
auto automaticTowerActive = fgGetBool("/sim/tower/auto-position", true);
SGGeod pos = globals->get_aircraft_position();
FGAirport * nearestAirport = FGAirport::findClosest(pos, 100.0);
if( nearestAirport == NULL )
{
SG_LOG(SG_ENVIRONMENT,SG_INFO,"FGEnvironmentMgr::update: No airport within 100NM range");
}
else
{
const string currentId = fgGetString("/sim/airport/closest-airport-id", "");
if (currentId != nearestAirport->ident())
{
SG_LOG(SG_ENVIRONMENT, SG_INFO, "FGEnvironmentMgr::updateClosestAirport: selected:" << nearestAirport->ident());
fgSetString("/sim/airport/closest-airport-id",
nearestAirport->ident().c_str());
}
}
{
/* If we are viewing a multiplayer aircraft, find nearest airport so that
Tower View etc works. */
std::string view_config_root = ViewPropertyEvaluator::getStringValue("(/sim/view[(/sim/current-view/view-number-raw)]/config/root)");
if (view_config_root != "/" && view_config_root != "") {
/* We are currently viewing a multiplayer aircraft. */
SGGeod pos = SGGeod::fromDegFt(
ViewPropertyEvaluator::getDoubleValue("((/sim/view[(/sim/current-view/view-number-raw)]/config/root)/position/longitude-deg)"),
ViewPropertyEvaluator::getDoubleValue("((/sim/view[(/sim/current-view/view-number-raw)]/config/root)/position/latitude-deg)"),
ViewPropertyEvaluator::getDoubleValue("((/sim/view[(/sim/current-view/view-number-raw)]/config/root)/position/altitude-ft)")
);
FGAirport * nearestAirport = FGAirport::findClosest(pos, 100.0);
if (nearestAirport) {
std::string path = ViewPropertyEvaluator::getStringValue("(/sim/view[(/sim/current-view/view-number-raw)]/config/root)/sim/tower/");
fgSetString(path + "airport-id", nearestAirport->getId());
if (nearestAirport->hasTower()) {
SGGeod tower_pos = nearestAirport->getTowerLocation();
fgSetDouble(path + "latitude-deg", tower_pos.getLatitudeDeg());
fgSetDouble(path + "longitude-deg", tower_pos.getLongitudeDeg());
fgSetDouble(path + "altitude-ft", tower_pos.getElevationFt());
SG_LOG(SG_ENVIRONMENT, SG_DEBUG, "airport-id=" << nearestAirport->getId() << " tower_pos=" << tower_pos);
fgSetDouble("/sim/airport/nearest-tower-latitude-deg", towerViewPositionLatDegNode->getDoubleValue());
fgSetDouble("/sim/airport/nearest-tower-longitude-deg", towerViewPositionLonDegNode->getDoubleValue());
fgSetDouble("/sim/airport/nearest-tower-altitude-ft", towerViewPositionAltFtNode->getDoubleValue());
if (automaticTowerActive) {
fgSetDouble("/sim/tower/latitude-deg", towerViewPositionLatDegNode->getDoubleValue());
fgSetDouble("/sim/tower/longitude-deg", towerViewPositionLonDegNode->getDoubleValue());
fgSetDouble("/sim/tower/altitude-ft", towerViewPositionAltFtNode->getDoubleValue());
}
else {
/* Use location of airport. */
fgSetDouble(path + "latitude-deg", nearestAirport->getLatitude());
fgSetDouble(path + "longitude-deg", nearestAirport->getLongitude());
fgSetDouble(path + "altitude-ft", nearestAirport->getElevation() + 20);
SG_LOG(SG_ENVIRONMENT, SG_DEBUG, "no tower for airport-id=" << nearestAirport->getId());
}
}
else {
SG_LOG(SG_ENVIRONMENT,SG_DEBUG,"FGEnvironmentMgr::update: No airport within 100NM range of current multiplayer aircraft");
}
}
}
}
void FGEnvironmentMgr::updateClosestAirport()
{
SG_LOG(SG_ENVIRONMENT, SG_DEBUG, "FGEnvironmentMgr::update: updating closest airport");
SGGeod pos = globals->get_aircraft_position();
//
// If we are viewing a multiplayer aircraft, find nearest airport so that
// Tower View etc works.
std::string view_config_root = ViewPropertyEvaluator::getStringValue("(/sim/view[(/sim/current-view/view-number-raw)]/config/root)");
if (view_config_root != "/" && view_config_root != "") {
/* We are currently viewing a multiplayer aircraft. */
pos = SGGeod::fromDegFt(
ViewPropertyEvaluator::getDoubleValue("((/sim/view[(/sim/current-view/view-number-raw)]/config/root)/position/longitude-deg)"),
ViewPropertyEvaluator::getDoubleValue("((/sim/view[(/sim/current-view/view-number-raw)]/config/root)/position/latitude-deg)"),
ViewPropertyEvaluator::getDoubleValue("((/sim/view[(/sim/current-view/view-number-raw)]/config/root)/position/altitude-ft)"));
}
// nearest tower logic;
// 1. find nearest airport
// 2. find nearest carrier
// - select the nearest one as the tower.
nearestAirport = FGAirport::findClosest(pos, 100.0);
auto automaticTowerActive = fgGetBool("/sim/tower/auto-position", true);
SGGeod nearestTowerPosition;
bool nearestTowerPositionValid = false;
std::string nearestIdent;
const SGGeod airportGeod;
double towerDistance = numeric_limits<double>::max();
if (nearestAirport) {
const string currentId = fgGetString("/sim/airport/closest-airport-id", "");
if (currentId != nearestAirport->ident()) {
SG_LOG(SG_ENVIRONMENT, SG_INFO, "FGEnvironmentMgr::updateClosestAirport: selected:" << nearestAirport->ident());
fgSetString("/sim/airport/closest-airport-id", nearestAirport->ident().c_str());
}
if (nearestAirport->hasTower())
nearestTowerPosition = nearestAirport->getTowerLocation();
else
nearestTowerPosition = nearestAirport->geod();
nearestIdent = nearestAirport->ident();
nearestTowerPositionValid = true;
towerDistance = SGGeodesy::distanceM(nearestTowerPosition, pos);
// when the tower doesn't move we can clear these.
// if the carrier is nearer these variables will be set in that logic.
towerViewPositionLatDegNode = towerViewPositionLonDegNode = towerViewPositionAltFtNode = nullptr;
}
else {
SG_LOG(SG_ENVIRONMENT, SG_WARN, "FGEnvironmentMgr::update: No airport within 100NM range");
}
auto nctn = SGSharedPtr< NearestCarrierToNotification> (new NearestCarrierToNotification(pos));
if (simgear::Emesary::ReceiptStatus::OK == simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(nctn)) {
SG_LOG(SG_ENVIRONMENT, SG_INFO, "Nearest carrier " << nctn->GetCarrierIdent() << " at a distance of " << nctn->GetDistanceMeters());
if (nearestCarrier != nctn->GetCarrier()) {
nearestCarrier = nctn->GetCarrier();
fgSetString("/sim/airport/nearest-carrier", nctn->GetCarrierIdent());
}
} else {
SG_LOG(SG_ENVIRONMENT, SG_INFO, "No carriers found");
fgSetString("/sim/airport/nearest-carrier", "");
fgSetDouble("/sim/airport/nearest-carrier-latitude-deg", 0);
fgSetDouble("/sim/airport/nearest-carrier-longitude-deg", 0);
fgSetDouble("/sim/airport/nearest-carrier-altitude-ft", 0);
fgSetDouble("/sim/airport/nearest-carrier-deck-height", 0);
nearestCarrier = nullptr;
}
if (nearestCarrier != nullptr) {
SGGeod carrierGeod(*nctn->GetPosition());
// figure out if the carrier's tower is closer
if (!nearestTowerPositionValid || nctn->GetDistanceMeters() < towerDistance) {
nearestTowerPosition = carrierGeod;
nearestIdent = nctn->GetCarrierIdent();
nearestTowerPositionValid = true;
//
// these will be used to determine and update the tower position
towerViewPositionLatDegNode = nctn->GetViewPositionLatNode();
towerViewPositionLonDegNode = nctn->GetViewPositionLonNode();
towerViewPositionAltFtNode = nctn->GetViewPositionAltNode();
}
// although the carrier is moving - these values can afford to be 10 seconds old so we don't need to
// update them.
fgSetDouble("/sim/airport/nearest-carrier-latitude-deg", nctn->GetPosition()->getLatitudeDeg());
fgSetDouble("/sim/airport/nearest-carrier-longitude-deg", nctn->GetPosition()->getLongitudeDeg());
fgSetDouble("/sim/airport/nearest-carrier-altitude-ft", nctn->GetPosition()->getElevationFt());
fgSetDouble("/sim/airport/nearest-carrier-deck-height", nctn->GetDeckheight());
}
if (fgGetString("/sim/airport/nearest-tower-ident") != nearestIdent) {
SG_LOG(SG_ENVIRONMENT, SG_ALERT, "Nearest airport tower now " << nearestIdent);
fgSetString("/sim/airport/nearest-tower-ident", nearestIdent);
}
if (automaticTowerActive) {
if (fgGetString("/sim/tower/airport-id") != nearestIdent) {
fgSetString("/sim/tower/airport-id", nearestIdent);
SG_LOG(SG_ENVIRONMENT, SG_INFO, "Auto Tower: now " << nearestIdent);
}
}
updateTowerPosition();
}
FGEnvironment
FGEnvironmentMgr::getEnvironment () const
{

View file

@ -25,6 +25,7 @@
#include <simgear/compiler.h>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/props/tiedpropertylist.hxx>
#include <simgear/math/SGMath.hxx>
#include <cmath>
@ -75,6 +76,7 @@ public:
private:
friend FGEnvironmentMgrMultiplayerListener;
void updateClosestAirport();
void updateTowerPosition();
double get_cloud_layer_span_m (int index) const;
void set_cloud_layer_span_m (int index, double span_m);
@ -98,9 +100,16 @@ private:
FGClouds *fgClouds = nullptr;
bool _cloudLayersDirty = true;
simgear::TiedPropertyList _tiedProperties;
SGPropertyChangeListener * _3dCloudsEnableListener = nullptr;
FGEnvironmentMgrMultiplayerListener * _multiplayerListener = nullptr;
SGSky* _sky = nullptr;
SGPropertyChangeListener * _3dCloudsEnableListener;
FGEnvironmentMgrMultiplayerListener * _multiplayerListener;
SGSky* _sky;
SGPropertyNode_ptr towerViewPositionLatDegNode;
SGPropertyNode_ptr towerViewPositionLonDegNode;
SGPropertyNode_ptr towerViewPositionAltFtNode;
const class FGAICarrier* nearestCarrier;
const class FGAirport* nearestAirport;
};
#endif // _ENVIRONMENT_MGR_HXX

View file

@ -180,6 +180,10 @@ void FGGlobals::initProperties()
viewLat = props->getNode("sim/current-view/viewer-lat-deg", true);
viewAlt = props->getNode("sim/current-view/viewer-elev-ft", true);
referenceOffsetX = props->getNode("sim/model/reference-offset-x", true);
referenceOffsetY = props->getNode("sim/model/reference-offset-y", true);
referenceOffsetZ = props->getNode("sim/model/reference-offset-z", true);
orientPitch = props->getNode("orientation/pitch-deg", true);
orientHeading = props->getNode("orientation/heading-deg", true);
orientRoll = props->getNode("orientation/roll-deg", true);
@ -613,6 +617,21 @@ FGGlobals::get_view_position_cart() const
{
return SGVec3d::fromGeod(get_view_position());
}
SGVec3d FGGlobals::get_ownship_reference_position_cart() const
{
SGVec3d pos = get_aircraft_position_cart();
if (referenceOffsetX)
pos[0] += referenceOffsetX->getDoubleValue();
if (referenceOffsetY)
pos[1] += referenceOffsetY->getDoubleValue();
if (referenceOffsetZ)
pos[2] += referenceOffsetZ->getDoubleValue();
return pos;
}
static void treeDumpRefCounts(int depth, SGPropertyNode* nd)
{

View file

@ -147,6 +147,8 @@ private:
SGPropertyNode_ptr viewLon, viewLat, viewAlt;
SGPropertyNode_ptr orientHeading, orientPitch, orientRoll;
SGPropertyNode_ptr referenceOffsetX, referenceOffsetY, referenceOffsetZ;
/**
* helper to initialise standard properties on a new property tree
*/
@ -350,6 +352,8 @@ public:
SGVec3d get_view_position_cart() const;
SGVec3d get_ownship_reference_position_cart() const;
inline string_list *get_channel_options_list () {
return channel_options_list;
}

View file

@ -111,11 +111,11 @@ extern "C" {
extern void awaitNasalGarbageCollectionComplete(bool can_wait);
}
#endif
static simgear::Notifications::MainLoopNotification mln_begin(simgear::Notifications::MainLoopNotification::Type::Begin);
static simgear::Notifications::MainLoopNotification mln_end(simgear::Notifications::MainLoopNotification::Type::End);
static simgear::Notifications::MainLoopNotification mln_started(simgear::Notifications::MainLoopNotification::Type::Started);
static simgear::Notifications::MainLoopNotification mln_stopped(simgear::Notifications::MainLoopNotification::Type::Stopped);
static simgear::Notifications::NasalGarbageCollectionConfigurationNotification *ngccn = nullptr;
static SGSharedPtr<simgear::Notifications::MainLoopNotification> mln_begin(new simgear::Notifications::MainLoopNotification(simgear::Notifications::MainLoopNotification::Type::Begin));
static SGSharedPtr<simgear::Notifications::MainLoopNotification> mln_end(new simgear::Notifications::MainLoopNotification(simgear::Notifications::MainLoopNotification::Type::End));
static SGSharedPtr<simgear::Notifications::MainLoopNotification> mln_started(new simgear::Notifications::MainLoopNotification(simgear::Notifications::MainLoopNotification::Type::Started));
static SGSharedPtr<simgear::Notifications::MainLoopNotification> mln_stopped(new simgear::Notifications::MainLoopNotification(simgear::Notifications::MainLoopNotification::Type::Stopped));
static SGSharedPtr<simgear::Notifications::NasalGarbageCollectionConfigurationNotification> ngccn;
// This method is usually called after OSG has finished rendering a frame in what OSG calls an idle handler and
// is reposonsible for invoking all of the relevant per frame processing; most of which is handled by subsystems.
static void fgMainLoop( void )
@ -143,7 +143,7 @@ static void fgMainLoop( void )
notify_gc_config = ngccn->SetActive(use_threaded_gc);
notify_gc_config |= ngccn->SetWait(threaded_wait);
if (notify_gc_config)
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(*ngccn);
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(ngccn);
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(mln_begin);
@ -356,7 +356,6 @@ static void fgIdleFunction ( void ) {
} else if (( idle_state == 5 ) || (idle_state == 2005)) {
idle_state+=2;
flightgear::initPosition();
flightgear::initTowerLocationListener();
simgear::SGModelLib::init(globals->get_fg_root().utf8Str(), globals->get_props());
@ -428,7 +427,7 @@ static void fgIdleFunction ( void ) {
flightgear::registerMainLoop();
ngccn = new simgear::Notifications::NasalGarbageCollectionConfigurationNotification(nasal_gc_threaded->getBoolValue(), nasal_gc_threaded_wait->getBoolValue());
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(*ngccn);
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(ngccn);
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(mln_started);
flightgear::addSentryBreadcrumb("entering main loop", "info");
@ -537,7 +536,7 @@ static void logToHome(const std::string& pri)
if (!pri.empty()) {
try {
fileLogLevel = std::min(fileLogLevel, logstream::priorityFromString(pri));
} catch (std::exception& e) {
} catch (std::exception& ) {
// let's not worry about this, and just log at INFO
}
}

View file

@ -73,74 +73,6 @@ static bool global_callbackRegistered = false;
void finalizePosition();
namespace { // annonymous namepsace to avoid warnings about inline classes
// Set current tower position lon/lat given an airport id
bool fgSetTowerPosFromAirportID( const string& id)
{
const FGAirport *a = fgFindAirportID( id);
if (a) {
SGGeod tower = a->getTowerLocation();
fgSetDouble("/sim/tower/longitude-deg", tower.getLongitudeDeg());
fgSetDouble("/sim/tower/latitude-deg", tower.getLatitudeDeg());
fgSetDouble("/sim/tower/altitude-ft", tower.getElevationFt());
return true;
} else {
return false;
}
}
class FGTowerLocationListener : public SGPropertyChangeListener {
void valueChanged(SGPropertyNode* node) override
{
string id(node->getStringValue());
if (fgGetBool("/sim/tower/auto-position",true))
{
// enforce using closest airport when auto-positioning is enabled
const char* closest_airport = fgGetString("/sim/airport/closest-airport-id", "");
if (closest_airport && (id != closest_airport))
{
id = closest_airport;
node->setStringValue(id);
}
}
fgSetTowerPosFromAirportID(id);
}
};
class FGClosestTowerLocationListener : public SGPropertyChangeListener
{
void valueChanged(SGPropertyNode* )
{
// closest airport has changed
if (fgGetBool("/sim/tower/auto-position",true))
{
// update tower position
const char* id = fgGetString("/sim/airport/closest-airport-id", "");
if (id && *id!=0)
fgSetString("/sim/tower/airport-id", id);
}
}
};
} // of anonymous namespace
void initTowerLocationListener() {
SGPropertyChangeListener* tll = new FGTowerLocationListener();
globals->addListenerToCleanup(tll);
fgGetNode("/sim/tower/airport-id", true)
->addChangeListener( tll, true );
FGClosestTowerLocationListener* ntcl = new FGClosestTowerLocationListener();
globals->addListenerToCleanup(ntcl);
fgGetNode("/sim/airport/closest-airport-id", true)
->addChangeListener(ntcl , true );
fgGetNode("/sim/tower/auto-position", true)
->addChangeListener(ntcl, true );
}
static void setInitialPosition(const SGGeod& aPos, double aHeadingDeg)
{
@ -425,7 +357,28 @@ static InitPosResult setInitialPosFromCarrier( const string& carrier )
// so our PagedLOD is loaded
fgSetDouble("/sim/presets/longitude-deg", initialPos.second.getLongitudeDeg());
fgSetDouble("/sim/presets/latitude-deg", initialPos.second.getLatitudeDeg());
SG_LOG( SG_GENERAL, SG_DEBUG, "Initial carrier pos = " << initialPos.second );
const std::string carrier = fgGetString("/sim/presets/carrier");
const std::string carrierpos = fgGetString("/sim/presets/carrier-position");
const std::string parkpos = fgGetString("/sim/presets/parkpos");
if (!carrier.empty())
{
std::string cpos = simgear::strutils::lowercase(carrierpos);
const bool inair = (cpos == "flols") || (cpos == "abeam");
if (cpos == "flols" || cpos == "abeam")
fgSetInt("/sim/presets/carrier-course", 3);// base=1, launch=2, recovery=3
else if (parkpos.find("cat") != std::string::npos)
fgSetInt("/sim/presets/carrier-course", 2);// base=1, launch=2, recovery=3
else
fgSetInt("/sim/presets/carrier-course", 1); // base
}
else
fgSetInt("/sim/presets/carrier-course", 0); // not defined.
SG_LOG( SG_GENERAL, SG_DEBUG, "Initial carrier pos = " << initialPos.second << " course " << fgGetInt("/sim/presets/carrier-course"));
return VicinityPosition;
}
@ -433,7 +386,7 @@ static InitPosResult setInitialPosFromCarrier( const string& carrier )
return Failure;
}
static InitPosResult checkCarrierSceneryLoaded(const SGSharedPtr<FGAICarrier> carrierRef)
static InitPosResult checkCarrierSceneryLoaded(FGAICarrier* carrierRef)
{
SGVec3d cartPos = carrierRef->getCartPos();
auto framestamp = globals->get_renderer()->getFrameStamp();

View file

@ -348,8 +348,10 @@ public:
fgGetNode("/environment/clouds/status")->addChangeListener(this);
auto vpb_active = fgGetNode("/scenery/use-vpb");
vpb_active->addChangeListener(this);
SGSceneFeatures::instance()->setVPBActive(vpb_active->getBoolValue());
if (vpb_active) {
vpb_active->addChangeListener(this);
SGSceneFeatures::instance()->setVPBActive(vpb_active->getBoolValue());
}
}
~ScenerySwitchListener()