]> git.mxchange.org Git - flightgear.git/commitdiff
First step into implementing the local-weather system
authorTorsten Dreyer <Torsten@t3r.de>
Sat, 14 Aug 2010 20:42:31 +0000 (22:42 +0200)
committerTorsten Dreyer <Torsten@t3r.de>
Sat, 14 Aug 2010 20:42:31 +0000 (22:42 +0200)
This is the first part of the local-weather implementation
of Thorsten Renk, currently written entirly in Nasal. Here
comes the terrain-sampling subsystem as a first step. It is
not (yet) included in the build process which will be
performed when the system has a little matured.

src/Environment/terrainsampler.cxx [new file with mode: 0755]
src/Environment/terrainsampler.hxx [new file with mode: 0755]
src/Environment/tiedpropertylist.hxx [new file with mode: 0644]

diff --git a/src/Environment/terrainsampler.cxx b/src/Environment/terrainsampler.cxx
new file mode 100755 (executable)
index 0000000..0f65874
--- /dev/null
@@ -0,0 +1,356 @@
+// 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
diff --git a/src/Environment/terrainsampler.hxx b/src/Environment/terrainsampler.hxx
new file mode 100755 (executable)
index 0000000..58e7cb8
--- /dev/null
@@ -0,0 +1,38 @@
+// terrainsampler.hxx -- \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
+#ifndef _TERRAIN_SAMPLER_HXX\r
+#define _TERRAIN_SAMPLER_HXX\r
+\r
+#include <simgear/structure/subsystem_mgr.hxx>\r
+\r
+namespace Environment {\r
+class TerrainSampler : public SGSubsystemGroup\r
+{\r
+public:\r
+       virtual ~TerrainSampler();\r
+       static TerrainSampler * createInstance( SGPropertyNode_ptr rootNode );\r
+};\r
+\r
+} // namespace\r
+\r
+#endif
\ No newline at end of file
diff --git a/src/Environment/tiedpropertylist.hxx b/src/Environment/tiedpropertylist.hxx
new file mode 100644 (file)
index 0000000..dbb9cc4
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef __TIEDPROPERTYLIST_HXX
+#define  __TIEDPROPERTYLIST_HXX
+#include <simgear/props/props.hxx>
+using simgear::PropertyList;
+
+// Maybe this goes into SimGear's props.hxx later?
+class TiedPropertyList : PropertyList {
+public:
+    TiedPropertyList() {}
+    TiedPropertyList( SGPropertyNode_ptr root ) { _root = root; }
+
+    void setRoot( SGPropertyNode_ptr root ) { _root = root; }
+    SGPropertyNode_ptr getRoot() const { return _root; }
+
+    template<typename T> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, const SGRawValue<T> &rawValue, bool useDefault = true  ) {
+        bool success = node->tie( rawValue, useDefault );
+        if( success ) {
+            SG_LOG( SG_ALL, SG_INFO, "Tied " << node->getPath() );
+            push_back( node );
+        } else {
+#if PROPS_STANDALONE
+            cerr << "Failed to tie property " << node->getPath() << endl;
+#else
+            SG_LOG(SG_GENERAL, SG_WARN, "Failed to tie property " << node->getPath() );
+#endif
+        }
+        return node;
+    }
+
+    template <class V> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, V * value, bool useDefault = true ) {
+        return Tie( node, SGRawValuePointer<V>(value), useDefault );
+    }
+
+    template <class V> SGPropertyNode_ptr Tie( const char * relative_path, V * value, bool useDefault = true ) {
+        return Tie( _root->getNode(relative_path,true), SGRawValuePointer<V>(value), useDefault );
+    }
+
+    template <class V> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, V (*getter)(), void (*setter)(V) = 0, bool useDefault = true ) {
+        return Tie(node, SGRawValueFunctions<V>(getter, setter), useDefault );
+    }
+
+    template <class V> SGPropertyNode_ptr Tie( const char * relative_path, V (*getter)(), void (*setter)(V) = 0, bool useDefault = true ) {
+        return Tie(_root->getNode(relative_path, true), SGRawValueFunctions<V>(getter, setter), useDefault );
+    }
+
+    template <class V> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, int index, V (*getter)(int), void (*setter)(int, V) = 0, bool useDefault = true) {
+        return Tie( node, SGRawValueFunctionsIndexed<V>(index, getter, setter), useDefault );
+    }
+
+    template <class V> SGPropertyNode_ptr Tie( const char * relative_path, int index, V (*getter)(int), void (*setter)(int, V) = 0, bool useDefault = true) {
+        return Tie( _root->getNode( relative_path, true ), SGRawValueFunctionsIndexed<V>(index, getter, setter), useDefault );
+    }
+
+    template <class T, class V> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, T * obj, V (T::*getter)() const, void (T::*setter)(V) = 0, bool useDefault = true) {
+        return Tie( node, SGRawValueMethods<T,V>(*obj, getter, setter), useDefault );
+    }
+
+    template <class T, class V> SGPropertyNode_ptr Tie( const char * relative_path, T * obj, V (T::*getter)() const, void (T::*setter)(V) = 0, bool useDefault = true) {
+        return Tie( _root->getNode( relative_path, true), SGRawValueMethods<T,V>(*obj, getter, setter), useDefault );
+    }
+
+    template <class T, class V> SGPropertyNode_ptr Tie( SGPropertyNode_ptr node, T * obj, int index, V (T::*getter)(int) const, void (T::*setter)(int, V) = 0, bool useDefault = true) {
+        return Tie( node, SGRawValueMethodsIndexed<T,V>(*obj, index, getter, setter), useDefault);
+    }
+
+    template <class T, class V> SGPropertyNode_ptr Tie( const char * relative_path, T * obj, int index, V (T::*getter)(int) const, void (T::*setter)(int, V) = 0, bool useDefault = true) {
+        return Tie( _root->getNode( relative_path, true ), SGRawValueMethodsIndexed<T,V>(*obj, index, getter, setter), useDefault);
+    }
+
+    void Untie() {
+        while( size() > 0 ) {
+            SG_LOG( SG_ALL, SG_INFO, "untie of " << back()->getPath() );
+            back()->untie();
+            pop_back();
+        }
+    }
+private:
+    SGPropertyNode_ptr _root;
+};
+#endif