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 GEO = "-geo";
|
||||||
|
const std::string HDG = "hdg";
|
||||||
const std::string Map::TYPE_NAME = "map";
|
const std::string Map::TYPE_NAME = "map";
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -112,87 +113,44 @@ 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) )
|
||||||
|
_geo_nodes[child].reset(new GeoNodePair());
|
||||||
|
else if( parent != _node && child->getNameString() == HDG )
|
||||||
|
_hdg_nodes.insert(child);
|
||||||
|
else
|
||||||
return Element::childAdded(parent, child);
|
return Element::childAdded(parent, child);
|
||||||
|
|
||||||
_geo_nodes[child].reset(new GeoNodePair());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
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) )
|
||||||
|
// 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);
|
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( child->getParent() != _node )
|
||||||
|
|
||||||
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 )
|
|
||||||
{
|
{
|
||||||
// Detect lat, lon tuples...
|
const std::string& name = child->getNameString();
|
||||||
GeoCoord coord = parseGeoCoord(child->getStringValue());
|
|
||||||
int index_other = -1;
|
|
||||||
|
|
||||||
switch( coord.type )
|
if( boost::ends_with(name, GEO) )
|
||||||
{
|
return geoNodeChanged(child);
|
||||||
case GeoCoord::LATITUDE:
|
else if( name == HDG )
|
||||||
index_other = child->getIndex() + 1;
|
return hdgNodeChanged(child);
|
||||||
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()) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Group::valueChanged(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
void Map::childChanged(SGPropertyNode * child)
|
void Map::childChanged(SGPropertyNode* child)
|
||||||
{
|
{
|
||||||
if( child->getParent() != _node )
|
if( child->getParent() != _node )
|
||||||
return Group::childChanged(child);
|
return Group::childChanged(child);
|
||||||
@ -201,8 +159,14 @@ namespace canvas
|
|||||||
|| child->getNameString() == "ref-lon" )
|
|| child->getNameString() == "ref-lon" )
|
||||||
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
|
_projection->setWorldPosition( _node->getDoubleValue("ref-lat"),
|
||||||
_node->getDoubleValue("ref-lon") );
|
_node->getDoubleValue("ref-lon") );
|
||||||
else if( child->getNameString() == "hdg" )
|
else if( child->getNameString() == HDG )
|
||||||
|
{
|
||||||
_projection->setOrientation(child->getFloatValue());
|
_projection->setOrientation(child->getFloatValue());
|
||||||
|
for( NodeSet::iterator it = _hdg_nodes.begin();
|
||||||
|
it != _hdg_nodes.end();
|
||||||
|
++it )
|
||||||
|
hdgNodeChanged(*it);
|
||||||
|
}
|
||||||
else if( child->getNameString() == "range" )
|
else if( child->getNameString() == "range" )
|
||||||
_projection->setRange(child->getDoubleValue());
|
_projection->setRange(child->getDoubleValue());
|
||||||
else if( child->getNameString() == "screen-range" )
|
else if( child->getNameString() == "screen-range" )
|
||||||
@ -213,6 +177,74 @@ namespace canvas
|
|||||||
_projection_dirty = true;
|
_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
|
Map::GeoCoord Map::parseGeoCoord(const std::string& val) const
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user