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:
Stuart Buchanan
2017-09-28 15:32:47 +01:00
parent b342245619
commit a800189c25
3 changed files with 83 additions and 24 deletions

View File

@@ -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;

View File

@@ -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

View File

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