14#include <simgear/constants.h>
15#include <simgear/debug/logstream.hxx>
17#include <simgear/scene/sky/sky.hxx>
18#include <simgear/scene/model/particles.hxx>
19#include <simgear/structure/event_mgr.hxx>
52 SGPropertyNode_ptr _enableNode;
58 _enableNode =
fgGetNode(
"/sim/rendering/clouds3d-enable",
true );
59 _enableNode->addChangeListener(
this );
66 _enableNode->removeChangeListener(
this );
71 _fgClouds->set_3dClouds( _enableNode->getBoolValue() );
76 _multiplayerListener(nullptr),
77 _sky(
globals->get_renderer()->getSky()),
78 nearestCarrier(nullptr),
79 nearestAirport(nullptr)
92 max_tower_height_feet =
fgGetDouble(
"/sim/airport/max-tower-height-ft", 70);
93 min_tower_height_feet =
fgGetDouble(
"/sim/airport/min-tower-height-ft", 6);
94 default_tower_height_feet =
fgGetDouble(
"default-tower-height-ft", 30);
99 remove_subsystem(
"ridgelift" );
100 remove_subsystem(
"terrainsampler" );
101 remove_subsystem(
"precipitation");
102 remove_subsystem(
"realwx");
103 remove_subsystem(
"controller");
104 remove_subsystem(
"magvar");
107 delete _3dCloudsEnableListener;
114 _environmentmgr(environmentmgr)
116 _node =
fgGetNode(
"/sim/current-view/model-view",
true );
117 _node->addChangeListener(
this);
121 _environmentmgr->updateClosestAirport();
125 _node->removeChangeListener(
this);
129 SGPropertyNode_ptr _node;
135 InitStatus r = SGSubsystemGroup::incrementalInit();
136 if (r == INIT_DONE) {
138 _multiplayerListener =
new FGEnvironmentMgrMultiplayerListener(
this);
139 globals->get_event_mgr()->addTask(
"updateClosestAirport",
140 [
this](){ this->updateClosestAirport(); }, 10 );
149 globals->get_event_mgr()->removeTask(
"updateClosestAirport");
150 delete _multiplayerListener;
151 _multiplayerListener =
nullptr;
152 SGSubsystemGroup::shutdown();
158 SG_LOG( SG_ENVIRONMENT, SG_INFO,
"Reinitializing environment subsystem");
159 SGSubsystemGroup::reinit();
165 SGSubsystemGroup::bind();
166 _environment->Tie(
fgGetNode(
"/environment",
true ) );
168 _tiedProperties.setRoot(
fgGetNode(
"/environment",
true ) );
170 _tiedProperties.Tie(
"effective-visibility-m", _sky,
171 &SGSky::get_visibility );
173 _tiedProperties.Tie(
"rebuild-layers", fgClouds,
181 SGPropertyNode_ptr layerNode =
fgGetNode(
"/environment/clouds",
true)->getChild(
"layer",
i,
true );
183 _tiedProperties.Tie( layerNode->getNode(
"span-m",
true),
this,
i,
184 &FGEnvironmentMgr::get_cloud_layer_span_m,
185 &FGEnvironmentMgr::set_cloud_layer_span_m);
187 _tiedProperties.Tie( layerNode->getNode(
"elevation-ft",
true),
this,
i,
188 &FGEnvironmentMgr::get_cloud_layer_elevation_ft,
189 &FGEnvironmentMgr::set_cloud_layer_elevation_ft);
191 _tiedProperties.Tie( layerNode->getNode(
"thickness-ft",
true),
this,
i,
192 &FGEnvironmentMgr::get_cloud_layer_thickness_ft,
193 &FGEnvironmentMgr::set_cloud_layer_thickness_ft);
195 _tiedProperties.Tie( layerNode->getNode(
"transition-ft",
true),
this,
i,
196 &FGEnvironmentMgr::get_cloud_layer_transition_ft,
197 &FGEnvironmentMgr::set_cloud_layer_transition_ft);
199 _tiedProperties.Tie( layerNode->getNode(
"coverage",
true),
this,
i,
200 &FGEnvironmentMgr::get_cloud_layer_coverage,
201 &FGEnvironmentMgr::set_cloud_layer_coverage);
203 _tiedProperties.Tie( layerNode->getNode(
"coverage-type",
true),
this,
i,
204 &FGEnvironmentMgr::get_cloud_layer_coverage_type,
205 &FGEnvironmentMgr::set_cloud_layer_coverage_type);
207 _tiedProperties.Tie( layerNode->getNode(
"visibility-m",
true),
this,
i,
208 &FGEnvironmentMgr::get_cloud_layer_visibility_m,
209 &FGEnvironmentMgr::set_cloud_layer_visibility_m);
211 _tiedProperties.Tie( layerNode->getNode(
"alpha",
true),
this,
i,
212 &FGEnvironmentMgr::get_cloud_layer_maxalpha,
213 &FGEnvironmentMgr::set_cloud_layer_maxalpha);
216 _tiedProperties.setRoot(
fgGetNode(
"/sim/rendering",
true ) );
218 _tiedProperties.Tie(
"clouds3d-density", _sky,
219 &SGSky::get_3dCloudDensity,
220 &SGSky::set_3dCloudDensity);
222 _tiedProperties.Tie(
"clouds3d-vis-range", _sky,
223 &SGSky::get_3dCloudVisRange,
224 &SGSky::set_3dCloudVisRange);
226 _tiedProperties.Tie(
"clouds3d-impostor-range", _sky,
227 &SGSky::get_3dCloudImpostorDistance,
228 &SGSky::set_3dCloudImpostorDistance);
230 _tiedProperties.Tie(
"clouds3d-lod1-range", _sky,
231 &SGSky::get_3dCloudLoD1Range,
232 &SGSky::set_3dCloudLoD1Range);
234 _tiedProperties.Tie(
"clouds3d-lod2-range", _sky,
235 &SGSky::get_3dCloudLoD2Range,
236 &SGSky::set_3dCloudLoD2Range);
238 _tiedProperties.Tie(
"clouds3d-wrap", _sky,
239 &SGSky::get_3dCloudWrap,
240 &SGSky::set_3dCloudWrap);
242 _tiedProperties.Tie(
"clouds3d-use-impostors", _sky,
243 &SGSky::get_3dCloudUseImpostors,
244 &SGSky::set_3dCloudUseImpostors);
250 _tiedProperties.Untie();
251 _environment->Untie();
252 SGSubsystemGroup::unbind();
258 SGGeod aircraftPos(
globals->get_aircraft_position());
260 SGSubsystemGroup::update(dt);
262 _environment->set_elevation_ft( aircraftPos.getElevationFt() );
264 auto particlesManager = simgear::ParticlesGlobalManager::instance();
265 particlesManager->setWindFrom(_environment->get_wind_from_heading_deg(),
266 _environment->get_wind_speed_kt());
267 particlesManager->update(dt,
globals->get_aircraft_position());
269 if( _cloudLayersDirty ) {
270 _cloudLayersDirty =
false;
271 fgClouds->set_update_event( fgClouds->get_update_event()+1 );
273 updateTowerPosition();
275 fgSetDouble(
"/environment/gravitational-acceleration-mps2",
279void FGEnvironmentMgr::updateTowerPosition()
281 if (towerViewPositionLatDegNode !=
nullptr && towerViewPositionLonDegNode !=
nullptr && towerViewPositionAltFtNode !=
nullptr) {
282 auto automaticTowerActive =
fgGetBool(
"/sim/tower/auto-position",
true);
284 fgSetDouble(
"/sim/airport/nearest-tower-latitude-deg", towerViewPositionLatDegNode->getDoubleValue());
285 fgSetDouble(
"/sim/airport/nearest-tower-longitude-deg", towerViewPositionLonDegNode->getDoubleValue());
286 fgSetDouble(
"/sim/airport/nearest-tower-altitude-ft", towerViewPositionAltFtNode->getDoubleValue());
288 if (automaticTowerActive) {
289 fgSetDouble(
"/sim/tower/latitude-deg", towerViewPositionLatDegNode->getDoubleValue());
290 fgSetDouble(
"/sim/tower/longitude-deg", towerViewPositionLonDegNode->getDoubleValue());
291 fgSetDouble(
"/sim/tower/altitude-ft", towerViewPositionAltFtNode->getDoubleValue());
296void FGEnvironmentMgr::updateClosestAirport()
298 SG_LOG(SG_ENVIRONMENT, SG_DEBUG,
"FGEnvironmentMgr::update: updating closest airport");
307 if (view_config_root !=
"/" && view_config_root !=
"") {
309 pos = SGGeod::fromDegFt(
321 auto automaticTowerActive =
fgGetBool(
"/sim/tower/auto-position",
true);
323 SGGeod nearestTowerPosition;
324 std::string nearestIdent;
325 const SGGeod airportGeod;
326 double towerDistance = std::numeric_limits<double>::max();
327 if (nearestAirport) {
328 const std::string currentId =
fgGetString(
"/sim/airport/closest-airport-id",
"");
329 if (currentId != nearestAirport->ident()) {
330 SG_LOG(SG_ENVIRONMENT, SG_INFO,
"FGEnvironmentMgr::updateClosestAirport: selected:" << nearestAirport->ident());
331 fgSetString(
"/sim/airport/closest-airport-id", nearestAirport->ident().c_str());
334 if (nearestAirport->hasTower()) {
335 nearestTowerPosition = nearestAirport->getTowerLocation();
336 SG_LOG(SG_ENVIRONMENT, SG_DEBUG,
"airport-id=" << nearestAirport->getId() <<
" tower_pos=" << nearestTowerPosition);
339 nearestTowerPosition = nearestAirport->geod();
340 SG_LOG(SG_ENVIRONMENT, SG_DEBUG,
"no tower for airport-id=" << nearestAirport->getId());
344 auto towerAirpotDistance =
abs(nearestTowerPosition.getElevationFt() - nearestAirport->geod().getElevationFt());
345 if (towerAirpotDistance < min_tower_height_feet) {
346 nearestTowerPosition.setElevationFt(nearestTowerPosition.getElevationFt() + default_tower_height_feet);
347 SG_LOG(SG_ENVIRONMENT, SG_DEBUG,
"Tower altitude adjusted because it was at below minimum height above ground (" << min_tower_height_feet <<
"feet) for airport " << nearestAirport->getId());
349 else if (towerAirpotDistance > max_tower_height_feet) {
350 nearestTowerPosition.setElevationFt(nearestTowerPosition.getElevationFt() + default_tower_height_feet);
351 SG_LOG(SG_ENVIRONMENT, SG_DEBUG,
"Tower altitude adjusted because it was taller than the permitted maximum of (" << max_tower_height_feet <<
"feet) for airport " << nearestAirport->getId());
354 nearestIdent = nearestAirport->ident();
355 towerDistance = SGGeodesy::distanceM(nearestTowerPosition, pos);
359 towerViewPositionLatDegNode = towerViewPositionLonDegNode = towerViewPositionAltFtNode =
nullptr;
362 SG_LOG(SG_ENVIRONMENT, SG_INFO,
"FGEnvironmentMgr::update: No airport within 100NM range");
364 auto nctn = SGSharedPtr< NearestCarrierToNotification> (
new NearestCarrierToNotification(pos));
365 if (simgear::Emesary::ReceiptStatus::OK == simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(nctn)) {
366 if (nearestCarrier != nctn->GetCarrier()) {
367 nearestCarrier = nctn->GetCarrier();
368 fgSetString(
"/sim/airport/nearest-carrier", nctn->GetCarrierIdent());
372 fgSetDouble(
"/sim/airport/nearest-carrier-latitude-deg", 0);
373 fgSetDouble(
"/sim/airport/nearest-carrier-longitude-deg", 0);
374 fgSetDouble(
"/sim/airport/nearest-carrier-altitude-ft", 0);
375 fgSetDouble(
"/sim/airport/nearest-carrier-deck-height", 0);
376 nearestCarrier =
nullptr;
380 if (nearestCarrier && (nctn->GetDistanceMeters() < towerDistance)) {
381 nearestIdent = nctn->GetCarrierIdent();
385 towerViewPositionLatDegNode = nctn->GetViewPositionLatNode();
386 towerViewPositionLonDegNode = nctn->GetViewPositionLonNode();
387 towerViewPositionAltFtNode = nctn->GetViewPositionAltNode();
391 fgSetDouble(
"/sim/airport/nearest-carrier-latitude-deg", nctn->GetPosition()->getLatitudeDeg());
392 fgSetDouble(
"/sim/airport/nearest-carrier-longitude-deg", nctn->GetPosition()->getLongitudeDeg());
393 fgSetDouble(
"/sim/airport/nearest-carrier-altitude-ft", nctn->GetPosition()->getElevationFt());
394 fgSetDouble(
"/sim/airport/nearest-carrier-deck-height", nctn->GetDeckheight());
396 if (nearestAirport !=
nullptr) {
398 if (automaticTowerActive) {
400 fgSetString(path +
"airport-id", nearestAirport->getId());
402 fgSetDouble(path +
"latitude-deg", nearestTowerPosition.getLatitudeDeg());
403 fgSetDouble(path +
"longitude-deg", nearestTowerPosition.getLongitudeDeg());
404 fgSetDouble(path +
"altitude-ft", nearestTowerPosition.getElevationFt());
408 SG_LOG(SG_ENVIRONMENT, SG_DEBUG,
"FGEnvironmentMgr::update: No airport or carrier within 100NM range of current multiplayer aircraft");
413 if (
fgGetString(
"/sim/airport/nearest-tower-ident") != nearestIdent) {
414 SG_LOG(SG_ENVIRONMENT, SG_INFO,
"Nearest airport tower now " << nearestIdent);
415 fgSetString(
"/sim/airport/nearest-tower-ident", nearestIdent);
417 if (automaticTowerActive) {
418 if (
fgGetString(
"/sim/tower/airport-id") != nearestIdent) {
419 fgSetString(
"/sim/tower/airport-id", nearestIdent);
420 SG_LOG(SG_ENVIRONMENT, SG_INFO,
"Auto Tower: now " << nearestIdent);
423 updateTowerPosition();
430 return *_environment;
451FGEnvironmentMgr::get_cloud_layer_span_m (
int index)
const
453 return _sky->get_cloud_layer(index)->getSpan_m();
457FGEnvironmentMgr::set_cloud_layer_span_m (
int index,
double span_m)
459 _sky->get_cloud_layer(index)->setSpan_m(span_m);
463FGEnvironmentMgr::get_cloud_layer_elevation_ft (
int index)
const
465 return _sky->get_cloud_layer(index)->getElevation_m() * SG_METER_TO_FEET;
469FGEnvironmentMgr::set_cloud_layer_elevation_ft (
int index,
double elevation_ft)
471 FGEnvironment env = *_environment;
474 _sky->get_cloud_layer(index)
475 ->setElevation_m(elevation_ft * SG_FEET_TO_METER);
477 _sky->get_cloud_layer(index)
480 _sky->get_cloud_layer(index)
485FGEnvironmentMgr::get_cloud_layer_thickness_ft (
int index)
const
487 return _sky->get_cloud_layer(index)->getThickness_m() * SG_METER_TO_FEET;
491FGEnvironmentMgr::set_cloud_layer_thickness_ft (
int index,
double thickness_ft)
493 _sky->get_cloud_layer(index)
494 ->setThickness_m(thickness_ft * SG_FEET_TO_METER);
498FGEnvironmentMgr::get_cloud_layer_transition_ft (
int index)
const
500 return _sky->get_cloud_layer(index)->getTransition_m() * SG_METER_TO_FEET;
504FGEnvironmentMgr::set_cloud_layer_transition_ft (
int index,
505 double transition_ft)
507 _sky->get_cloud_layer(index)
508 ->setTransition_m(transition_ft * SG_FEET_TO_METER);
512FGEnvironmentMgr::get_cloud_layer_coverage (
int index)
const
514 return _sky->get_cloud_layer(index)->getCoverageString().c_str();
518FGEnvironmentMgr::set_cloud_layer_coverage (
int index,
519 const char * coverage_name)
521 if( _sky->get_cloud_layer(index)->getCoverageString() == coverage_name )
524 _sky->get_cloud_layer(index)->setCoverageString(coverage_name);
525 _cloudLayersDirty =
true;
529FGEnvironmentMgr::get_cloud_layer_coverage_type (
int index)
const
531 return _sky->get_cloud_layer(index)->getCoverage();
535FGEnvironmentMgr::get_cloud_layer_visibility_m (
int index)
const
537 return _sky->get_cloud_layer(index)->getVisibility_m();
541FGEnvironmentMgr::set_cloud_layer_visibility_m (
int index,
double visibility_m)
543 _sky->get_cloud_layer(index)->setVisibility_m(visibility_m);
547FGEnvironmentMgr::get_cloud_layer_maxalpha (
int index )
const
549 return _sky->get_cloud_layer(index)->getMaxAlpha();
553FGEnvironmentMgr::set_cloud_layer_maxalpha (
int index,
double maxalpha)
555 _sky->get_cloud_layer(index)->setMaxAlpha(maxalpha);
559FGEnvironmentMgr::set_cloud_layer_coverage_type (
int index,
int type )
561 if( type < 0 || type >= SGCloudLayer::SG_MAX_CLOUD_COVERAGES ) {
562 SG_LOG(SG_ENVIRONMENT,SG_WARN,
"Unknown cloud layer type " << type <<
" ignored" );
566 if(
static_cast<SGCloudLayer::Coverage
>(type) == _sky->get_cloud_layer(index)->getCoverage() )
569 _sky->get_cloud_layer(index)->setCoverage(
static_cast<SGCloudLayer::Coverage
>(type));
570 _cloudLayersDirty =
true;
static const Gravity * instance()
static LayerInterpolateController * createInstance(SGPropertyNode_ptr rootNode)
static RealWxController * createInstance(SGPropertyNode_ptr rootNode)
static TerrainSampler * createInstance(SGPropertyNode_ptr rootNode)
virtual ~FG3DCloudsListener()
virtual void valueChanged(SGPropertyNode *node)
FG3DCloudsListener(FGClouds *fgClouds)
static FGAirportRef findClosest(const SGGeod &aPos, double aCuttofNm, Filter *filter=NULL)
Syntactic wrapper around FGPositioned::findClosest - find the closest match for filter,...
void set_update_event(int count)
int get_update_event(void) const
Manage environment information.
virtual ~FGEnvironmentMgr()
InitStatus incrementalInit() override
const FGEnvironment * getAircraftEnvironment() const
void update(double dt) override
virtual FGEnvironment getEnvironmentAtPosition(const SGGeod &aPos) const
virtual FGEnvironment getEnvironment() const
Get the environment information for the plane's current position.
Model the natural environment.
virtual double get_wind_speed_kt() const
virtual double get_wind_from_heading_deg() const
virtual void set_elevation_ft(double elevation_ft)
SGGeod get_aircraft_position() const
SGSubsystemMgr::Registrant< FGEnvironmentMgr > registrantFGEnvironmentMgr
std::string fgGetString(const char *name, const char *defaultValue)
Get a string value for a property.
const std::string & getStringValue(const char *spec)
double getDoubleValue(const char *spec, double default_)
Precipitation manager This manager calculate the intensity of precipitation in function of the altitu...
bool fgSetDouble(const char *name, double defaultValue)
Set a double value for a property.
bool fgGetBool(char const *name, bool def)
Get a bool value for a property.
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
FGEnvironmentMgrMultiplayerListener(FGEnvironmentMgr *environmentmgr)
virtual void valueChanged(SGPropertyNode *node)
virtual ~FGEnvironmentMgrMultiplayerListener()