Add support for Slippy Map Canvas layers.
- Add so-called Web Mercator projection and ability to choose projection for a Canvas Map. - Add supporting functions for Slippy Maps (i.e. OSM)
This commit is contained in:
@@ -47,6 +47,12 @@ namespace canvas
|
||||
const std::string GEO = "-geo";
|
||||
const std::string HDG = "hdg";
|
||||
const std::string Map::TYPE_NAME = "map";
|
||||
const std::string WEB_MERCATOR = "webmercator";
|
||||
const std::string REF_LAT = "ref-lat";
|
||||
const std::string REF_LON = "ref-lon";
|
||||
const std::string SCREEN_RANGE = "screen-range";
|
||||
const std::string RANGE = "range";
|
||||
const std::string PROJECTION = "projection";
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Map::staticInit()
|
||||
@@ -64,12 +70,16 @@ namespace canvas
|
||||
const SGPropertyNode_ptr& node,
|
||||
const Style& parent_style,
|
||||
ElementWeakPtr parent ):
|
||||
Group(canvas, node, parent_style, parent),
|
||||
// TODO make projection configurable
|
||||
_projection(new SansonFlamsteedProjection),
|
||||
_projection_dirty(true)
|
||||
Group(canvas, node, parent_style, parent)
|
||||
{
|
||||
staticInit();
|
||||
if (node->getChild(PROJECTION) &&
|
||||
(node->getChild(PROJECTION)->getStringValue() == WEB_MERCATOR)) {
|
||||
_projection = (boost::shared_ptr<HorizontalProjection>) new WebMercatorProjection();
|
||||
} else {
|
||||
_projection = (boost::shared_ptr<HorizontalProjection>) new SansonFlamsteedProjection();
|
||||
}
|
||||
_projection_dirty = true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -162,10 +172,10 @@ namespace canvas
|
||||
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") );
|
||||
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());
|
||||
@@ -174,11 +184,23 @@ namespace canvas
|
||||
++it )
|
||||
hdgNodeChanged(*it);
|
||||
}
|
||||
else if( child->getNameString() == "range" )
|
||||
else if( child->getNameString() == RANGE )
|
||||
_projection->setRange(child->getDoubleValue());
|
||||
else if( child->getNameString() == "screen-range" )
|
||||
else if( child->getNameString() == SCREEN_RANGE )
|
||||
_projection->setScreenRange(child->getDoubleValue());
|
||||
else
|
||||
else if( child->getNameString() == PROJECTION ) {
|
||||
if (child->getStringValue() == WEB_MERCATOR) {
|
||||
_projection = (boost::shared_ptr<HorizontalProjection>) new WebMercatorProjection();
|
||||
} else {
|
||||
_projection = (boost::shared_ptr<HorizontalProjection>) new SansonFlamsteedProjection();
|
||||
}
|
||||
_projection->setWorldPosition(_node->getDoubleValue(REF_LAT),
|
||||
_node->getDoubleValue(REF_LON) );
|
||||
_projection->setOrientation(_node->getFloatValue(HDG));
|
||||
_projection->setScreenRange(_node->getDoubleValue(SCREEN_RANGE));
|
||||
_projection->setRange(_node->getDoubleValue(RANGE));
|
||||
_projection_dirty = true;
|
||||
} else
|
||||
return Group::childChanged(child);
|
||||
|
||||
_projection_dirty = true;
|
||||
|
||||
@@ -190,6 +190,32 @@ namespace canvas
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* WebMercator projection, relative to the projection center.
|
||||
* Required for Slippy Maps - i.e. openstreetmap
|
||||
*/
|
||||
class WebMercatorProjection:
|
||||
public HorizontalProjection
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual ScreenPosition project(double lat, double lon) const
|
||||
{
|
||||
double d_lat = lat - _ref_lat,
|
||||
d_lon = lon - _ref_lon;
|
||||
double r = 6378137.f / 1852; // Equatorial radius divided by ?
|
||||
|
||||
ScreenPosition pos;
|
||||
|
||||
pos.x = r * d_lon;
|
||||
pos.y = r * (log(tan(d_lat) + 1.0 / cos(d_lat)));
|
||||
//pos.x = lon;
|
||||
//pos.y = log(tan(lat) + 1.0 / cos(lat));
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace canvas
|
||||
} // namespace simgear
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ static naRef f_fmod(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef b = naNumValue(argc > 1 ? args[1] : naNil());
|
||||
if(naIsNil(a) || naIsNil(b))
|
||||
naRuntimeError(c, "non numeric arguments to fmod()");
|
||||
|
||||
|
||||
a.num = fmod(a.num, b.num);
|
||||
return VALIDATE(a);
|
||||
}
|
||||
@@ -119,7 +119,7 @@ static naRef f_clamp(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
naRef min = naNumValue(argc > 1 ? args[1] : naNil());
|
||||
naRef max = naNumValue(argc > 2 ? args[2] : naNil());
|
||||
|
||||
|
||||
if(naIsNil(a) || naIsNil(min) || naIsNil(max))
|
||||
naRuntimeError(c, "non numeric arguments to clamp()");
|
||||
|
||||
@@ -133,10 +133,10 @@ static naRef f_periodic(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
naRef b = naNumValue(argc > 1 ? args[1] : naNil());
|
||||
naRef x = naNumValue(argc > 2 ? args[2] : naNil());
|
||||
|
||||
|
||||
if(naIsNil(a) || naIsNil(b) || naIsNil(x))
|
||||
naRuntimeError(c, "non numeric arguments to periodic()");
|
||||
|
||||
|
||||
range = b.num - a.num;
|
||||
x.num = x.num - range*floor((x.num - a.num)/range);
|
||||
// two security checks that can only happen due to roundoff
|
||||
@@ -145,7 +145,7 @@ static naRef f_periodic(naContext c, naRef me, int argc, naRef* args)
|
||||
if (b.num <= x.num)
|
||||
x.num = b.num;
|
||||
return VALIDATE(x);
|
||||
|
||||
|
||||
// x.num = SGMiscd::normalizePeriodic(a, b, x);
|
||||
return VALIDATE(x);
|
||||
}
|
||||
@@ -156,7 +156,7 @@ static naRef f_round(naContext c, naRef me, int argc, naRef* args)
|
||||
naRef b = naNumValue(argc > 1 ? args[1] : naNil());
|
||||
#ifdef _MSC_VER
|
||||
double x,y;
|
||||
#endif
|
||||
#endif
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric arguments to round()");
|
||||
if (naIsNil(b))
|
||||
@@ -169,21 +169,31 @@ static naRef f_round(naContext c, naRef me, int argc, naRef* args)
|
||||
double x = round(a.num / b.num);
|
||||
#endif
|
||||
a.num = x * b.num;
|
||||
|
||||
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
|
||||
static naRef f_tan(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric arguments to tan()");
|
||||
|
||||
|
||||
a.num = tan(a.num);
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_atan(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
if(naIsNil(a))
|
||||
naRuntimeError(c, "non numeric arguments to tan()");
|
||||
|
||||
a.num = atan(a.num);
|
||||
return VALIDATE(a);
|
||||
}
|
||||
|
||||
static naRef f_asin(naContext c, naRef me, int argc, naRef* args)
|
||||
{
|
||||
naRef a = naNumValue(argc > 0 ? args[0] : naNil());
|
||||
@@ -210,15 +220,16 @@ static naCFuncItem funcs[] = {
|
||||
{ "pow", f_pow },
|
||||
{ "sqrt", f_sqrt },
|
||||
{ "atan2", f_atan2 },
|
||||
{ "atan", f_atan },
|
||||
{ "floor", f_floor },
|
||||
{ "ceil", f_ceil },
|
||||
{ "fmod", f_fmod },
|
||||
{ "clamp", f_clamp },
|
||||
{ "periodic", f_periodic },
|
||||
{ "round", f_round },
|
||||
{ "tan", f_tan },
|
||||
{ "periodic", f_periodic },
|
||||
{ "round", f_round },
|
||||
{ "tan", f_tan },
|
||||
{ "acos", f_acos },
|
||||
{ "asin", f_asin },
|
||||
{ "asin", f_asin },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user