-// terrainsampler.cxx --\r
-//\r
-// Written by Torsten Dreyer, started July 2010\r
-// Based on local weather implementation in nasal from \r
-// Thorsten Renk\r
-//\r
-// Copyright (C) 2010 Curtis Olson\r
-//\r
-// This program is free software; you can redistribute it and/or\r
-// modify it under the terms of the GNU General Public License as\r
-// published by the Free Software Foundation; either version 2 of the\r
-// License, or (at your option) any later version.\r
-//\r
-// This program is distributed in the hope that it will be useful, but\r
-// WITHOUT ANY WARRANTY; without even the implied warranty of\r
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-// General Public License for more details.\r
-//\r
-// You should have received a copy of the GNU General Public License\r
-// along with this program; if not, write to the Free Software\r
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\r
-//\r
-#ifdef HAVE_CONFIG_H\r
-# include <config.h>\r
-#endif\r
-\r
-#include <Main/fg_props.hxx>\r
-#include <simgear/math/sg_random.h>\r
-#include <Scenery/scenery.hxx>\r
-#include <deque>\r
-\r
-#include "terrainsampler.hxx"\r
-using simgear::PropertyList;\r
-\r
-#include "tiedpropertylist.hxx"\r
-\r
-namespace Environment {\r
-/**\r
- * @brief Class for presampling the terrain roughness\r
- */\r
-class AreaSampler : public SGSubsystem {\r
-public:\r
- AreaSampler( SGPropertyNode_ptr rootNode );\r
- virtual ~AreaSampler();\r
- void update( double dt );\r
- void bind();\r
- void unbind();\r
-\r
- double getOrientationDeg() const { return _orientation_rad * SG_RADIANS_TO_DEGREES; }\r
- void setOrientationDeg( double value ) { _orientation_rad = value * SG_DEGREES_TO_RADIANS; }\r
-\r
- int getElevationHistogramStep() const { return _elevationHistogramStep; }\r
- void setElevationHistograpStep( int value ) { \r
- _elevationHistogramStep = value > 0 ? value : 500;\r
- _elevationHistogramCount = _elevationHistogramMax / _elevationHistogramStep;\r
- }\r
-\r
- int getElevationHistogramMax() const { return _elevationHistogramMax; }\r
- void setElevationHistograpMax( int value ) { \r
- _elevationHistogramMax = value > 0 ? value : 10000;\r
- _elevationHistogramCount = _elevationHistogramMax / _elevationHistogramStep;\r
- }\r
-\r
- int getElevationHistogramCount() const { return _elevationHistogramCount; }\r
-\r
-private:\r
- void analyse();\r
-\r
- SGPropertyNode_ptr _rootNode;\r
-\r
- bool _enabled;\r
- bool _useAircraftPosition;\r
- double _latitude_deg;\r
- double _longitude_deg;\r
- double _orientation_rad;\r
- int _radius;\r
- int _samples_per_frame;\r
- int _max_samples; // keep xx samples in queue for analysis\r
- int _analyze_every; // Run analysis every xx samples\r
- int _elevationHistogramMax;\r
- int _elevationHistogramStep;\r
- int _elevationHistogramCount;\r
-\r
- double _altOffset;\r
- double _altMedian;\r
- double _altMin;\r
- double _altLayered;\r
- double _altMean;\r
-\r
- SGPropertyNode_ptr _positionLatitudeNode;\r
- SGPropertyNode_ptr _positionLongitudeNode;\r
-\r
- deque<double> elevations;\r
- TiedPropertyList _tiedProperties;\r
-};\r
-\r
-AreaSampler::AreaSampler( SGPropertyNode_ptr rootNode ) :\r
- _rootNode(rootNode),\r
- _enabled(true),\r
- _useAircraftPosition(false),\r
- _latitude_deg(0.0),\r
- _longitude_deg(0.0),\r
- _orientation_rad(0.0),\r
- _radius(40000.0),\r
- _samples_per_frame(5),\r
- _max_samples(1000),\r
- _analyze_every(200),\r
- _elevationHistogramMax(10000),\r
- _elevationHistogramStep(500),\r
- _elevationHistogramCount(_elevationHistogramMax/_elevationHistogramStep),\r
- _altOffset(0),\r
- _altMedian(0),\r
- _altMin(0),\r
- _altLayered(0),\r
- _altMean(0)\r
-{\r
- _positionLatitudeNode = fgGetNode( "/position/latitude-deg", true );\r
- _positionLongitudeNode = fgGetNode( "/position/longitude-deg", true );\r
-}\r
-\r
-AreaSampler::~AreaSampler()\r
-{\r
-}\r
-\r
-\r
-void AreaSampler::bind()\r
-{\r
- _tiedProperties.setRoot( _rootNode );\r
- _tiedProperties.Tie( "enabled", &_enabled );\r
-\r
- _tiedProperties.setRoot( _rootNode->getNode( "input", true ) );\r
- _tiedProperties.Tie( "use-aircraft-position", &_useAircraftPosition );\r
- _tiedProperties.Tie( "latitude-deg", &_latitude_deg );\r
- _tiedProperties.Tie( "latitude-deg", &_latitude_deg );\r
- _tiedProperties.Tie( "longitude-deg", &_longitude_deg );\r
- _tiedProperties.Tie( "orientation-deg", this, &AreaSampler::getOrientationDeg, &AreaSampler::setOrientationDeg );\r
- _tiedProperties.Tie( "radius-m", &_radius );\r
- _tiedProperties.Tie( "max-samples-per-frame", &_samples_per_frame );\r
- _tiedProperties.Tie( "max-samples", &_max_samples );\r
- _tiedProperties.Tie( "analyse-every", &_analyze_every );\r
- _tiedProperties.Tie( "elevation-histogram-max-ft", this, &AreaSampler::getElevationHistogramMax, &AreaSampler::setElevationHistograpMax );\r
- _tiedProperties.Tie( "elevation-histogram-step-ft", this, &AreaSampler::getElevationHistogramStep, &AreaSampler::setElevationHistograpStep );\r
- _tiedProperties.Tie( "elevation-histogram-count", this, &AreaSampler::getElevationHistogramCount );\r
-\r
- _tiedProperties.setRoot( _rootNode->getNode( "output", true ) );\r
- _tiedProperties.Tie( "alt-offset-ft", &_altOffset );\r
- _tiedProperties.Tie( "alt-median-ft", &_altMedian );\r
- _tiedProperties.Tie( "alt-min-ft", &_altMin );\r
- _tiedProperties.Tie( "alt-layered-ft", &_altLayered );\r
- _tiedProperties.Tie( "alt-mean-ft", &_altMean );\r
-}\r
-\r
-void AreaSampler::unbind()\r
-{\r
- _tiedProperties.Untie();\r
-}\r
-\r
-void AreaSampler::update( double dt )\r
-{\r
- if( !(_enabled && dt > SGLimitsd::min()) )\r
- return;\r
-\r
- if( _useAircraftPosition ) {\r
- _longitude_deg = _positionLongitudeNode->getDoubleValue();\r
- _latitude_deg = _positionLatitudeNode->getDoubleValue();\r
- }\r
-\r
- SGGeoc center = SGGeoc::fromGeod( SGGeod::fromDegM( _longitude_deg, _latitude_deg, SG_MAX_ELEVATION_M ) );\r
-\r
- FGScenery * scenery = globals->get_scenery();\r
- for( int i = 0; \r
- i < _samples_per_frame; \r
- i++ ) {\r
-\r
- double distance = sg_random() * _radius;\r
- double course = sg_random() * 2.0 * SG_PI;\r
- SGGeod probe = SGGeod::fromGeoc(center.advanceRadM( course, distance ));\r
- double elevation_m = 0.0;\r
- if (scenery->get_elevation_m( probe, elevation_m, NULL ))\r
- elevations.push_front(elevation_m *= SG_METER_TO_FEET);\r
- \r
- if( elevations.size() >= (deque<unsigned>::size_type)_max_samples ) {\r
- analyse();\r
- elevations.resize( _max_samples - _analyze_every );\r
- }\r
- }\r
-}\r
-\r
-void AreaSampler::analyse()\r
-{\r
- double sum;\r
-\r
- vector<int> histogram(_elevationHistogramCount,0);\r
- \r
- for( deque<double>::size_type i = 0; i < elevations.size(); i++ ) {\r
- int idx = SGMisc<int>::clip( (int)(elevations[i]/_elevationHistogramStep), 0, histogram.size()-1 );\r
- histogram[idx]++;\r
- }\r
-\r
- _altMedian = 0.0;\r
- sum = 0.0;\r
- for( vector<int>::size_type i = 0; i < histogram.size(); i++ ) {\r
- sum += histogram[i];\r
- if( sum > 0.5 * elevations.size() ) {\r
- _altMedian = i * _elevationHistogramStep;\r
- break;\r
- }\r
- }\r
-\r
- _altOffset = 0.0;\r
- sum = 0.0;\r
- for( vector<int>::size_type i = 0; i < histogram.size(); i++ ) {\r
- sum += histogram[i];\r
- if( sum > 0.3 * elevations.size() ) {\r
- _altOffset = i * _elevationHistogramStep;\r
- break;\r
- }\r
- }\r
-\r
- _altMean = 0.0;\r
- for( vector<int>::size_type i = 0; i < histogram.size(); i++ ) {\r
- _altMean += histogram[i] * i;\r
- }\r
- _altMean *= _elevationHistogramStep;\r
- if( elevations.size() != 0.0 ) _altMean /= elevations.size();\r
-\r
- _altMin = 0.0;\r
- for( vector<int>::size_type i = 0; i < histogram.size(); i++ ) {\r
- if( histogram[i] > 0 ) {\r
- _altMin = i * _elevationHistogramStep;\r
- break;\r
- }\r
- }\r
-\r
- double alt_low_min = 0.0;\r
- double n_max = 0.0;\r
- sum = 0.0;\r
- for( vector<int>::size_type i = 0; i < histogram.size()-1; i++ ) {\r
- sum += histogram[i];\r
- if( histogram[i] > n_max ) n_max = histogram[i];\r
- if( n_max > histogram[i+1] && sum > 0.3*elevations.size()) {\r
- alt_low_min = i * _elevationHistogramStep;\r
- break;\r
- }\r
- }\r
-\r
- _altLayered = 0.5 * (_altMin + _altOffset);\r
-\r
-#if 0\r
- SG_LOG( SG_ALL, SG_ALERT, "TerrainPresampler - alalysis results:" <<\r
- " total:" << elevations.size() <<\r
- " mean:" << _altMean <<\r
- " median:" << _altMedian <<\r
- " min:" << _altMin <<\r
- " alt_20:" << _altOffset );\r
-#endif\r
-#if 0\r
-append(alt_50_array, alt_med);\r
-#endif\r
-}\r
-\r
-/* --------------------- End of AreaSampler implementation ------------- */\r
-\r
-/* --------------------- TerrainSamplerImplementation -------------------------- */\r
-\r
-class TerrainSamplerImplementation : public TerrainSampler\r
-{\r
-public:\r
- TerrainSamplerImplementation ( SGPropertyNode_ptr rootNode );\r
- virtual ~TerrainSamplerImplementation ();\r
- \r
- virtual void init ();\r
- virtual void reinit ();\r
- virtual void bind();\r
- virtual void unbind();\r
- virtual void update (double delta_time_sec);\r
-private:\r
- inline string areaSubsystemName( unsigned i ) {\r
- ostringstream name;\r
- name << "area" << i;\r
- return name.str();\r
- }\r
-\r
- SGPropertyNode_ptr _rootNode;\r
- bool _enabled;\r
- TiedPropertyList _tiedProperties;\r
-};\r
-\r
-TerrainSamplerImplementation::TerrainSamplerImplementation( SGPropertyNode_ptr rootNode ) :\r
- _rootNode( rootNode ),\r
- _enabled(true)\r
-{\r
-}\r
-\r
-TerrainSamplerImplementation::~TerrainSamplerImplementation()\r
-{\r
-}\r
-\r
-void TerrainSamplerImplementation::init()\r
-{\r
- PropertyList areaNodes = _rootNode->getChildren( "area" );\r
- \r
- for( PropertyList::size_type i = 0; i < areaNodes.size(); i++ )\r
- set_subsystem( areaSubsystemName(i), new AreaSampler( areaNodes[i] ) );\r
-\r
- SGSubsystemGroup::bind();// bind the subsystems before the get init()ed\r
- SGSubsystemGroup::init();\r
-}\r
-\r
-void TerrainSamplerImplementation::reinit()\r
-{\r
- for( unsigned i = 0;; i++ ) {\r
- string subsystemName = areaSubsystemName(i);\r
- SGSubsystem * subsys = get_subsystem( subsystemName );\r
- if( subsys == NULL )\r
- break;\r
- remove_subsystem( subsystemName );\r
- }\r
- \r
- init();\r
-}\r
-\r
-void TerrainSamplerImplementation::bind()\r
-{\r
- SGSubsystemGroup::bind();\r
- _tiedProperties.Tie( _rootNode->getNode("enabled",true), &_enabled );\r
-}\r
-\r
-void TerrainSamplerImplementation::unbind()\r
-{\r
- _tiedProperties.Untie();\r
- SGSubsystemGroup::unbind();\r
-}\r
-\r
-void TerrainSamplerImplementation::update( double dt )\r
-{\r
- if( !(_enabled && dt > SGLimitsd::min()) )\r
- return;\r
- SGSubsystemGroup::update(dt);\r
-}\r
-\r
-/* ----------------------------------------------------------------------- */\r
-\r
-/* implementation of the TerrainSampler factory to hide the implementation\r
- details */\r
-TerrainSampler::~TerrainSampler ()\r
-{\r
-}\r
-\r
-TerrainSampler * TerrainSampler::createInstance( SGPropertyNode_ptr rootNode )\r
-{\r
- return new TerrainSamplerImplementation( rootNode );\r
-}\r
-\r
-} // namespace\r
-\r
+// terrainsampler.cxx --
+//
+// Written by Torsten Dreyer, started July 2010
+// Based on local weather implementation in nasal from
+// Thorsten Renk
+//
+// Copyright (C) 2010 Curtis Olson
+//
+// 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.
+//
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Main/fg_props.hxx>
+#include <simgear/math/sg_random.h>
+#include <Scenery/scenery.hxx>
+#include <deque>
+
+#include "terrainsampler.hxx"
+using simgear::PropertyList;
+
+#include "tiedpropertylist.hxx"
+
+namespace Environment {
+/**
+ * @brief Class for presampling the terrain roughness
+ */
+class AreaSampler : public SGSubsystem {
+public:
+ AreaSampler( SGPropertyNode_ptr rootNode );
+ virtual ~AreaSampler();
+ void update( double dt );
+ void bind();
+ void unbind();
+
+ double getOrientationDeg() const { return _orientation_rad * SG_RADIANS_TO_DEGREES; }
+ void setOrientationDeg( double value ) { _orientation_rad = value * SG_DEGREES_TO_RADIANS; }
+
+ int getElevationHistogramStep() const { return _elevationHistogramStep; }
+ void setElevationHistograpStep( int value ) {
+ _elevationHistogramStep = value > 0 ? value : 500;
+ _elevationHistogramCount = _elevationHistogramMax / _elevationHistogramStep;
+ }
+
+ int getElevationHistogramMax() const { return _elevationHistogramMax; }
+ void setElevationHistograpMax( int value ) {
+ _elevationHistogramMax = value > 0 ? value : 10000;
+ _elevationHistogramCount = _elevationHistogramMax / _elevationHistogramStep;
+ }
+
+ int getElevationHistogramCount() const { return _elevationHistogramCount; }
+
+private:
+ void analyse();
+
+ SGPropertyNode_ptr _rootNode;
+
+ bool _enabled;
+ bool _useAircraftPosition;
+ double _latitude_deg;
+ double _longitude_deg;
+ double _orientation_rad;
+ int _radius;
+ int _samples_per_frame;
+ int _max_samples; // keep xx samples in queue for analysis
+ int _analyze_every; // Run analysis every xx samples
+ int _elevationHistogramMax;
+ int _elevationHistogramStep;
+ int _elevationHistogramCount;
+
+ double _altOffset;
+ double _altMedian;
+ double _altMin;
+ double _altLayered;
+ double _altMean;
+
+ SGPropertyNode_ptr _positionLatitudeNode;
+ SGPropertyNode_ptr _positionLongitudeNode;
+
+ deque<double> elevations;
+ TiedPropertyList _tiedProperties;
+};
+
+AreaSampler::AreaSampler( SGPropertyNode_ptr rootNode ) :
+ _rootNode(rootNode),
+ _enabled(true),
+ _useAircraftPosition(false),
+ _latitude_deg(0.0),
+ _longitude_deg(0.0),
+ _orientation_rad(0.0),
+ _radius(40000.0),
+ _samples_per_frame(5),
+ _max_samples(1000),
+ _analyze_every(200),
+ _elevationHistogramMax(10000),
+ _elevationHistogramStep(500),
+ _elevationHistogramCount(_elevationHistogramMax/_elevationHistogramStep),
+ _altOffset(0),
+ _altMedian(0),
+ _altMin(0),
+ _altLayered(0),
+ _altMean(0)
+{
+ _positionLatitudeNode = fgGetNode( "/position/latitude-deg", true );
+ _positionLongitudeNode = fgGetNode( "/position/longitude-deg", true );
+}
+
+AreaSampler::~AreaSampler()
+{
+}
+
+
+void AreaSampler::bind()
+{
+ _tiedProperties.setRoot( _rootNode );
+ _tiedProperties.Tie( "enabled", &_enabled );
+
+ _tiedProperties.setRoot( _rootNode->getNode( "input", true ) );
+ _tiedProperties.Tie( "use-aircraft-position", &_useAircraftPosition );
+ _tiedProperties.Tie( "latitude-deg", &_latitude_deg );
+ _tiedProperties.Tie( "latitude-deg", &_latitude_deg );
+ _tiedProperties.Tie( "longitude-deg", &_longitude_deg );
+ _tiedProperties.Tie( "orientation-deg", this, &AreaSampler::getOrientationDeg, &AreaSampler::setOrientationDeg );
+ _tiedProperties.Tie( "radius-m", &_radius );
+ _tiedProperties.Tie( "max-samples-per-frame", &_samples_per_frame );
+ _tiedProperties.Tie( "max-samples", &_max_samples );
+ _tiedProperties.Tie( "analyse-every", &_analyze_every );
+ _tiedProperties.Tie( "elevation-histogram-max-ft", this, &AreaSampler::getElevationHistogramMax, &AreaSampler::setElevationHistograpMax );
+ _tiedProperties.Tie( "elevation-histogram-step-ft", this, &AreaSampler::getElevationHistogramStep, &AreaSampler::setElevationHistograpStep );
+ _tiedProperties.Tie( "elevation-histogram-count", this, &AreaSampler::getElevationHistogramCount );
+
+ _tiedProperties.setRoot( _rootNode->getNode( "output", true ) );
+ _tiedProperties.Tie( "alt-offset-ft", &_altOffset );
+ _tiedProperties.Tie( "alt-median-ft", &_altMedian );
+ _tiedProperties.Tie( "alt-min-ft", &_altMin );
+ _tiedProperties.Tie( "alt-layered-ft", &_altLayered );
+ _tiedProperties.Tie( "alt-mean-ft", &_altMean );
+}
+
+void AreaSampler::unbind()
+{
+ _tiedProperties.Untie();
+}
+
+void AreaSampler::update( double dt )
+{
+ if( !(_enabled && dt > SGLimitsd::min()) )
+ return;
+
+ if( _useAircraftPosition ) {
+ _longitude_deg = _positionLongitudeNode->getDoubleValue();
+ _latitude_deg = _positionLatitudeNode->getDoubleValue();
+ }
+
+ SGGeoc center = SGGeoc::fromGeod( SGGeod::fromDegM( _longitude_deg, _latitude_deg, SG_MAX_ELEVATION_M ) );
+
+ FGScenery * scenery = globals->get_scenery();
+ for( int i = 0;
+ i < _samples_per_frame;
+ i++ ) {
+
+ double distance = sg_random() * _radius;
+ double course = sg_random() * 2.0 * SG_PI;
+ SGGeod probe = SGGeod::fromGeoc(center.advanceRadM( course, distance ));
+ double elevation_m = 0.0;
+ if (scenery->get_elevation_m( probe, elevation_m, NULL ))
+ elevations.push_front(elevation_m *= SG_METER_TO_FEET);
+
+ if( elevations.size() >= (deque<unsigned>::size_type)_max_samples ) {
+ analyse();
+ elevations.resize( _max_samples - _analyze_every );
+ }
+ }
+}
+
+void AreaSampler::analyse()
+{
+ double sum;
+
+ vector<int> histogram(_elevationHistogramCount,0);
+
+ for( deque<double>::size_type i = 0; i < elevations.size(); i++ ) {
+ int idx = SGMisc<int>::clip( (int)(elevations[i]/_elevationHistogramStep), 0, histogram.size()-1 );
+ histogram[idx]++;
+ }
+
+ _altMedian = 0.0;
+ sum = 0.0;
+ for( vector<int>::size_type i = 0; i < histogram.size(); i++ ) {
+ sum += histogram[i];
+ if( sum > 0.5 * elevations.size() ) {
+ _altMedian = i * _elevationHistogramStep;
+ break;
+ }
+ }
+
+ _altOffset = 0.0;
+ sum = 0.0;
+ for( vector<int>::size_type i = 0; i < histogram.size(); i++ ) {
+ sum += histogram[i];
+ if( sum > 0.3 * elevations.size() ) {
+ _altOffset = i * _elevationHistogramStep;
+ break;
+ }
+ }
+
+ _altMean = 0.0;
+ for( vector<int>::size_type i = 0; i < histogram.size(); i++ ) {
+ _altMean += histogram[i] * i;
+ }
+ _altMean *= _elevationHistogramStep;
+ if( elevations.size() != 0.0 ) _altMean /= elevations.size();
+
+ _altMin = 0.0;
+ for( vector<int>::size_type i = 0; i < histogram.size(); i++ ) {
+ if( histogram[i] > 0 ) {
+ _altMin = i * _elevationHistogramStep;
+ break;
+ }
+ }
+
+ double alt_low_min = 0.0;
+ double n_max = 0.0;
+ sum = 0.0;
+ for( vector<int>::size_type i = 0; i < histogram.size()-1; i++ ) {
+ sum += histogram[i];
+ if( histogram[i] > n_max ) n_max = histogram[i];
+ if( n_max > histogram[i+1] && sum > 0.3*elevations.size()) {
+ alt_low_min = i * _elevationHistogramStep;
+ break;
+ }
+ }
+
+ _altLayered = 0.5 * (_altMin + _altOffset);
+
+#if 0
+ SG_LOG( SG_ALL, SG_ALERT, "TerrainPresampler - alalysis results:" <<
+ " total:" << elevations.size() <<
+ " mean:" << _altMean <<
+ " median:" << _altMedian <<
+ " min:" << _altMin <<
+ " alt_20:" << _altOffset );
+#endif
+#if 0
+append(alt_50_array, alt_med);
+#endif
+}
+
+/* --------------------- End of AreaSampler implementation ------------- */
+
+/* --------------------- TerrainSamplerImplementation -------------------------- */
+
+class TerrainSamplerImplementation : public TerrainSampler
+{
+public:
+ TerrainSamplerImplementation ( SGPropertyNode_ptr rootNode );
+ virtual ~TerrainSamplerImplementation ();
+
+ virtual void init ();
+ virtual void reinit ();
+ virtual void bind();
+ virtual void unbind();
+ virtual void update (double delta_time_sec);
+private:
+ inline string areaSubsystemName( unsigned i ) {
+ ostringstream name;
+ name << "area" << i;
+ return name.str();
+ }
+
+ SGPropertyNode_ptr _rootNode;
+ bool _enabled;
+ TiedPropertyList _tiedProperties;
+};
+
+TerrainSamplerImplementation::TerrainSamplerImplementation( SGPropertyNode_ptr rootNode ) :
+ _rootNode( rootNode ),
+ _enabled(true)
+{
+}
+
+TerrainSamplerImplementation::~TerrainSamplerImplementation()
+{
+}
+
+void TerrainSamplerImplementation::init()
+{
+ PropertyList areaNodes = _rootNode->getChildren( "area" );
+
+ for( PropertyList::size_type i = 0; i < areaNodes.size(); i++ )
+ set_subsystem( areaSubsystemName(i), new AreaSampler( areaNodes[i] ) );
+
+ SGSubsystemGroup::bind();// bind the subsystems before the get init()ed
+ SGSubsystemGroup::init();
+}
+
+void TerrainSamplerImplementation::reinit()
+{
+ for( unsigned i = 0;; i++ ) {
+ string subsystemName = areaSubsystemName(i);
+ SGSubsystem * subsys = get_subsystem( subsystemName );
+ if( subsys == NULL )
+ break;
+ remove_subsystem( subsystemName );
+ }
+
+ init();
+}
+
+void TerrainSamplerImplementation::bind()
+{
+ SGSubsystemGroup::bind();
+ _tiedProperties.Tie( _rootNode->getNode("enabled",true), &_enabled );
+}
+
+void TerrainSamplerImplementation::unbind()
+{
+ _tiedProperties.Untie();
+ SGSubsystemGroup::unbind();
+}
+
+void TerrainSamplerImplementation::update( double dt )
+{
+ if( !(_enabled && dt > SGLimitsd::min()) )
+ return;
+ SGSubsystemGroup::update(dt);
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* implementation of the TerrainSampler factory to hide the implementation
+ details */
+TerrainSampler::~TerrainSampler ()
+{
+}
+
+TerrainSampler * TerrainSampler::createInstance( SGPropertyNode_ptr rootNode )
+{
+ return new TerrainSamplerImplementation( rootNode );
+}
+
+} // namespace
+