diff --git a/simgear/canvas/elements/CanvasMap.cxx b/simgear/canvas/elements/CanvasMap.cxx index cca235b4..e15dc13b 100644 --- a/simgear/canvas/elements/CanvasMap.cxx +++ b/simgear/canvas/elements/CanvasMap.cxx @@ -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) new WebMercatorProjection(); + } else { + _projection = (boost::shared_ptr) 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) new WebMercatorProjection(); + } else { + _projection = (boost::shared_ptr) 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; diff --git a/simgear/canvas/elements/map/projection.hxx b/simgear/canvas/elements/map/projection.hxx index d60f7d5f..e58b9f94 100644 --- a/simgear/canvas/elements/map/projection.hxx +++ b/simgear/canvas/elements/map/projection.hxx @@ -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 diff --git a/simgear/nasal/mathlib.c b/simgear/nasal/mathlib.c index 564168c5..7c8210f0 100644 --- a/simgear/nasal/mathlib.c +++ b/simgear/nasal/mathlib.c @@ -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 } };