]> git.mxchange.org Git - simgear.git/commitdiff
canvas::Map: Property to keep children aligned to given hdg.
authorThomas Geymayer <tomgey@gmail.com>
Thu, 26 Feb 2015 21:34:21 +0000 (22:34 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Thu, 26 Feb 2015 21:34:21 +0000 (22:34 +0100)
Setting the 'hdg' property on child elements will rotate
them with respect to the heading set on the map projection.

simgear/canvas/elements/CanvasMap.cxx
simgear/canvas/elements/CanvasMap.hxx
simgear/canvas/elements/map/projection.hxx

index bbf5645e555e1a844e0714e4ef74d622cfbc224a..ee60bf24e774434720c7f1540d3778b7cb2a3ca9 100644 (file)
@@ -44,6 +44,7 @@ namespace canvas
 
   //----------------------------------------------------------------------------
   const std::string GEO = "-geo";
+  const std::string HDG = "hdg";
   const std::string Map::TYPE_NAME = "map";
 
   //----------------------------------------------------------------------------
@@ -112,87 +113,44 @@ namespace canvas
   //----------------------------------------------------------------------------
   void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
   {
-    if( !boost::ends_with(child->getNameString(), GEO) )
+    if( boost::ends_with(child->getNameString(), GEO) )
+      _geo_nodes[child].reset(new GeoNodePair());
+    else if( parent != _node && child->getNameString() == HDG )
+      _hdg_nodes.insert(child);
+    else
       return Element::childAdded(parent, child);
-
-    _geo_nodes[child].reset(new GeoNodePair());
   }
 
   //----------------------------------------------------------------------------
   void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
   {
-    if( !boost::ends_with(child->getNameString(), GEO) )
+    if( boost::ends_with(child->getNameString(), GEO) )
+      // TODO remove from other node
+      _geo_nodes.erase(child);
+    else if( parent != _node && child->getName() == HDG )
+      _hdg_nodes.erase(child);
+    else
       return Element::childRemoved(parent, child);
-
-    // TODO remove from other node
-    _geo_nodes.erase(child);
   }
 
   //----------------------------------------------------------------------------
-  void Map::valueChanged(SGPropertyNode * child)
+  void Map::valueChanged(SGPropertyNode* child)
   {
-    const std::string& name = child->getNameString();
-
-    if( !boost::ends_with(name, GEO) )
-      return Group::valueChanged(child);
-
-    GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
-    if( it_geo_node == _geo_nodes.end() )
-      LOG_GEO_RET("geo node not found!")
-    GeoNodePair* geo_node = it_geo_node->second.get();
-
-    geo_node->setDirty();
-
-    if( geo_node->getStatus() & GeoNodePair::INCOMPLETE )
+    if( child->getParent() != _node )
     {
-      // Detect lat, lon tuples...
-      GeoCoord coord = parseGeoCoord(child->getStringValue());
-      int index_other = -1;
-
-      switch( coord.type )
-      {
-        case GeoCoord::LATITUDE:
-          index_other = child->getIndex() + 1;
-          geo_node->setNodeLat(child);
-          break;
-        case GeoCoord::LONGITUDE:
-          index_other = child->getIndex() - 1;
-          geo_node->setNodeLon(child);
-          break;
-        default:
-          LOG_GEO_RET("Invalid geo coord")
-      }
-
-      SGPropertyNode *other = child->getParent()->getChild(name, index_other);
-      if( !other )
-        return;
-
-      GeoCoord coord_other = parseGeoCoord(other->getStringValue());
-      if(    coord_other.type == GeoCoord::INVALID
-          || coord_other.type == coord.type )
-        return;
-
-      GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
-      if( it_geo_node_other == _geo_nodes.end() )
-        LOG_GEO_RET("other geo node not found!")
-      GeoNodePair* geo_node_other = it_geo_node_other->second.get();
-
-      // Let use both nodes use the same GeoNodePair instance
-      if( geo_node_other != geo_node )
-        it_geo_node_other->second = it_geo_node->second;
-
-      if( coord_other.type == GeoCoord::LATITUDE )
-        geo_node->setNodeLat(other);
-      else
-        geo_node->setNodeLon(other);
-
-      // Set name for resulting screen coordinate nodes
-      geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
+      const std::string& name = child->getNameString();
+
+      if( boost::ends_with(name, GEO) )
+        return geoNodeChanged(child);
+      else if( name == HDG )
+        return hdgNodeChanged(child);
     }
+
+    return Group::valueChanged(child);
   }
 
   //----------------------------------------------------------------------------
-  void Map::childChanged(SGPropertyNode * child)
+  void Map::childChanged(SGPropertyNode* child)
   {
     if( child->getParent() != _node )
       return Group::childChanged(child);
@@ -201,8 +159,14 @@ namespace canvas
         || child->getNameString() == "ref-lon" )
       _projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
                                      _node->getDoubleValue("ref-lon") );
-    else if( child->getNameString() == "hdg" )
+    else if( child->getNameString() == HDG )
+    {
       _projection->setOrientation(child->getFloatValue());
+      for( NodeSet::iterator it = _hdg_nodes.begin();
+                             it != _hdg_nodes.end();
+                           ++it )
+        hdgNodeChanged(*it);
+    }
     else if( child->getNameString() == "range" )
       _projection->setRange(child->getDoubleValue());
     else if( child->getNameString() == "screen-range" )
@@ -213,6 +177,74 @@ namespace canvas
     _projection_dirty = true;
   }
 
+  //----------------------------------------------------------------------------
+  void Map::geoNodeChanged(SGPropertyNode* child)
+  {
+    GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
+    if( it_geo_node == _geo_nodes.end() )
+      LOG_GEO_RET("GeoNode not found!")
+    GeoNodePair* geo_node = it_geo_node->second.get();
+
+    geo_node->setDirty();
+
+    if( !(geo_node->getStatus() & GeoNodePair::INCOMPLETE) )
+      return;
+
+    // Detect lat, lon tuples...
+    GeoCoord coord = parseGeoCoord(child->getStringValue());
+    int index_other = -1;
+
+    switch( coord.type )
+    {
+      case GeoCoord::LATITUDE:
+        index_other = child->getIndex() + 1;
+        geo_node->setNodeLat(child);
+        break;
+      case GeoCoord::LONGITUDE:
+        index_other = child->getIndex() - 1;
+        geo_node->setNodeLon(child);
+        break;
+      default:
+        LOG_GEO_RET("Invalid geo coord")
+    }
+
+    const std::string& name = child->getNameString();
+    SGPropertyNode *other = child->getParent()->getChild(name, index_other);
+    if( !other )
+      return;
+
+    GeoCoord coord_other = parseGeoCoord(other->getStringValue());
+    if(    coord_other.type == GeoCoord::INVALID
+        || coord_other.type == coord.type )
+      return;
+
+    GeoNodes::iterator it_geo_node_other = _geo_nodes.find(other);
+    if( it_geo_node_other == _geo_nodes.end() )
+      LOG_GEO_RET("other geo node not found!")
+    GeoNodePair* geo_node_other = it_geo_node_other->second.get();
+
+    // Let use both nodes use the same GeoNodePair instance
+    if( geo_node_other != geo_node )
+      it_geo_node_other->second = it_geo_node->second;
+
+    if( coord_other.type == GeoCoord::LATITUDE )
+      geo_node->setNodeLat(other);
+    else
+      geo_node->setNodeLon(other);
+
+    // Set name for resulting screen coordinate nodes
+    geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
+  }
+
+  //----------------------------------------------------------------------------
+  void Map::hdgNodeChanged(SGPropertyNode* child)
+  {
+    child->getParent()->setFloatValue(
+      "tf[0]/rot",
+      SGMiscf::deg2rad(child->getFloatValue() - _projection->orientation())
+    );
+  }
+
   //----------------------------------------------------------------------------
   Map::GeoCoord Map::parseGeoCoord(const std::string& val) const
   {
index 6bd2e54d9a5ef43373895e8d7cdd336598b44548..4af74ac77ff1af5b12b03a9d99facbeeab15a09b 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <boost/shared_ptr.hpp>
 #include <boost/unordered_map.hpp>
+#include <boost/unordered_set.hpp>
 
 namespace simgear
 {
@@ -59,14 +60,18 @@ namespace canvas
       typedef boost::unordered_map< SGPropertyNode*,
                                     boost::shared_ptr<GeoNodePair>
                                   > GeoNodes;
+      typedef boost::unordered_set<SGPropertyNode*> NodeSet;
+
       GeoNodes _geo_nodes;
+      NodeSet  _hdg_nodes;
       boost::shared_ptr<HorizontalProjection> _projection;
       bool _projection_dirty;
 
       struct GeoCoord
       {
         GeoCoord():
-          type(INVALID)
+          type(INVALID),
+          value(0)
         {}
         enum
         {
@@ -77,6 +82,9 @@ namespace canvas
         double value;
       };
 
+      void geoNodeChanged(SGPropertyNode * child);
+      void hdgNodeChanged(SGPropertyNode * child);
+
       GeoCoord parseGeoCoord(const std::string& val) const;
   };
 
index 9a3f65d7488f6a6c0c8e3fd10c5a9dee6300d815..d60f7d5ffa73834eecdabb5717078423ff90526e 100644 (file)
@@ -34,7 +34,10 @@ namespace canvas
     public:
       struct ScreenPosition
       {
-        ScreenPosition() {}
+        ScreenPosition():
+          x(0),
+          y(0)
+        {}
 
         ScreenPosition(double x, double y):
           x(x),
@@ -67,8 +70,11 @@ namespace canvas
     public:
 
       HorizontalProjection():
-        _cos_rot(1),
-        _sin_rot(0),
+        _ref_lat(0),
+        _ref_lon(0),
+        _angle(0),
+        _cos_angle(1),
+        _sin_angle(0),
         _range(5)
       {
         setScreenRange(200);
@@ -88,9 +94,19 @@ namespace canvas
        */
       void setOrientation(float hdg)
       {
+        _angle = hdg;
+
         hdg = SGMiscf::deg2rad(hdg);
-        _sin_rot = sin(hdg);
-        _cos_rot = cos(hdg);
+        _sin_angle = sin(hdg);
+        _cos_angle = cos(hdg);
+      }
+
+      /**
+       * Get orientation/heading of the projection (in degree)
+       */
+      float orientation() const
+      {
+        return _angle;
       }
 
       void setRange(double range)
@@ -114,8 +130,8 @@ namespace canvas
         pos.y *= scale;
         return ScreenPosition
         (
-          _cos_rot * pos.x - _sin_rot * pos.y,
-         -_sin_rot * pos.x - _cos_rot * pos.y
+          _cos_angle * pos.x - _sin_angle * pos.y,
+         -_sin_angle * pos.x - _cos_angle * pos.y
         );
       }
 
@@ -129,10 +145,11 @@ namespace canvas
        */
       virtual ScreenPosition project(double lat, double lon) const = 0;
 
-      double  _ref_lat,
-              _ref_lon,
-              _cos_rot,
-              _sin_rot,
+      double  _ref_lat,   ///<! Reference latitude (radian)
+              _ref_lon,   ///<! Reference latitude (radian)
+              _angle,     ///<! Map rotation angle (degree)
+              _cos_angle,
+              _sin_angle,
               _range;
   };