28#include <simgear/math/sg_random.hxx>
34using simgear::PropertyList;
37using std::ostringstream;
40#include <simgear/props/tiedpropertylist.hxx>
58 void update(
double dt)
override;
65 _elevationHistogramStep = value > 0 ? value : 500;
66 _elevationHistogramCount = _elevationHistogramMax / _elevationHistogramStep;
71 _elevationHistogramMax = value > 0 ? value : 10000;
72 _elevationHistogramCount = _elevationHistogramMax / _elevationHistogramStep;
80 SGPropertyNode_ptr _rootNode;
83 bool _useAircraftPosition;
87 double _max_computation_time_norm;
89 double _reuse_samples_norm;
90 double _recalc_distance_norm;
91 int _elevationHistogramMax;
92 int _elevationHistogramStep;
93 int _elevationHistogramCount;
94 SGGeod _inputPosition;
101 SGGeod _outputPosition;
103 SGPropertyNode_ptr _signalNode;
104 SGPropertyNode_ptr _positionLatitudeNode;
105 SGPropertyNode_ptr _positionLongitudeNode;
107 deque<double> _elevations;
108 simgear::TiedPropertyList _tiedProperties;
114 _useAircraftPosition(false),
118 _max_computation_time_norm(0.1),
120 _reuse_samples_norm(0.8),
121 _recalc_distance_norm(0.1),
122 _elevationHistogramMax(10000),
123 _elevationHistogramStep(500),
124 _elevationHistogramCount(_elevationHistogramMax/_elevationHistogramStep),
130 _signalNode(rootNode->getNode(
"output/valid", true )),
131 _positionLatitudeNode(
fgGetNode(
"/position/latitude-deg", true )),
132 _positionLongitudeNode(
fgGetNode(
"/position/longitude-deg", true ))
134 _inputPosition.setElevationM( SG_MAX_ELEVATION_M );
144 _tiedProperties.setRoot( _rootNode );
145 _tiedProperties.Tie(
"enabled", &_enabled );
147 _tiedProperties.setRoot( _rootNode->getNode(
"input",
true ) );
148 _tiedProperties.Tie(
"use-aircraft-position", &_useAircraftPosition );
149 _tiedProperties.Tie(
"latitude-deg", &_inputPosition, &SGGeod::getLatitudeDeg, &SGGeod::setLatitudeDeg );
150 _tiedProperties.Tie(
"longitude-deg", &_inputPosition, &SGGeod::getLongitudeDeg, &SGGeod::setLongitudeDeg );
151 _tiedProperties.Tie(
"heading-deg", &_heading_deg );
152 _tiedProperties.Tie(
"speed-kt", &_speed_kt );
153 _tiedProperties.Tie(
"radius-m", &_radius );
154 _tiedProperties.Tie(
"max-computation-time-norm", &_max_computation_time_norm );
155 _tiedProperties.Tie(
"max-samples", &_max_samples );
156 _tiedProperties.Tie(
"reuse-samples-norm", &_reuse_samples_norm );
157 _tiedProperties.Tie(
"recalc-distance-norm", &_recalc_distance_norm );
162 _tiedProperties.setRoot( _rootNode->getNode(
"output",
true ) );
163 _tiedProperties.Tie(
"alt-offset-ft", &_altOffset );
164 _tiedProperties.Tie(
"alt-median-ft", &_altMedian );
165 _tiedProperties.Tie(
"alt-min-ft", &_altMin );
166 _tiedProperties.Tie(
"alt-layered-ft", &_altLayered );
167 _tiedProperties.Tie(
"alt-mean-ft", &_altMean );
168 _tiedProperties.Tie(
"longitude-deg", &_outputPosition, &SGGeod::getLongitudeDeg );
169 _tiedProperties.Tie(
"latitude-deg", &_outputPosition, &SGGeod::getLatitudeDeg );
175 _tiedProperties.Untie();
180 _signalNode->setBoolValue(
false);
197 if( !(_enabled && dt > SGLimitsd::min()) )
201 if( _useAircraftPosition && _speed_kt < 0.5 ) {
202 _inputPosition = SGGeod::fromDegM(
203 _positionLongitudeNode->getDoubleValue(),
204 _positionLatitudeNode->getDoubleValue(),
205 SG_MAX_ELEVATION_M );
209 SGGeoc center = SGGeoc::fromGeod( _inputPosition );
212 if( _speed_kt >= 0.5 ) {
213 double distance_m = _speed_kt * dt * SG_NM_TO_METER;
214 center = center.advanceRadM( _heading_deg * SG_DEGREES_TO_RADIANS, distance_m );
215 _inputPosition = SGGeod::fromGeoc( center );
218 if( _signalNode->getBoolValue() ) {
221 if( SGGeoc::distanceM( center, SGGeoc::fromGeod(_outputPosition ) ) >= _recalc_distance_norm * _radius ) {
222 _elevations.resize( _max_samples * _reuse_samples_norm );
223 _signalNode->setBoolValue(
false );
227 if( _signalNode->getBoolValue() )
232 SGTimeStamp start = SGTimeStamp::now();
233 while( (SGTimeStamp::now() - start).toSecs() < dt * _max_computation_time_norm ) {
235 double distance = sg_random();
236 distance = _radius * (1-distance*distance);
237 double course = sg_random() * 2.0 * SG_PI;
238 SGGeod probe = SGGeod::fromGeoc(center.advanceRadM( course, distance ));
239 double elevation_m = 0.0;
242 _elevations.push_front(elevation_m *= SG_METER_TO_FEET);
244 if( _elevations.size() >= (deque<unsigned>::size_type)_max_samples ) {
247 _outputPosition = _inputPosition;
248 _signalNode->setBoolValue(
true );
254void AreaSampler::analyse()
258 vector<int> histogram(_elevationHistogramCount,0);
260 for( deque<double>::size_type
i = 0;
i < _elevations.size();
i++ ) {
261 int idx = SGMisc<int>::clip( (
int)(_elevations[
i]/_elevationHistogramStep), 0, histogram.size()-1 );
267 for( vector<int>::size_type
i = 0;
i < histogram.size();
i++ ) {
269 if( sum > 0.5 * _elevations.size() ) {
270 _altMedian =
i * _elevationHistogramStep;
277 for( vector<int>::size_type
i = 0;
i < histogram.size();
i++ ) {
279 if( sum > 0.3 * _elevations.size() ) {
280 _altOffset =
i * _elevationHistogramStep;
286 for( vector<int>::size_type
i = 0;
i < histogram.size();
i++ ) {
287 _altMean += histogram[
i] *
i;
289 _altMean *= _elevationHistogramStep;
290 if( _elevations.size() != 0.0 ) _altMean /= _elevations.size();
293 for( vector<int>::size_type
i = 0;
i < histogram.size();
i++ ) {
294 if( histogram[
i] > 0 ) {
295 _altMin =
i * _elevationHistogramStep;
313 _altLayered = 0.5 * (_altMin + _altOffset);
316append(alt_50_array, alt_med);
323SGSubsystemMgr::Registrant<AreaSampler> registrantAreaSampler;
337 void bind()
override;
339 void init()
override;
343 void update(
double delta_time_sec)
override;
349 inline string areaSubsystemName(
unsigned i ) {
355 SGPropertyNode_ptr _rootNode;
357 simgear::TiedPropertyList _tiedProperties;
361 _rootNode( rootNode ),
378 PropertyList areaNodes = _rootNode->getChildren(
"area" );
380 for( PropertyList::size_type
i = 0;
i < areaNodes.size();
i++ )
381 set_subsystem( areaSubsystemName(
i),
new AreaSampler( areaNodes[
i] ) );
383 SGSubsystemGroup::init();
392 for(
unsigned i = 0;;
i++ ) {
393 string subsystemName = areaSubsystemName(
i);
394 SGSubsystem * subsys = get_subsystem( subsystemName );
397 remove_subsystem( subsystemName );
407 SGSubsystemGroup::bind();
408 _tiedProperties.Tie( _rootNode->getNode(
"enabled",
true), &_enabled );
413 _tiedProperties.Untie();
414 SGSubsystemGroup::unbind();
419 if( !(_enabled && dt > SGLimitsd::min()) )
421 SGSubsystemGroup::update(dt);
Class for presampling the terrain roughness.
int getElevationHistogramMax() const
void setElevationHistograpMax(int value)
static const char * staticSubsystemClassId()
AreaSampler(SGPropertyNode_ptr rootNode)
int getElevationHistogramCount() const
void setElevationHistograpStep(int value)
int getElevationHistogramStep() const
void update(double dt) override
void update(double delta_time_sec) override
virtual ~TerrainSamplerImplementation()
static const char * staticSubsystemClassId()
TerrainSamplerImplementation(SGPropertyNode_ptr rootNode)
InitStatus incrementalInit() override
static TerrainSampler * createInstance(SGPropertyNode_ptr rootNode)
bool get_elevation_m(const SGGeod &geod, double &alt, const simgear::BVHMaterial **material, const osg::Node *butNotFrom=0)
Compute the elevation of the scenery at geodetic latitude lat, geodetic longitude lon and not higher ...
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.