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:
@@ -44,6 +44,7 @@ namespace canvas
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
const std::string GEO = "-geo";
|
const std::string GEO = "-geo";
|
||||||
|
const std::string HDG = "hdg";
|
||||||
const std::string Map::TYPE_NAME = "map";
|
const std::string Map::TYPE_NAME = "map";
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@@ -112,39 +113,83 @@ namespace canvas
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
void Map::childAdded(SGPropertyNode* parent, SGPropertyNode* child)
|
||||||
{
|
{
|
||||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
if( boost::ends_with(child->getNameString(), GEO) )
|
||||||
return Element::childAdded(parent, child);
|
|
||||||
|
|
||||||
_geo_nodes[child].reset(new GeoNodePair());
|
_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)
|
void Map::childRemoved(SGPropertyNode* parent, SGPropertyNode* child)
|
||||||
{
|
{
|
||||||
if( !boost::ends_with(child->getNameString(), GEO) )
|
if( boost::ends_with(child->getNameString(), GEO) )
|
||||||
return Element::childRemoved(parent, child);
|
|
||||||
|
|
||||||
// TODO remove from other node
|
// TODO remove from other node
|
||||||
_geo_nodes.erase(child);
|
_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)
|
void Map::valueChanged(SGPropertyNode* child)
|
||||||
|
{
|
||||||
|
if( child->getParent() != _node )
|
||||||
{
|
{
|
||||||
const std::string& name = child->getNameString();
|
const std::string& name = child->getNameString();
|
||||||
|
|
||||||
if( !boost::ends_with(name, GEO) )
|
if( boost::ends_with(name, GEO) )
|
||||||
return Group::valueChanged(child);
|
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);
|
GeoNodes::iterator it_geo_node = _geo_nodes.find(child);
|
||||||
if( it_geo_node == _geo_nodes.end() )
|
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();
|
GeoNodePair* geo_node = it_geo_node->second.get();
|
||||||
|
|
||||||
geo_node->setDirty();
|
geo_node->setDirty();
|
||||||
|
|
||||||
if( geo_node->getStatus() & GeoNodePair::INCOMPLETE )
|
if( !(geo_node->getStatus() & GeoNodePair::INCOMPLETE) )
|
||||||
{
|
return;
|
||||||
|
|
||||||
// Detect lat, lon tuples...
|
// Detect lat, lon tuples...
|
||||||
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
||||||
int index_other = -1;
|
int index_other = -1;
|
||||||
@@ -163,6 +208,7 @@ namespace canvas
|
|||||||
LOG_GEO_RET("Invalid geo coord")
|
LOG_GEO_RET("Invalid geo coord")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& name = child->getNameString();
|
||||||
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
|
SGPropertyNode *other = child->getParent()->getChild(name, index_other);
|
||||||
if( !other )
|
if( !other )
|
||||||
return;
|
return;
|
||||||
@@ -189,28 +235,14 @@ namespace canvas
|
|||||||
// Set name for resulting screen coordinate nodes
|
// Set name for resulting screen coordinate nodes
|
||||||
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
|
geo_node->setTargetName( name.substr(0, name.length() - GEO.length()) );
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Map::childChanged(SGPropertyNode * child)
|
void Map::hdgNodeChanged(SGPropertyNode* child)
|
||||||
{
|
{
|
||||||
if( child->getParent() != _node )
|
child->getParent()->setFloatValue(
|
||||||
return Group::childChanged(child);
|
"tf[0]/rot",
|
||||||
|
SGMiscf::deg2rad(child->getFloatValue() - _projection->orientation())
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
@@ -59,14 +60,18 @@ namespace canvas
|
|||||||
typedef boost::unordered_map< SGPropertyNode*,
|
typedef boost::unordered_map< SGPropertyNode*,
|
||||||
boost::shared_ptr<GeoNodePair>
|
boost::shared_ptr<GeoNodePair>
|
||||||
> GeoNodes;
|
> GeoNodes;
|
||||||
|
typedef boost::unordered_set<SGPropertyNode*> NodeSet;
|
||||||
|
|
||||||
GeoNodes _geo_nodes;
|
GeoNodes _geo_nodes;
|
||||||
|
NodeSet _hdg_nodes;
|
||||||
boost::shared_ptr<HorizontalProjection> _projection;
|
boost::shared_ptr<HorizontalProjection> _projection;
|
||||||
bool _projection_dirty;
|
bool _projection_dirty;
|
||||||
|
|
||||||
struct GeoCoord
|
struct GeoCoord
|
||||||
{
|
{
|
||||||
GeoCoord():
|
GeoCoord():
|
||||||
type(INVALID)
|
type(INVALID),
|
||||||
|
value(0)
|
||||||
{}
|
{}
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@@ -77,6 +82,9 @@ namespace canvas
|
|||||||
double value;
|
double value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void geoNodeChanged(SGPropertyNode * child);
|
||||||
|
void hdgNodeChanged(SGPropertyNode * child);
|
||||||
|
|
||||||
GeoCoord parseGeoCoord(const std::string& val) const;
|
GeoCoord parseGeoCoord(const std::string& val) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,10 @@ namespace canvas
|
|||||||
public:
|
public:
|
||||||
struct ScreenPosition
|
struct ScreenPosition
|
||||||
{
|
{
|
||||||
ScreenPosition() {}
|
ScreenPosition():
|
||||||
|
x(0),
|
||||||
|
y(0)
|
||||||
|
{}
|
||||||
|
|
||||||
ScreenPosition(double x, double y):
|
ScreenPosition(double x, double y):
|
||||||
x(x),
|
x(x),
|
||||||
@@ -67,8 +70,11 @@ namespace canvas
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
HorizontalProjection():
|
HorizontalProjection():
|
||||||
_cos_rot(1),
|
_ref_lat(0),
|
||||||
_sin_rot(0),
|
_ref_lon(0),
|
||||||
|
_angle(0),
|
||||||
|
_cos_angle(1),
|
||||||
|
_sin_angle(0),
|
||||||
_range(5)
|
_range(5)
|
||||||
{
|
{
|
||||||
setScreenRange(200);
|
setScreenRange(200);
|
||||||
@@ -88,9 +94,19 @@ namespace canvas
|
|||||||
*/
|
*/
|
||||||
void setOrientation(float hdg)
|
void setOrientation(float hdg)
|
||||||
{
|
{
|
||||||
|
_angle = hdg;
|
||||||
|
|
||||||
hdg = SGMiscf::deg2rad(hdg);
|
hdg = SGMiscf::deg2rad(hdg);
|
||||||
_sin_rot = sin(hdg);
|
_sin_angle = sin(hdg);
|
||||||
_cos_rot = cos(hdg);
|
_cos_angle = cos(hdg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get orientation/heading of the projection (in degree)
|
||||||
|
*/
|
||||||
|
float orientation() const
|
||||||
|
{
|
||||||
|
return _angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setRange(double range)
|
void setRange(double range)
|
||||||
@@ -114,8 +130,8 @@ namespace canvas
|
|||||||
pos.y *= scale;
|
pos.y *= scale;
|
||||||
return ScreenPosition
|
return ScreenPosition
|
||||||
(
|
(
|
||||||
_cos_rot * pos.x - _sin_rot * pos.y,
|
_cos_angle * pos.x - _sin_angle * pos.y,
|
||||||
-_sin_rot * pos.x - _cos_rot * 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;
|
virtual ScreenPosition project(double lat, double lon) const = 0;
|
||||||
|
|
||||||
double _ref_lat,
|
double _ref_lat, ///<! Reference latitude (radian)
|
||||||
_ref_lon,
|
_ref_lon, ///<! Reference latitude (radian)
|
||||||
_cos_rot,
|
_angle, ///<! Map rotation angle (degree)
|
||||||
_sin_rot,
|
_cos_angle,
|
||||||
|
_sin_angle,
|
||||||
_range;
|
_range;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user