29#include <simgear/math/SGMath.hxx>
59class LayerTable :
public std::vector<LayerTableBucket *>,
public SGPropertyChangeListener
63 _rootNode(rootNode) {}
94 void valueChanged( SGPropertyNode * node );
95 SGPropertyNode_ptr _rootNode;
110 void bind()
override;
111 void init()
override;
115 void update(
double delta_time_sec)
override;
121 SGPropertyNode_ptr _rootNode;
123 double _boundary_transition;
124 SGPropertyNode_ptr _altitude_n;
125 SGPropertyNode_ptr _altitude_agl_n;
131 simgear::TiedPropertyList _tiedProperties;
138 for( iterator it = begin(); it != end(); it++ )
144 double last_altitude_ft = 0.0;
145 double sort_required =
false;
148 for (
i = 0;
i < (size_t)_rootNode->nChildren();
i++) {
149 const SGPropertyNode * child = _rootNode->getChild(
i);
150 if ( child->getNameString() ==
"entry"
151 && child->getStringValue(
"elevation-ft",
"")[0] !=
'\0'
152 && ( child->getDoubleValue(
"elevation-ft") > 0.1 ||
i == 0 ) )
163 if (
i == 0 && parent != NULL )
173 sort_required =
true;
178 while( size() >
i ) {
188 for( size_type n = 1; n < size(); n++ ) {
189 if( fabs(at(n)->altitude_ft - at(n-1)->altitude_ft ) < 1 ) {
190 SG_LOG( SG_ENVIRONMENT, SG_ALERT,
"Removing duplicate altitude entry in environment config for altitude " << at(n)->altitude_ft );
191 erase( begin() + n );
201 for(
unsigned i = 0;
i < size();
i++ ) {
202 SGPropertyNode_ptr baseNode = _rootNode->getChild(
"entry",
i,
true );
203 at(
i)->environment.Tie( baseNode );
204 baseNode->getNode(
"pressure-sea-level-inhg",
true )->addChangeListener(
this );
205 baseNode->getNode(
"elevation-ft",
true)->addChangeListener(
this);
214 for(
unsigned i = 0;
i < size();
i++ ) {
215 SGPropertyNode_ptr baseNode = _rootNode->getChild(
"entry",
i,
true );
216 at(
i)->environment.Untie();
217 baseNode->getNode(
"pressure-sea-level-inhg",
true )->removeChangeListener(
this );
218 baseNode->getNode(
"elevation-ft",
true)->removeChangeListener(
this);
222void LayerTable::valueChanged( SGPropertyNode * node )
226 if (node->getNameString() ==
"pressure-sea-level-inhg") {
227 double value = node->getDoubleValue();
228 for (iterator it = begin(); it != end(); it++) {
229 (*it)->environment.set_pressure_sea_level_inhg(value);
232 bool sort_required =
false;
233 double last_altitude_ft = 0.0;
234 for (iterator it = begin(); it != end(); it++) {
235 (*it)->altitude_ft = (*it)->environment.get_elevation_ft();
236 if ((*it)->altitude_ft < last_altitude_ft)
237 sort_required =
true;
238 last_altitude_ft = (*it)->altitude_ft;
253 if ((length == 1) || (at(0)->altitude_ft >= altitude_ft)) {
254 *result = at(0)->environment;
256 }
else if (at(length-1)->altitude_ft <= altitude_ft) {
257 *result = at(length-1)->environment;
264 layer < length && at(layer)->altitude_ft <= altitude_ft;
269 double fraction = ((altitude_ft - at(layer-1)->altitude_ft) /
270 (at(layer)->altitude_ft - at(layer-1)->altitude_ft));
277 _rootNode( rootNode ),
279 _boundary_transition(0.0),
280 _altitude_n(
fgGetNode(
"/position/altitude-ft", true)),
281 _altitude_agl_n(
fgGetNode(
"/position/altitude-agl-ft", true)),
282 _boundary_table( rootNode->getNode(
"boundary", true ) ),
283 _aloft_table( rootNode->getNode(
"aloft", true ) )
289 _boundary_table.read();
292 _aloft_table.read(&(*(_boundary_table.end()-1))->environment);
297 _boundary_table.Unbind();
298 _aloft_table.Unbind();
306 _boundary_table.Bind();
313 _environment.Tie( _rootNode->getNode(
"interpolated",
true ) );
314 _tiedProperties.Tie( _rootNode->getNode(
"enabled",
true), &_enabled );
315 _tiedProperties.Tie( _rootNode->getNode(
"boundary-transition-ft",
true ), &_boundary_transition );
320 _boundary_table.Unbind();
321 _aloft_table.Unbind();
322 _tiedProperties.Untie();
323 _environment.Untie();
328 if( !_enabled || delta_time_sec <= SGLimitsd::min() )
331 double altitude_ft = _altitude_n->getDoubleValue();
332 double altitude_agl_ft = _altitude_agl_n->getDoubleValue();
335 if( _boundary_transition <= SGLimitsd::min() )
336 _boundary_transition = 500;
338 int length = _boundary_table.size();
342 double boundary_limit = _boundary_table[length-1]->altitude_ft;
343 if (boundary_limit >= altitude_agl_ft) {
346 _boundary_table.interpolate(altitude_agl_ft, &_environment);
348 }
else if ((boundary_limit + _boundary_transition) >= altitude_agl_ft) {
352 _boundary_table.
interpolate( altitude_agl_ft, &env1);
354 double fraction = (altitude_agl_ft - boundary_limit) / _boundary_transition;
361 _aloft_table.interpolate( altitude_ft, &_environment);
375SGSubsystemMgr::Registrant<LayerInterpolateControllerImplementation> registrantLayerInterpolateControllerImplementation;
Implementation of the LayerIterpolateController.
LayerInterpolateControllerImplementation(SGPropertyNode_ptr rootNode)
static const char * staticSubsystemClassId()
void update(double delta_time_sec) override
static LayerInterpolateController * createInstance(SGPropertyNode_ptr rootNode)
Models a column of our atmosphere by stacking a number of environments above each other.
void read(FGEnvironment *parent=NULL)
Read the environment column from properties relative to the given root node.
LayerTable(SGPropertyNode_ptr rootNode)
void Unbind()
Unbind all environments properties from property nodes and deregister listeners.
void interpolate(double altitude_ft, FGEnvironment *environment)
Interpolate and write environment values for a given altitude.
void Bind()
Bind all environments properties to property nodes and initialize the listeners.
Model the natural environment.
virtual void read(const SGPropertyNode *node)
FGEnvironment & interpolate(const FGEnvironment &env2, double fraction, FGEnvironment *result) const
virtual double get_elevation_ft() const
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Describes an element of a LayerTable.
static bool lessThan(LayerTableBucket *a, LayerTableBucket *b)
LessThan predicate for bucket pointers.
FGEnvironment environment
bool operator<(const LayerTableBucket &b) const