canvas::Map: Property to keep children aligned to given hdg.

Setting the 'hdg' property on child elements will rotate
them with respect to the heading set on the map projection.
This commit is contained in:
Thomas Geymayer 2015-02-26 22:34:21 +01:00
parent 1365a02aea
commit ca7acb1f2c
3 changed files with 134 additions and 77 deletions

View 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,39 +113,83 @@ namespace canvas
//----------------------------------------------------------------------------
void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
{
if( !boost::ends_with(child->getNameString(), GEO) )
return Element::childAdded(parent, child);
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);
}
//----------------------------------------------------------------------------
void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
{
if( !boost::ends_with(child->getNameString(), GEO) )
return Element::childRemoved(parent, child);
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);
}
//----------------------------------------------------------------------------
void Map::valueChanged(SGPropertyNode* child)
{
if( child->getParent() != _node )
{
const std::string& name = child->getNameString();
if( !boost::ends_with(name, GEO) )
return Group::valueChanged(child);
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)
{
if( child->getParent() != _node )
return Group::childChanged(child);
if( child->getNameString() == "ref-lat"
|| child->getNameString() == "ref-lon" )
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
_node->getDoubleValue("ref-lon") );
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" )
_projection->setScreenRange(child->getDoubleValue());
else
return Group::childChanged(child);
_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("geo node not found!")
LOG_GEO_RET("GeoNode not found!")
GeoNodePair* geo_node = it_geo_node->second.get();
geo_node->setDirty();
if( geo_node->getStatus() & GeoNodePair::INCOMPLETE )
{
if( !(geo_node->getStatus() & GeoNodePair::INCOMPLETE) )
return;
// Detect lat, lon tuples...
GeoCoord coord = parseGeoCoord(child->getStringValue());
int index_other = -1;
@ -163,6 +208,7 @@ namespace canvas
LOG_GEO_RET("Invalid geo coord")
}
const std::string& name = child->getNameString();
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
if( !other )
return;
@ -189,28 +235,14 @@ namespace canvas
// Set name for resulting screen coordinate nodes
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
}
}
//----------------------------------------------------------------------------
void Map::childChanged(SGPropertyNode * child)
void Map::hdgNodeChanged(SGPropertyNode* child)
{
if( child->getParent() != _node )
return Group::childChanged(child);
if( child->getNameString() == "ref-lat"
|| child->getNameString() == "ref-lon" )
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
_node->getDoubleValue("ref-lon") );
else if( child->getNameString() == "hdg" )
_projection->setOrientation(child->getFloatValue());
else if( child->getNameString() == "range" )
_projection->setRange(child->getDoubleValue());
else if( child->getNameString() == "screen-range" )
_projection->setScreenRange(child->getDoubleValue());
else
return Group::childChanged(child);
_projection_dirty = true;
child->getParent()->setFloatValue(
"tf[0]/rot",
SGMiscf::deg2rad(child->getFloatValue() - _projection->orientation())
);
}
//----------------------------------------------------------------------------

View 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;
};

View 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;
};