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:
parent
303e518e87
commit
522d7e8450
13 changed files with 552 additions and 178 deletions
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
102
src/AIModel/AINotifications.hxx
Normal file
102
src/AIModel/AINotifications.hxx
Normal 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
|
|
@ -36,6 +36,7 @@ set(HEADERS
|
|||
AIGroundVehicle.hxx
|
||||
AIManager.hxx
|
||||
AIMultiplayer.hxx
|
||||
AINotifications.hxx
|
||||
AIShip.hxx
|
||||
AIStatic.hxx
|
||||
AIStorm.hxx
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Add table
Reference in a new issue