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:
parent
1365a02aea
commit
ca7acb1f2c
@ -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())
|
||||
);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user