Merge branch 'proj6' of https://github.com/mapnik/mapnik into cmake-support

This commit is contained in:
Mathis Logemann 2021-03-24 23:30:50 +01:00
commit 4eed15f87a
36 changed files with 644 additions and 518 deletions

View file

@ -1,6 +1,6 @@
# This file is part of Mapnik (c++ mapping toolkit) # This file is part of Mapnik (c++ mapping toolkit)
# #
# Copyright (C) 2017 Artem Pavlenko # Copyright (C) 2021 Artem Pavlenko
# #
# Mapnik is free software; you can redistribute it and/or # Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -66,7 +66,8 @@ SCONF_TEMP_DIR = '.sconf_temp'
BOOST_SEARCH_PREFIXES = ['/usr/local','/opt/local','/sw','/usr',] BOOST_SEARCH_PREFIXES = ['/usr/local','/opt/local','/sw','/usr',]
BOOST_MIN_VERSION = '1.61' BOOST_MIN_VERSION = '1.61'
#CAIRO_MIN_VERSION = '1.8.0' #CAIRO_MIN_VERSION = '1.8.0'
PROJ_MIN_VERSION = (7, 2, 0)
PROJ_MIN_VERSION_STRING = "%s.%s.%s" % PROJ_MIN_VERSION
HARFBUZZ_MIN_VERSION = (0, 9, 34) HARFBUZZ_MIN_VERSION = (0, 9, 34)
HARFBUZZ_MIN_VERSION_STRING = "%s.%s.%s" % HARFBUZZ_MIN_VERSION HARFBUZZ_MIN_VERSION_STRING = "%s.%s.%s" % HARFBUZZ_MIN_VERSION
@ -80,6 +81,7 @@ pretty_dep_names = {
'ogr':'OGR-enabled GDAL C++ Library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/OGR', 'ogr':'OGR-enabled GDAL C++ Library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/OGR',
'cairo':'Cairo C library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option', 'cairo':'Cairo C library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option',
'proj':'Proj C Projections library | configure with PROJ_LIBS & PROJ_INCLUDES | more info: http://trac.osgeo.org/proj/', 'proj':'Proj C Projections library | configure with PROJ_LIBS & PROJ_INCLUDES | more info: http://trac.osgeo.org/proj/',
'proj-min-version':'libproj >=%s required' % PROJ_MIN_VERSION_STRING,
'pg':'Postgres C Library required for PostGIS plugin | configure with pg_config program or configure with PG_LIBS & PG_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/PostGIS', 'pg':'Postgres C Library required for PostGIS plugin | configure with pg_config program or configure with PG_LIBS & PG_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/PostGIS',
'sqlite3':'SQLite3 C Library | configure with SQLITE_LIBS & SQLITE_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/SQLite', 'sqlite3':'SQLite3 C Library | configure with SQLITE_LIBS & SQLITE_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/SQLite',
'jpeg':'JPEG C library | configure with JPEG_LIBS & JPEG_INCLUDES', 'jpeg':'JPEG C library | configure with JPEG_LIBS & JPEG_INCLUDES',
@ -103,7 +105,7 @@ pretty_dep_names = {
'boost_regex_icu':'libboost_regex built with optional ICU unicode support is needed for unicode regex support in mapnik.', 'boost_regex_icu':'libboost_regex built with optional ICU unicode support is needed for unicode regex support in mapnik.',
'sqlite_rtree':'The SQLite plugin requires libsqlite3 built with RTREE support (-DSQLITE_ENABLE_RTREE=1)', 'sqlite_rtree':'The SQLite plugin requires libsqlite3 built with RTREE support (-DSQLITE_ENABLE_RTREE=1)',
'pgsql2sqlite_rtree':'The pgsql2sqlite program requires libsqlite3 built with RTREE support (-DSQLITE_ENABLE_RTREE=1)', 'pgsql2sqlite_rtree':'The pgsql2sqlite program requires libsqlite3 built with RTREE support (-DSQLITE_ENABLE_RTREE=1)',
'PROJ_LIB':'The directory where proj4 stores its data files. Must exist for proj4 to work correctly', 'PROJ_LIB':'The directory where proj stores its data files. Must exist for proj to work correctly',
'GDAL_DATA':'The directory where GDAL stores its data files. Must exist for GDAL to work correctly', 'GDAL_DATA':'The directory where GDAL stores its data files. Must exist for GDAL to work correctly',
'ICU_DATA':'The directory where icu stores its data files. If ICU reports a path, it must exist. ICU can also be built without .dat files and in that case this path is empty' 'ICU_DATA':'The directory where icu stores its data files. If ICU reports a path, it must exist. ICU can also be built without .dat files and in that case this path is empty'
} }
@ -407,7 +409,7 @@ opts.AddVariables(
BoolVariable('WEBP', 'Build Mapnik with WEBP read', 'True'), BoolVariable('WEBP', 'Build Mapnik with WEBP read', 'True'),
PathVariable('WEBP_INCLUDES', 'Search path for libwebp include files', '/usr/include', PathVariable.PathAccept), PathVariable('WEBP_INCLUDES', 'Search path for libwebp include files', '/usr/include', PathVariable.PathAccept),
PathVariable('WEBP_LIBS','Search path for libwebp library files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept), PathVariable('WEBP_LIBS','Search path for libwebp library files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept),
BoolVariable('PROJ', 'Build Mapnik with proj4 support to enable transformations between many different projections', 'True'), BoolVariable('PROJ', 'Build Mapnik with proj support to enable transformations between many different projections', 'True'),
PathVariable('PROJ_INCLUDES', 'Search path for PROJ.4 include files', '/usr/include', PathVariable.PathAccept), PathVariable('PROJ_INCLUDES', 'Search path for PROJ.4 include files', '/usr/include', PathVariable.PathAccept),
PathVariable('PROJ_LIBS', 'Search path for PROJ.4 library files', '/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept), PathVariable('PROJ_LIBS', 'Search path for PROJ.4 library files', '/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept),
('PG_INCLUDES', 'Search path for libpq (postgres client) include files', ''), ('PG_INCLUDES', 'Search path for libpq (postgres client) include files', ''),
@ -918,6 +920,31 @@ def CheckGdalData(context, silent=False):
context.Result('Failed to detect (mapnik-config will have null value)') context.Result('Failed to detect (mapnik-config will have null value)')
return value return value
def proj_version(context):
context.Message('Checking for Proj version >=%s...' % PROJ_MIN_VERSION_STRING)
ret, out = context.TryRun("""
#include "proj.h"
#include <stdio.h>
#define PROJ_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
PROJ_VERSION_MAJOR*10000+PROJ_VERSION_MINOR*100+PROJ_VERSION_PATCH)
int main()
{
printf("%d;%d.%d.%d", PROJ_VERSION_ATLEAST{min-version}, PROJ_VERSION_MAJOR, PROJ_VERSION_MINOR, PROJ_VERSION_PATCH);
return 0;
}
""".replace("{min-version}", str(PROJ_MIN_VERSION)),'.c')
if not ret:
context.Result('error (could not get version from proj.h)')
else:
ok_str, found_version_str = out.strip().split(';', 1)
major,minor,patch = found_version_str.split('.')
ret = int(ok_str), int(major)*10000+int(minor)*100+int(patch)
if ret:
context.Result('yes (found Proj %s)' % found_version_str)
else:
context.Result('no (found Proj %s)' % found_version_str)
return ret
def CheckProjData(context, silent=False): def CheckProjData(context, silent=False):
@ -925,51 +952,40 @@ def CheckProjData(context, silent=False):
context.Message('Checking for PROJ_LIB directory...') context.Message('Checking for PROJ_LIB directory...')
ret, out = context.TryRun(""" ret, out = context.TryRun("""
// This is narly, could eventually be replaced using https://github.com/OSGeo/proj.4/pull/551] #include <proj.h>
#include <proj_api.h>
#include <iostream> #include <iostream>
#include <cstring> #include <sstream>
#include <vector>
#include <string>
#include <fstream>
static void my_proj4_logger(void * user_data, int /*level*/, const char * msg) std::vector<std::string> split_searchpath(std::string const& paths)
{ {
std::string* posMsg = static_cast<std::string*>(user_data); std::vector<std::string> output;
*posMsg += msg; std::stringstream ss(paths);
std::string path;
for( std::string path;std::getline(ss, path, ':');)
{
output.push_back(path);
}
return output;
} }
// https://github.com/OSGeo/gdal/blob/ddbf6d39aa4b005a77ca4f27c2d61a3214f336f8/gdal/alg/gdalapplyverticalshiftgrid.cpp#L616-L633 int main()
{
std::string find_proj_path(const char * pszFilename) { PJ_INFO info = proj_info();
std::string osMsg; std::string result = info.searchpath;
std::string osFilename; for (auto path : split_searchpath(result))
projCtx ctx = pj_ctx_alloc();
pj_ctx_set_app_data(ctx, &osMsg);
pj_ctx_set_debug(ctx, PJ_LOG_DEBUG_MAJOR);
pj_ctx_set_logger(ctx, my_proj4_logger);
PAFile f = pj_open_lib(ctx, pszFilename, "rb");
if( f )
{ {
pj_ctx_fclose(ctx, f); std::ifstream file(path + "/proj.db");
if (file)
{
std::cout << path;
return 0;
}
} }
size_t nPos = osMsg.find("fopen("); return -1;
if( nPos != std::string::npos )
{
osFilename = osMsg.substr(nPos + strlen("fopen("));
nPos = osFilename.find(")");
if( nPos != std::string::npos )
osFilename = osFilename.substr(0, nPos);
}
pj_ctx_free(ctx);
return osFilename;
}
int main() {
std::string result = find_proj_path(" ");
std::cout << result;
if (result.empty()) {
return -1;
}
return 0;
} }
""", '.cpp') """, '.cpp')
@ -977,7 +993,7 @@ int main() {
if silent: if silent:
context.did_show_result=1 context.did_show_result=1
if ret: if ret:
context.Result('pj_open_lib returned %s' % value) context.Result('proj_info.searchpath returned %s' % value)
else: else:
context.Result('Failed to detect (mapnik-config will have null value)') context.Result('Failed to detect (mapnik-config will have null value)')
return value return value
@ -1215,7 +1231,7 @@ int main()
context.Result(ret) context.Result(ret)
return ret return ret
__cplusplus = {'14':'201402L', '17':'201703L'} __cplusplus = {'14':'201402L', '17':'201703L', '20':'202002L'}
def supports_cxx_std (context, silent=False): def supports_cxx_std (context, silent=False):
cplusplus_string = __cplusplus[env['CXX_STD']] cplusplus_string = __cplusplus[env['CXX_STD']]
@ -1245,6 +1261,7 @@ conf_tests = { 'prioritize_paths' : prioritize_paths,
'FindBoost' : FindBoost, 'FindBoost' : FindBoost,
'CheckBoost' : CheckBoost, 'CheckBoost' : CheckBoost,
'CheckIcuData' : CheckIcuData, 'CheckIcuData' : CheckIcuData,
'proj_version' : proj_version,
'CheckProjData' : CheckProjData, 'CheckProjData' : CheckProjData,
'CheckGdalData' : CheckGdalData, 'CheckGdalData' : CheckGdalData,
'CheckCairoHasFreetype' : CheckCairoHasFreetype, 'CheckCairoHasFreetype' : CheckCairoHasFreetype,
@ -1545,7 +1562,7 @@ if not preconfigured:
env['SKIPPED_DEPS'].append('jpeg') env['SKIPPED_DEPS'].append('jpeg')
if env['PROJ']: if env['PROJ']:
OPTIONAL_LIBSHEADERS.append(['proj', 'proj_api.h', False,'C','-DMAPNIK_USE_PROJ4']) OPTIONAL_LIBSHEADERS.append(['proj', 'proj.h', False,'C','-DMAPNIK_USE_PROJ'])
inc_path = env['%s_INCLUDES' % 'PROJ'] inc_path = env['%s_INCLUDES' % 'PROJ']
lib_path = env['%s_LIBS' % 'PROJ'] lib_path = env['%s_LIBS' % 'PROJ']
env.AppendUnique(CPPPATH = fix_path(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
@ -1697,6 +1714,13 @@ if not preconfigured:
else: else:
color_print(4, 'Could not find optional header or shared library for %s' % libname) color_print(4, 'Could not find optional header or shared library for %s' % libname)
env['SKIPPED_DEPS'].append(libname) env['SKIPPED_DEPS'].append(libname)
elif libname == 'proj':
result, version = conf.proj_version()
if not result:
env['SKIPPED_DEPS'].append('proj-min-version')
else:
env.Append(CPPDEFINES = define)
env.Append(CPPDEFINES = "-DPROJ_VERSION=%d" % version)
else: else:
env.Append(CPPDEFINES = define) env.Append(CPPDEFINES = define)
else: else:

View file

@ -9,6 +9,7 @@ test_env = env.Clone()
test_env['LIBS'] = [env['MAPNIK_NAME']] test_env['LIBS'] = [env['MAPNIK_NAME']]
test_env.AppendUnique(LIBS=copy(env['LIBMAPNIK_LIBS'])) test_env.AppendUnique(LIBS=copy(env['LIBMAPNIK_LIBS']))
test_env.AppendUnique(LIBS='mapnik-wkt') test_env.AppendUnique(LIBS='mapnik-wkt')
test_env.AppendUnique(LIBS='sqlite3')
if env['PLATFORM'] == 'Linux': if env['PLATFORM'] == 'Linux':
test_env.AppendUnique(LIBS='dl') test_env.AppendUnique(LIBS='dl')
test_env.AppendUnique(LIBS='rt') test_env.AppendUnique(LIBS='rt')

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Map[]> <!DOCTYPE Map[]>
<Map <Map
srs="+init=epsg:4326" srs="epsg:4326"
background-color="#dfd8c9"> background-color="#dfd8c9">
<Style name="style"> <Style name="style">
@ -10,7 +10,7 @@
</Rule> </Rule>
</Style> </Style>
<Layer name="layer" <Layer name="layer"
srs="+init=epsg:4326"> srs="epsg:4326">
<StyleName>style</StyleName> <StyleName>style</StyleName>
<Datasource> <Datasource>
<Parameter name="file">./valid.geotiff.tif</Parameter> <Parameter name="file">./valid.geotiff.tif</Parameter>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Map[]> <!DOCTYPE Map[]>
<Map <Map
srs="+init=epsg:4326" srs="epsg:4326"
background-color="#dfd8c9"> background-color="#dfd8c9">
<Style name="style"> <Style name="style">
@ -10,7 +10,7 @@
</Rule> </Rule>
</Style> </Style>
<Layer name="layer" <Layer name="layer"
srs="+init=epsg:4326"> srs="epsg:4326">
<StyleName>style</StyleName> <StyleName>style</StyleName>
<Datasource> <Datasource>
<Parameter name="file">./valid.geotiff.tif</Parameter> <Parameter name="file">./valid.geotiff.tif</Parameter>

View file

@ -24,7 +24,7 @@ public:
} }
bool operator()() const bool operator()() const
{ {
mapnik::Map m(256,256,"+init=epsg:3857"); mapnik::Map m(256,256,"epsg:3857");
mapnik::parameters params; mapnik::parameters params;
params["type"]="memory"; params["type"]="memory";

View file

@ -51,7 +51,7 @@ void render(mapnik::geometry::multi_polygon<double> const& geom,
agg::pixfmt_rgba32_plain pixf(buf); agg::pixfmt_rgba32_plain pixf(buf);
ren_base renb(pixf); ren_base renb(pixf);
renderer ren(renb); renderer ren(renb);
mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326")); mapnik::proj_transform prj_trans(mapnik::projection("epsg:4326"),mapnik::projection("epsg:4326"));
ren.color(agg::rgba8(127,127,127,255)); ren.color(agg::rgba8(127,127,127,255));
agg::rasterizer_scanline_aa<> ras; agg::rasterizer_scanline_aa<> ras;
for (auto const& poly : geom) for (auto const& poly : geom)

View file

@ -9,7 +9,7 @@ class test : public benchmark::test_case
std::string dest_; std::string dest_;
mapnik::box2d<double> from_; mapnik::box2d<double> from_;
mapnik::box2d<double> to_; mapnik::box2d<double> to_;
bool defer_proj4_init_; bool defer_proj_init_;
public: public:
test(mapnik::parameters const& params, test(mapnik::parameters const& params,
std::string const& src, std::string const& src,
@ -22,11 +22,11 @@ public:
dest_(dest), dest_(dest),
from_(from), from_(from),
to_(to), to_(to),
defer_proj4_init_(defer_proj) {} defer_proj_init_(defer_proj) {}
bool validate() const bool validate() const
{ {
mapnik::projection src(src_,defer_proj4_init_); mapnik::projection src(src_,defer_proj_init_);
mapnik::projection dest(dest_,defer_proj4_init_); mapnik::projection dest(dest_,defer_proj_init_);
mapnik::proj_transform tr(src,dest); mapnik::proj_transform tr(src,dest);
mapnik::box2d<double> bbox = from_; mapnik::box2d<double> bbox = from_;
if (!tr.forward(bbox)) return false; if (!tr.forward(bbox)) return false;
@ -38,15 +38,15 @@ public:
} }
bool operator()() const bool operator()() const
{ {
mapnik::projection src(src_,defer_proj_init_);
mapnik::projection dest(dest_,defer_proj_init_);
mapnik::proj_transform tr(src,dest);
for (std::size_t i=0;i<iterations_;++i) for (std::size_t i=0;i<iterations_;++i)
{ {
for (int j=-180;j<180;j=j+5) for (int j=-180;j<180;j=j+5)
{ {
for (int k=-85;k<85;k=k+5) for (int k=-85;k<85;k=k+5)
{ {
mapnik::projection src(src_,defer_proj4_init_);
mapnik::projection dest(dest_,defer_proj4_init_);
mapnik::proj_transform tr(src,dest);
mapnik::box2d<double> box(j,k,j,k); mapnik::box2d<double> box(j,k,j,k);
if (!tr.forward(box)) throw std::runtime_error("could not transform coords"); if (!tr.forward(box)) throw std::runtime_error("could not transform coords");
} }
@ -56,19 +56,19 @@ public:
} }
}; };
// echo -180 -60 | cs2cs -f "%.10f" +init=epsg:4326 +to +init=epsg:3857 // echo -180 -60 | cs2cs -f "%.10f" epsg:4326 +to epsg:3857
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
mapnik::box2d<double> from(-180,-80,180,80); mapnik::box2d<double> from(-180,-80,180,80);
mapnik::box2d<double> to(-20037508.3427892476,-15538711.0963092316,20037508.3427892476,15538711.0963092316); mapnik::box2d<double> to(-20037508.3427892476,-15538711.0963092316,20037508.3427892476,15538711.0963092316);
std::string from_str("+init=epsg:4326"); std::string from_str("epsg:4326");
std::string to_str("+init=epsg:3857"); std::string to_str("epsg:3857");
std::string from_str2("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"); std::string from_str2("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
std::string to_str2("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"); std::string to_str2("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over");
return benchmark::sequencer(argc, argv) return benchmark::sequencer(argc, argv)
.run<test>("lonlat->merc epsg", from_str, to_str, from, to, true) .run<test>("lonlat->merc epsg (internal)", from_str, to_str, from, to, true)
.run<test>("lonlat->merc literal", from_str2, to_str2, from, to, true) .run<test>("lonlat->merc literal (libproj)", from_str2, to_str2, from, to, true)
.run<test>("merc->lonlat epsg", to_str, from_str, to, from, true) .run<test>("merc->lonlat epsg (internal)", to_str, from_str, to, from, true)
.run<test>("merc->lonlat literal", to_str2, from_str2, to, from, true) .run<test>("merc->lonlat literal (libproj)", to_str2, from_str2, to, from, true)
.done(); .done();
} }

View file

@ -8,7 +8,7 @@ todo
- shrink icu data - shrink icu data
' '
MASON_VERSION="edb620c7" MASON_VERSION="485514d8"
function setup_mason() { function setup_mason() {
if [[ ! -d ./.mason ]]; then if [[ ! -d ./.mason ]]; then
@ -49,17 +49,17 @@ BOOST_VERSION="1.75.0"
function install_mason_deps() { function install_mason_deps() {
install ccache 3.3.1 install ccache 3.3.1
install zlib 1.2.8 install zlib 1.2.8
install jpeg_turbo 1.5.1 libjpeg install jpeg_turbo 1.5.2 libjpeg
install libpng 1.6.28 libpng install libpng 1.6.32 libpng
install libtiff 4.0.7 libtiff install libtiff 4.0.8 libtiff
install libpq 9.6.2 install libpq 9.6.5
install sqlite 3.17.0 libsqlite3 install sqlite 3.34.0 libsqlite3
install icu ${ICU_VERSION} install icu ${ICU_VERSION}
install proj 4.9.3 libproj install proj 7.2.1 libproj
install pixman 0.34.0 libpixman-1 install pixman 0.34.0 libpixman-1
install cairo 1.14.8 libcairo install cairo 1.14.8 libcairo
install webp 0.6.0 libwebp install webp 0.6.0 libwebp
install libgdal 2.1.3 libgdal install libgdal 2.2.3 libgdal
install boost ${BOOST_VERSION} install boost ${BOOST_VERSION}
install boost_libsystem ${BOOST_VERSION} install boost_libsystem ${BOOST_VERSION}
install boost_libfilesystem ${BOOST_VERSION} install boost_libfilesystem ${BOOST_VERSION}

View file

@ -41,7 +41,7 @@ if env['HAS_CAIRO']:
demo_env.Append(CPPDEFINES = '-DHAVE_CAIRO') demo_env.Append(CPPDEFINES = '-DHAVE_CAIRO')
libraries = [env['MAPNIK_NAME']] libraries = [env['MAPNIK_NAME']]
libraries.extend(copy(env['LIBMAPNIK_LIBS'])) libraries.extend([copy(env['LIBMAPNIK_LIBS']), 'sqlite3', 'pthread'])
rundemo = demo_env.Program('rundemo', source, LIBS=libraries) rundemo = demo_env.Program('rundemo', source, LIBS=libraries)
Depends(rundemo, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME'])) Depends(rundemo, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME']))

View file

@ -421,11 +421,11 @@ void MainWindow::set_default_extent(double x0,double y0, double x1, double y1)
if (map_ptr) if (map_ptr)
{ {
mapnik::projection prj(map_ptr->srs()); mapnik::projection prj(map_ptr->srs());
prj.forward(x0,y0); prj.forward(x0, y0);
prj.forward(x1,y1); prj.forward(x1, y1);
default_extent_=mapnik::box2d<double>(x0,y0,x1,y1); default_extent_=mapnik::box2d<double>(x0, y0, x1, y1);
mapWidget_->zoomToBox(default_extent_); mapWidget_->zoomToBox(default_extent_);
std::cout << "SET DEFAULT EXT\n"; std::cout << "SET DEFAULT EXT:" << default_extent_ << std::endl;
} }
} }
catch (...) {} catch (...) {}

View file

@ -23,7 +23,7 @@
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <mapnik/agg_renderer.hpp> #include <mapnik/agg_renderer.hpp>
#include <mapnik/layer.hpp> #include <mapnik/layer.hpp>
#include <mapnik/projection.hpp> #include <mapnik/proj_transform.hpp>
#include <mapnik/scale_denominator.hpp> #include <mapnik/scale_denominator.hpp>
#include <mapnik/view_transform.hpp> #include <mapnik/view_transform.hpp>
#include <mapnik/transform_path_adapter.hpp> #include <mapnik/transform_path_adapter.hpp>
@ -156,7 +156,7 @@ void MapWidget::mousePressEvent(QMouseEvent* e)
{ {
QVector<QPair<QString,QString> > info; QVector<QPair<QString,QString> > info;
projection map_proj(map_->srs()); // map projection projection map_proj(map_->srs(), true); // map projection
double scale_denom = scale_denominator(map_->scale(),map_proj.is_geographic()); double scale_denom = scale_denominator(map_->scale(),map_proj.is_geographic());
view_transform t(map_->width(),map_->height(),map_->get_current_extent()); view_transform t(map_->width(),map_->height(),map_->get_current_extent());
@ -170,7 +170,7 @@ void MapWidget::mousePressEvent(QMouseEvent* e)
double x = e->x(); double x = e->x();
double y = e->y(); double y = e->y();
std::cout << "query at " << x << "," << y << "\n"; std::cout << "query at " << x << "," << y << "\n";
projection layer_proj(layer.srs()); projection layer_proj(layer.srs(), true);
mapnik::proj_transform prj_trans(map_proj,layer_proj); mapnik::proj_transform prj_trans(map_proj,layer_proj);
//std::auto_ptr<mapnik::memory_datasource> data(new mapnik::memory_datasource); //std::auto_ptr<mapnik::memory_datasource> data(new mapnik::memory_datasource);
mapnik::featureset_ptr fs = map_->query_map_point(index,x,y); mapnik::featureset_ptr fs = map_->query_map_point(index,x,y);
@ -586,38 +586,43 @@ void MapWidget::updateMap()
try try
{ {
projection prj(map_->srs()); // map projection projection prj(map_->srs(), true); // map projection
box2d<double> ext = map_->get_current_extent(); box2d<double> ext = map_->get_current_extent();
double x0 = ext.minx(); double x0 = ext.minx();
double y0 = ext.miny(); double y0 = ext.miny();
double x1 = ext.maxx(); double x1 = ext.maxx();
double y1 = ext.maxy(); double y1 = ext.maxy();
prj.inverse(x0,y0); double z = 0;
prj.inverse(x1,y1); std::string dest_srs = {"epsg:4326"};
std::cout << "BBOX (WGS84): " << x0 << "," << y0 << "," << x1 << "," << y1 << "\n"; mapnik::proj_transform proj_tr(map_->srs(), dest_srs);
update();
// emit signal to interested widgets proj_tr.forward(x0, y0, z);
emit mapViewChanged(); proj_tr.forward(x1, y1, z);
} std::cout << "MAP SIZE:" << map_->width() << "," << map_->height() << std::endl;
catch (...) std::cout << "BBOX (WGS84): " << x0 << "," << y0 << "," << x1 << "," << y1 << "\n";
{ update();
std::cerr << "Unknown exception caught!\n"; // emit signal to interested widgets
} emit mapViewChanged();
}
catch (...)
{
std::cerr << "Unknown exception caught!\n";
}
} }
} }
std::shared_ptr<Map> MapWidget::getMap() std::shared_ptr<Map> MapWidget::getMap()
{ {
return map_; return map_;
} }
void MapWidget::setMap(std::shared_ptr<Map> map) void MapWidget::setMap(std::shared_ptr<Map> map)
{ {
map_ = map; map_ = map;
} }
void MapWidget::layerSelected(int index) void MapWidget::layerSelected(int index)
{ {
selectedLayer_ = index; selectedLayer_ = index;
} }

View file

@ -66,10 +66,9 @@ struct layer_rendering_material
std::vector<layer_rendering_material> materials_; std::vector<layer_rendering_material> materials_;
layer_rendering_material(layer const& lay, projection const& dest) layer_rendering_material(layer const& lay, projection const& dest)
: : lay_(lay),
lay_(lay), proj0_(dest),
proj0_(dest), proj1_(lay.srs(), true) {}
proj1_(lay.srs(),true) {}
layer_rendering_material(layer_rendering_material && rhs) = default; layer_rendering_material(layer_rendering_material && rhs) = default;
}; };
@ -255,8 +254,7 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
} }
processor_context_ptr current_ctx = ds->get_context(ctx_map); processor_context_ptr current_ctx = ds->get_context(ctx_map);
proj_transform prj_trans(mat.proj0_,mat.proj1_); proj_transform * proj_trans_ptr = m_.get_proj_transform(mat.proj0_.params(), mat.proj1_.params());
box2d<double> query_ext = extent; // unbuffered box2d<double> query_ext = extent; // unbuffered
box2d<double> buffered_query_ext(query_ext); // buffered box2d<double> buffered_query_ext(query_ext); // buffered
@ -286,22 +284,22 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
bool early_return = false; bool early_return = false;
// first, try intersection of map extent forward projected into layer srs // first, try intersection of map extent forward projected into layer srs
if (prj_trans.forward(buffered_query_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext)) if (proj_trans_ptr->forward(buffered_query_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext))
{ {
fw_success = true; fw_success = true;
layer_ext.clip(buffered_query_ext); layer_ext.clip(buffered_query_ext);
} }
// if no intersection and projections are also equal, early return // if no intersection and projections are also equal, early return
else if (prj_trans.equal()) else if (proj_trans_ptr->equal())
{ {
early_return = true; early_return = true;
} }
// next try intersection of layer extent back projected into map srs // next try intersection of layer extent back projected into map srs
else if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext_map_srs.intersects(layer_ext)) else if (proj_trans_ptr->backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext_map_srs.intersects(layer_ext))
{ {
layer_ext.clip(buffered_query_ext_map_srs); layer_ext.clip(buffered_query_ext_map_srs);
// forward project layer extent back into native projection // forward project layer extent back into native projection
if (! prj_trans.forward(layer_ext, PROJ_ENVELOPE_POINTS)) if (! proj_trans_ptr->forward(layer_ext, PROJ_ENVELOPE_POINTS))
{ {
MAPNIK_LOG_ERROR(feature_style_processor) MAPNIK_LOG_ERROR(feature_style_processor)
<< "feature_style_processor: Layer=" << lay.name() << "feature_style_processor: Layer=" << lay.name()
@ -353,17 +351,17 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
layer_ext2 = lay.envelope(); layer_ext2 = lay.envelope();
if (fw_success) if (fw_success)
{ {
if (prj_trans.forward(query_ext, PROJ_ENVELOPE_POINTS)) if (proj_trans_ptr->forward(query_ext, PROJ_ENVELOPE_POINTS))
{ {
layer_ext2.clip(query_ext); layer_ext2.clip(query_ext);
} }
} }
else else
{ {
if (prj_trans.backward(layer_ext2, PROJ_ENVELOPE_POINTS)) if (proj_trans_ptr->backward(layer_ext2, PROJ_ENVELOPE_POINTS))
{ {
layer_ext2.clip(query_ext); layer_ext2.clip(query_ext);
prj_trans.forward(layer_ext2, PROJ_ENVELOPE_POINTS); proj_trans_ptr->forward(layer_ext2, PROJ_ENVELOPE_POINTS);
} }
} }
@ -495,9 +493,7 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
layer const& lay = mat.lay_; layer const& lay = mat.lay_;
std::vector<rule_cache> const & rule_caches = mat.rule_caches_; std::vector<rule_cache> const & rule_caches = mat.rule_caches_;
proj_transform * proj_trans_ptr = m_.get_proj_transform(mat.proj0_.params(), mat.proj1_.params());
proj_transform prj_trans(mat.proj0_,mat.proj1_);
bool cache_features = lay.cache_features() && active_styles.size() > 1; bool cache_features = lay.cache_features() && active_styles.size() > 1;
datasource_ptr ds = lay.datasource(); datasource_ptr ds = lay.datasource();
@ -525,10 +521,9 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
cache->prepare(); cache->prepare();
render_style(p, style, render_style(p, style,
rule_caches[i], rule_caches[i++],
cache, cache,
prj_trans); *proj_trans_ptr);
++i;
} }
cache->clear(); cache->clear();
} }
@ -540,8 +535,7 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
for (feature_type_style const* style : active_styles) for (feature_type_style const* style : active_styles)
{ {
cache->prepare(); cache->prepare();
render_style(p, style, rule_caches[i], cache, prj_trans); render_style(p, style, rule_caches[i++], cache, *proj_trans_ptr);
++i;
} }
cache->clear(); cache->clear();
} }
@ -565,9 +559,8 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
{ {
cache->prepare(); cache->prepare();
render_style(p, style, render_style(p, style,
rule_caches[i], rule_caches[i++],
cache, prj_trans); cache, *proj_trans_ptr);
++i;
} }
} }
// We only have a single style and no grouping. // We only have a single style and no grouping.
@ -579,10 +572,9 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
{ {
featureset_ptr features = *featuresets++; featureset_ptr features = *featuresets++;
render_style(p, style, render_style(p, style,
rule_caches[i], rule_caches[i++],
features, features,
prj_trans); *proj_trans_ptr);
++i;
} }
} }
} }

View file

@ -42,7 +42,7 @@ using datasource_ptr = std::shared_ptr<datasource>;
* @brief A Mapnik map layer. * @brief A Mapnik map layer.
* *
* Create a layer with a named string and, optionally, an srs string either * Create a layer with a named string and, optionally, an srs string either
* with a Proj.4 epsg code ('+init=epsg:<code>') or with a Proj.4 literal * with a Proj.4 epsg code ('epsg:<code>') or with a Proj.4 literal
* ('+proj=<literal>'). If no srs is specified it will default to * ('+proj=<literal>'). If no srs is specified it will default to
* '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' * '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
*/ */
@ -50,7 +50,7 @@ class MAPNIK_DECL layer
{ {
public: public:
layer(std::string const& name, layer(std::string const& name,
std::string const& srs=MAPNIK_LONGLAT_PROJ); std::string const& srs = MAPNIK_GEOGRAPHIC_PROJ);
// copy // copy
layer(layer const& l); layer(layer const& l);
// move // move

View file

@ -33,15 +33,17 @@
#include <mapnik/well_known_srs.hpp> #include <mapnik/well_known_srs.hpp>
#include <mapnik/image_compositing.hpp> #include <mapnik/image_compositing.hpp>
#include <mapnik/font_engine_freetype.hpp> #include <mapnik/font_engine_freetype.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/warning.hpp> #include <mapnik/warning.hpp>
MAPNIK_DISABLE_WARNING_PUSH MAPNIK_DISABLE_WARNING_PUSH
#include <mapnik/warning_ignore.hpp> #include <mapnik/warning_ignore.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>
#include <boost/utility/string_view.hpp>
MAPNIK_DISABLE_WARNING_POP MAPNIK_DISABLE_WARNING_POP
// stl // stl
#include <map>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <string> #include <string>
@ -58,6 +60,31 @@ class layer;
class MAPNIK_DECL Map : boost::equality_comparable<Map> class MAPNIK_DECL Map : boost::equality_comparable<Map>
{ {
public: public:
using key_type = std::pair<std::string, std::string>;
using compatible_key_type = std::pair<boost::string_view, boost::string_view>;
struct compatible_hash
{
template <typename KeyType>
std::size_t operator() (KeyType const& key) const
{
using hash_type = boost::hash<typename KeyType::first_type>;
std::size_t seed = hash_type{}(key.first);
seed ^= hash_type{}(key.second) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
};
struct compatible_predicate
{
bool operator()(compatible_key_type const& k1,
compatible_key_type const& k2) const
{
return k1 == k2;
}
};
using proj_cache_type = boost::unordered_map<key_type, std::unique_ptr<proj_transform>, compatible_hash>;
enum aspect_fix_mode enum aspect_fix_mode
{ {
@ -83,8 +110,8 @@ public:
}; };
private: private:
static const unsigned MIN_MAPSIZE=16; static const unsigned MIN_MAPSIZE = 16;
static const unsigned MAX_MAPSIZE=MIN_MAPSIZE<<10; static const unsigned MAX_MAPSIZE = MIN_MAPSIZE << 10;
unsigned width_; unsigned width_;
unsigned height_; unsigned height_;
std::string srs_; std::string srs_;
@ -104,7 +131,7 @@ private:
boost::optional<std::string> font_directory_; boost::optional<std::string> font_directory_;
freetype_engine::font_file_mapping_type font_file_mapping_; freetype_engine::font_file_mapping_type font_file_mapping_;
freetype_engine::font_memory_cache_type font_memory_cache_; freetype_engine::font_memory_cache_type font_memory_cache_;
thread_local static proj_cache_type proj_cache_;
public: public:
using const_style_iterator = std::map<std::string,feature_type_style>::const_iterator; using const_style_iterator = std::map<std::string,feature_type_style>::const_iterator;
@ -126,7 +153,7 @@ public:
* @param height Initial map height. * @param height Initial map height.
* @param srs Initial map projection. * @param srs Initial map projection.
*/ */
Map(int width, int height, std::string const& srs = MAPNIK_LONGLAT_PROJ); Map(int width, int height, std::string const& srs = MAPNIK_GEOGRAPHIC_PROJ);
/*! \brief Copy Constructor. /*! \brief Copy Constructor.
* *
@ -503,9 +530,12 @@ public:
return font_memory_cache_; return font_memory_cache_;
} }
proj_transform * get_proj_transform(std::string const& source, std::string const& dest) const;
private: private:
friend void swap(Map & rhs, Map & lhs); friend void swap(Map & rhs, Map & lhs);
void fixAspectRatio(); void fixAspectRatio();
void init_proj_transform(std::string const& source, std::string const& dest);
void init_proj_transforms();
}; };
DEFINE_ENUM(aspect_fix_mode_e,Map::aspect_fix_mode); DEFINE_ENUM(aspect_fix_mode_e,Map::aspect_fix_mode);

View file

@ -27,40 +27,37 @@
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/util/noncopyable.hpp> #include <mapnik/util/noncopyable.hpp>
#include <mapnik/geometry/point.hpp> #include <mapnik/geometry/point.hpp>
#include <mapnik/projection.hpp>
// stl // stl
#include <vector> #include <vector>
namespace mapnik { namespace mapnik {
class projection;
template <typename T> class box2d; template <typename T> class box2d;
class MAPNIK_DECL proj_transform : private util::noncopyable class MAPNIK_DECL proj_transform : private util::noncopyable
{ {
public: public:
proj_transform(projection const& source, proj_transform(projection const& source, projection const& dest);
projection const& dest); ~proj_transform();
bool equal() const; bool equal() const;
bool is_known() const; bool is_known() const;
bool forward (double& x, double& y , double& z) const; bool forward (double& x, double& y , double& z) const;
bool backward (double& x, double& y , double& z) const; bool backward (double& x, double& y , double& z) const;
bool forward (double *x, double *y , double *z, int point_count, int offset = 1) const; bool forward (double *x, double *y , double *z, std::size_t point_count, std::size_t offset = 1) const;
bool backward (double *x, double *y , double *z, int point_count, int offset = 1) const; bool backward (double *x, double *y , double *z, std::size_t point_count, std::size_t offset = 1) const;
bool forward (geometry::point<double> & p) const; bool forward (geometry::point<double> & p) const;
bool backward (geometry::point<double> & p) const; bool backward (geometry::point<double> & p) const;
unsigned int forward (std::vector<geometry::point<double>> & ls) const; unsigned int forward (std::vector<geometry::point<double>> & ls) const;
unsigned int backward (std::vector<geometry::point<double>> & ls) const; unsigned int backward (std::vector<geometry::point<double>> & ls) const;
bool forward (box2d<double> & box) const; bool forward (box2d<double> & box) const;
bool backward (box2d<double> & box) const; bool backward (box2d<double> & box) const;
bool forward (box2d<double> & box, int points) const; bool forward (box2d<double> & box, std::size_t points) const;
bool backward (box2d<double> & box, int points) const; bool backward (box2d<double> & box, std::size_t points) const;
mapnik::projection const& source() const; std::string definition() const;
mapnik::projection const& dest() const;
private: private:
projection const& source_; PJ_CONTEXT* ctx_ = nullptr;
projection const& dest_; PJ* transform_ = nullptr;
bool is_source_longlat_; bool is_source_longlat_;
bool is_dest_longlat_; bool is_dest_longlat_;
bool is_source_equal_dest_; bool is_source_equal_dest_;

View file

@ -37,6 +37,18 @@ MAPNIK_DISABLE_WARNING_POP
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
// fwd decl
#if PROJ_VERSION >= 80000
struct pj_ctx;
using PJ_CONTEXT = struct pj_ctx;
#else
struct projCtx_t;
using PJ_CONTEXT = struct projCtx_t;
#endif
struct PJconsts;
using PJ = struct PJconsts;
namespace mapnik { namespace mapnik {
class proj_init_error : public std::runtime_error class proj_init_error : public std::runtime_error
@ -52,7 +64,7 @@ class MAPNIK_DECL projection
public: public:
projection(std::string const& params, projection(std::string const& params,
bool defer_proj_init = false); bool defer_proj_init = false);
projection(projection const& rhs); projection(projection const& rhs);
~projection(); ~projection();
@ -66,7 +78,7 @@ public:
void forward(double & x, double & y) const; void forward(double & x, double & y) const;
void inverse(double & x,double & y) const; void inverse(double & x,double & y) const;
std::string expanded() const; std::string expanded() const;
void init_proj4() const; void init_proj() const;
private: private:
void swap (projection& rhs); void swap (projection& rhs);
@ -75,8 +87,8 @@ private:
std::string params_; std::string params_;
bool defer_proj_init_; bool defer_proj_init_;
mutable bool is_geographic_; mutable bool is_geographic_;
mutable void * proj_; mutable PJ * proj_;
mutable void * proj_ctx_; mutable PJ_CONTEXT * proj_ctx_;
}; };
template <typename charT, typename traits> template <typename charT, typename traits>

View file

@ -27,8 +27,8 @@
namespace mapnik { namespace util { namespace mapnik { namespace util {
constexpr double pi = 3.1415926535897932384626433832795; constexpr double pi = 3.14159265358979323846;
constexpr double tau = 6.283185307179586476925286766559; constexpr double tau = 2.0 * pi;
template <typename T> template <typename T>
constexpr T const& clamp(T const& v, T const& lo, T const& hi) constexpr T const& clamp(T const& v, T const& lo, T const& hi)
@ -38,12 +38,12 @@ constexpr T const& clamp(T const& v, T const& lo, T const& hi)
constexpr double degrees(double rad) constexpr double degrees(double rad)
{ {
return rad * (360 / tau); return rad * (180.0 / pi);
} }
constexpr double radians(double deg) constexpr double radians(double deg)
{ {
return deg * (tau / 360); return deg * (pi / 180);
} }
MAPNIK_DECL double normalize_angle(double angle); MAPNIK_DECL double normalize_angle(double angle);

View file

@ -41,7 +41,7 @@ namespace mapnik {
enum well_known_srs_enum : std::uint8_t { enum well_known_srs_enum : std::uint8_t {
WGS_84, WGS_84,
G_MERC, WEB_MERC,
well_known_srs_enum_MAX well_known_srs_enum_MAX
}; };
@ -53,8 +53,8 @@ constexpr double MERC_MAX_EXTENT = EARTH_RADIUS * util::pi;
constexpr double MERC_MAX_LATITUDE = 85.0511287798065923778; constexpr double MERC_MAX_LATITUDE = 85.0511287798065923778;
// MERC_MAX_LATITUDE = degrees(2 * atan(exp(pi)) - pi / 2) // MERC_MAX_LATITUDE = degrees(2 * atan(exp(pi)) - pi / 2)
extern MAPNIK_DECL std::string const MAPNIK_LONGLAT_PROJ; extern MAPNIK_DECL std::string const MAPNIK_GEOGRAPHIC_PROJ;
extern MAPNIK_DECL std::string const MAPNIK_GMERC_PROJ; extern MAPNIK_DECL std::string const MAPNIK_WEBMERCATOR_PROJ;
MAPNIK_DECL boost::optional<bool> is_known_geographic(std::string const& srs); MAPNIK_DECL boost::optional<bool> is_known_geographic(std::string const& srs);
MAPNIK_DECL boost::optional<well_known_srs_e> is_well_known_srs(std::string const& srs); MAPNIK_DECL boost::optional<well_known_srs_e> is_well_known_srs(std::string const& srs);

View file

@ -76,8 +76,9 @@ if '-DHAVE_PNG' in env['CPPDEFINES']:
lib_env['LIBS'].append('png') lib_env['LIBS'].append('png')
enabled_imaging_libraries.append('png_reader.cpp') enabled_imaging_libraries.append('png_reader.cpp')
if '-DMAPNIK_USE_PROJ4' in env['CPPDEFINES']: if '-DMAPNIK_USE_PROJ' in env['CPPDEFINES']:
lib_env['LIBS'].append('proj') lib_env['LIBS'].append('proj')
lib_env['LIBS'].append('sqlite3')
if '-DHAVE_TIFF' in env['CPPDEFINES']: if '-DHAVE_TIFF' in env['CPPDEFINES']:
lib_env['LIBS'].append('tiff') lib_env['LIBS'].append('tiff')

View file

@ -66,7 +66,7 @@ IMPLEMENT_ENUM( aspect_fix_mode_e, aspect_fix_mode_strings )
Map::Map() Map::Map()
: width_(400), : width_(400),
height_(400), height_(400),
srs_(MAPNIK_LONGLAT_PROJ), srs_(MAPNIK_GEOGRAPHIC_PROJ),
buffer_size_(0), buffer_size_(0),
background_image_comp_op_(src_over), background_image_comp_op_(src_over),
background_image_opacity_(1.0), background_image_opacity_(1.0),
@ -110,8 +110,11 @@ Map::Map(Map const& rhs)
extra_params_(rhs.extra_params_), extra_params_(rhs.extra_params_),
font_directory_(rhs.font_directory_), font_directory_(rhs.font_directory_),
font_file_mapping_(rhs.font_file_mapping_), font_file_mapping_(rhs.font_file_mapping_),
// on copy discard memory cache // on copy discard memory caches
font_memory_cache_() {} font_memory_cache_()
{
init_proj_transforms();
}
Map::Map(Map && rhs) Map::Map(Map && rhs)
@ -137,9 +140,12 @@ Map::Map(Map && rhs)
Map::~Map() {} Map::~Map() {}
thread_local Map::proj_cache_type Map::proj_cache_ = proj_cache_type();
Map& Map::operator=(Map rhs) Map& Map::operator=(Map rhs)
{ {
swap(*this, rhs); swap(*this, rhs);
init_proj_transforms();
return *this; return *this;
} }
@ -164,7 +170,7 @@ void swap (Map & lhs, Map & rhs)
std::swap(lhs.extra_params_, rhs.extra_params_); std::swap(lhs.extra_params_, rhs.extra_params_);
std::swap(lhs.font_directory_,rhs.font_directory_); std::swap(lhs.font_directory_,rhs.font_directory_);
std::swap(lhs.font_file_mapping_,rhs.font_file_mapping_); std::swap(lhs.font_file_mapping_,rhs.font_file_mapping_);
// on assignment discard memory cache // on assignment discard memory caches
//std::swap(lhs.font_memory_cache_,rhs.font_memory_cache_); //std::swap(lhs.font_memory_cache_,rhs.font_memory_cache_);
} }
@ -321,13 +327,30 @@ size_t Map::layer_count() const
return layers_.size(); return layers_.size();
} }
proj_transform * Map::get_proj_transform(std::string const& source, std::string const& dest) const
{
compatible_key_type key = std::make_pair<boost::string_view, boost::string_view>(source, dest);
auto itr = proj_cache_.find(key, compatible_hash{}, compatible_predicate{});
if (itr == proj_cache_.end())
{
mapnik::projection srs1(source, true);
mapnik::projection srs2(dest, true);
return proj_cache_.emplace(std::make_pair(source, dest),
std::make_unique<proj_transform>(srs1, srs2)).first->second.get();
}
return itr->second.get();
}
void Map::add_layer(layer const& l) void Map::add_layer(layer const& l)
{ {
init_proj_transform(srs_, l.srs());
layers_.emplace_back(l); layers_.emplace_back(l);
} }
void Map::add_layer(layer && l) void Map::add_layer(layer && l)
{ {
init_proj_transform(srs_, l.srs());
layers_.push_back(std::move(l)); layers_.push_back(std::move(l));
} }
@ -343,6 +366,7 @@ void Map::remove_all()
fontsets_.clear(); fontsets_.clear();
font_file_mapping_.clear(); font_file_mapping_.clear();
font_memory_cache_.clear(); font_memory_cache_.clear();
proj_cache_.clear();
} }
layer const& Map::get_layer(size_t index) const layer const& Map::get_layer(size_t index) const
@ -419,7 +443,9 @@ std::string const& Map::srs() const
void Map::set_srs(std::string const& _srs) void Map::set_srs(std::string const& _srs)
{ {
if (srs_ != _srs) init_proj_transforms();
srs_ = _srs; srs_ = _srs;
} }
void Map::set_buffer_size(int _buffer_size) void Map::set_buffer_size(int _buffer_size)
@ -517,7 +543,6 @@ void Map::zoom_all()
{ {
return; return;
} }
projection proj0(srs_);
box2d<double> ext; box2d<double> ext;
bool success = false; bool success = false;
bool first = true; bool first = true;
@ -526,10 +551,9 @@ void Map::zoom_all()
if (layer.active()) if (layer.active())
{ {
std::string const& layer_srs = layer.srs(); std::string const& layer_srs = layer.srs();
projection proj1(layer_srs); proj_transform * proj_trans_ptr = get_proj_transform(srs_, layer_srs);;
proj_transform prj_trans(proj0,proj1);
box2d<double> layer_ext = layer.envelope(); box2d<double> layer_ext = layer.envelope();
if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS)) if (proj_trans_ptr->backward(layer_ext, PROJ_ENVELOPE_POINTS))
{ {
success = true; success = true;
MAPNIK_LOG_DEBUG(map) << "map: Layer " << layer.name() << " original ext=" << layer.envelope(); MAPNIK_LOG_DEBUG(map) << "map: Layer " << layer.name() << " original ext=" << layer.envelope();
@ -707,11 +731,9 @@ featureset_ptr Map::query_point(unsigned index, double x, double y) const
mapnik::datasource_ptr ds = layer.datasource(); mapnik::datasource_ptr ds = layer.datasource();
if (ds) if (ds)
{ {
mapnik::projection dest(srs_); proj_transform * proj_trans_ptr = get_proj_transform(layer.srs(), srs_);
mapnik::projection source(layer.srs());
proj_transform prj_trans(source,dest);
double z = 0; double z = 0;
if (!prj_trans.equal() && !prj_trans.backward(x,y,z)) if (!proj_trans_ptr->equal() && !proj_trans_ptr->backward(x,y,z))
{ {
throw std::runtime_error("query_point: could not project x,y into layer srs"); throw std::runtime_error("query_point: could not project x,y into layer srs");
} }
@ -721,7 +743,7 @@ featureset_ptr Map::query_point(unsigned index, double x, double y) const
{ {
map_ex.clip(*maximum_extent_); map_ex.clip(*maximum_extent_);
} }
if (!prj_trans.backward(map_ex,PROJ_ENVELOPE_POINTS)) if (!proj_trans_ptr->backward(map_ex,PROJ_ENVELOPE_POINTS))
{ {
std::ostringstream s; std::ostringstream s;
s << "query_point: could not project map extent '" << map_ex s << "query_point: could not project map extent '" << map_ex
@ -772,4 +794,28 @@ void Map::set_extra_parameters(parameters& params)
extra_params_ = params; extra_params_ = params;
} }
void Map::init_proj_transform(std::string const& source, std::string const& dest)
{
compatible_key_type key = std::make_pair<boost::string_view, boost::string_view>(source, dest);
auto itr = proj_cache_.find(key, compatible_hash{}, compatible_predicate{});
if (itr == proj_cache_.end())
{
mapnik::projection p0(source, true);
mapnik::projection p1(dest, true);
proj_cache_.emplace(std::make_pair(source, dest),
std::make_unique<proj_transform>(p0, p1));
}
}
void Map::init_proj_transforms()
{
std::for_each(layers_.begin(),
layers_.end(),
[this] (auto const& l)
{
init_proj_transform(srs_, l.srs());
});
}
} }

View file

@ -28,13 +28,13 @@
#include <mapnik/proj_transform.hpp> #include <mapnik/proj_transform.hpp>
#include <mapnik/coord.hpp> #include <mapnik/coord.hpp>
#include <mapnik/util/is_clockwise.hpp> #include <mapnik/util/is_clockwise.hpp>
#include <mapnik/util/trim.hpp>
// boost // boost
#include <boost/geometry/algorithms/envelope.hpp> #include <boost/geometry/algorithms/envelope.hpp>
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
// proj4 // proj
#include <proj_api.h> #include <proj.h>
#endif #endif
// stl // stl
@ -95,30 +95,28 @@ auto envelope_points(box2d<T> const& env, std::size_t num_points)
proj_transform::proj_transform(projection const& source, proj_transform::proj_transform(projection const& source,
projection const& dest) projection const& dest)
: source_(source), : is_source_longlat_(false),
dest_(dest),
is_source_longlat_(false),
is_dest_longlat_(false), is_dest_longlat_(false),
is_source_equal_dest_(false), is_source_equal_dest_(false),
wgs84_to_merc_(false), wgs84_to_merc_(false),
merc_to_wgs84_(false) merc_to_wgs84_(false)
{ {
is_source_equal_dest_ = (source_ == dest_); is_source_equal_dest_ = (source == dest);
if (!is_source_equal_dest_) if (!is_source_equal_dest_)
{ {
is_source_longlat_ = source_.is_geographic(); is_source_longlat_ = source.is_geographic();
is_dest_longlat_ = dest_.is_geographic(); is_dest_longlat_ = dest.is_geographic();
boost::optional<well_known_srs_e> src_k = source.well_known(); boost::optional<well_known_srs_e> src_k = source.well_known();
boost::optional<well_known_srs_e> dest_k = dest.well_known(); boost::optional<well_known_srs_e> dest_k = dest.well_known();
bool known_trans = false; bool known_trans = false;
if (src_k && dest_k) if (src_k && dest_k)
{ {
if (*src_k == WGS_84 && *dest_k == G_MERC) if (*src_k == WGS_84 && *dest_k == WEB_MERC)
{ {
wgs84_to_merc_ = true; wgs84_to_merc_ = true;
known_trans = true; known_trans = true;
} }
else if (*src_k == G_MERC && *dest_k == WGS_84) else if (*src_k == WEB_MERC && *dest_k == WGS_84)
{ {
merc_to_wgs84_ = true; merc_to_wgs84_ = true;
known_trans = true; known_trans = true;
@ -126,16 +124,45 @@ proj_transform::proj_transform(projection const& source,
} }
if (!known_trans) if (!known_trans)
{ {
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
source_.init_proj4(); ctx_ = proj_context_create();
dest_.init_proj4(); transform_ = proj_create_crs_to_crs(ctx_,
source.params().c_str(),
dest.params().c_str(), nullptr);
if (transform_ == nullptr)
{
throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections: '") + source.params() + "'->'" + dest.params() + "'");
}
PJ* transform_gis = proj_normalize_for_visualization(ctx_, transform_);
if (transform_gis == nullptr)
{
throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections: '") + source.params() + "'->'" + dest.params() + "'");
}
proj_destroy(transform_);
transform_ = transform_gis;
#else #else
throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections without proj4 support (-DMAPNIK_USE_PROJ4): '") + source_.params() + "'->'" + dest_.params() + "'"); throw std::runtime_error(std::string("Cannot initialize proj_transform for given projections without proj support (-DMAPNIK_USE_PROJ): '") + source.params() + "'->'" + dest.params() + "'");
#endif #endif
} }
} }
} }
proj_transform::~proj_transform()
{
#ifdef MAPNIK_USE_PROJ
if (transform_)
{
proj_destroy(transform_);
transform_ = nullptr;
}
if (ctx_)
{
proj_context_destroy(ctx_);
ctx_ = nullptr;
}
#endif
}
bool proj_transform::equal() const bool proj_transform::equal() const
{ {
return is_source_equal_dest_; return is_source_equal_dest_;
@ -187,9 +214,8 @@ unsigned int proj_transform::forward (std::vector<geometry::point<double>> & ls)
return 0; return 0;
} }
bool proj_transform::forward (double * x, double * y , double * z, int point_count, int offset) const bool proj_transform::forward (double * x, double * y , double * z, std::size_t point_count, std::size_t offset) const
{ {
if (is_source_equal_dest_) if (is_source_equal_dest_)
return true; return true;
@ -202,42 +228,19 @@ bool proj_transform::forward (double * x, double * y , double * z, int point_cou
return merc2lonlat(x, y, point_count, offset); return merc2lonlat(x, y, point_count, offset);
} }
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
if (is_source_longlat_) if (proj_trans_generic(transform_, PJ_FWD,
{ x, offset * sizeof(double), point_count,
int i; y, offset * sizeof(double), point_count,
for(i=0; i<point_count; i++) { z, offset * sizeof(double), point_count,
x[i*offset] *= DEG_TO_RAD; 0, 0, 0) != point_count)
y[i*offset] *= DEG_TO_RAD;
}
}
if (pj_transform( source_.proj_, dest_.proj_, point_count,
offset, x,y,z) != 0)
{
return false; return false;
}
for(int j=0; j<point_count; j++) {
if (x[j] == HUGE_VAL || y[j] == HUGE_VAL)
{
return false;
}
}
if (is_dest_longlat_)
{
int i;
for(i=0; i<point_count; i++) {
x[i*offset] *= RAD_TO_DEG;
y[i*offset] *= RAD_TO_DEG;
}
}
#endif #endif
return true; return true;
} }
bool proj_transform::backward (double * x, double * y , double * z, int point_count, int offset) const bool proj_transform::backward (double * x, double * y , double * z, std::size_t point_count, std::size_t offset) const
{ {
if (is_source_equal_dest_) if (is_source_equal_dest_)
return true; return true;
@ -251,38 +254,13 @@ bool proj_transform::backward (double * x, double * y , double * z, int point_co
return lonlat2merc(x, y, point_count, offset); return lonlat2merc(x, y, point_count, offset);
} }
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
if (is_dest_longlat_) if (proj_trans_generic(transform_, PJ_INV,
{ x, offset * sizeof(double), point_count,
for (int i = 0; i < point_count; ++i) y, offset * sizeof(double), point_count,
{ z, offset * sizeof(double), point_count,
x[i * offset] *= DEG_TO_RAD; 0, 0, 0) != point_count)
y[i * offset] *= DEG_TO_RAD;
}
}
if (pj_transform(dest_.proj_, source_.proj_, point_count,
offset, x, y, z) != 0)
{
return false; return false;
}
for (int j = 0; j < point_count; ++j)
{
if (x[j] == HUGE_VAL || y[j] == HUGE_VAL)
{
return false;
}
}
if (is_source_longlat_)
{
for (int i = 0; i < point_count; ++i)
{
x[i * offset] *= RAD_TO_DEG;
y[i * offset] *= RAD_TO_DEG;
}
}
#endif #endif
return true; return true;
} }
@ -394,7 +372,7 @@ bool proj_transform::backward (box2d<double> & box) const
// Alternative is to provide proper clipping box // Alternative is to provide proper clipping box
// in the target srs by setting map 'maximum-extent' // in the target srs by setting map 'maximum-extent'
bool proj_transform::backward(box2d<double>& env, int points) const bool proj_transform::backward(box2d<double>& env, std::size_t points) const
{ {
if (is_source_equal_dest_) if (is_source_equal_dest_)
return true; return true;
@ -433,7 +411,7 @@ bool proj_transform::backward(box2d<double>& env, int points) const
return true; return true;
} }
bool proj_transform::forward(box2d<double>& env, int points) const bool proj_transform::forward(box2d<double>& env, std::size_t points) const
{ {
if (is_source_equal_dest_) if (is_source_equal_dest_)
return true; return true;
@ -473,13 +451,25 @@ bool proj_transform::forward(box2d<double>& env, int points) const
return true; return true;
} }
mapnik::projection const& proj_transform::source() const std::string proj_transform::definition() const
{ {
return source_; #ifdef MAPNIK_USE_PROJ
} if (transform_)
mapnik::projection const& proj_transform::dest() const {
{ PJ_PROJ_INFO info = proj_pj_info(transform_);
return dest_; return mapnik::util::trim_copy(info.definition);
} }
else
#endif
if (wgs84_to_merc_)
{
return "wgs84 => merc";
}
else if (merc_to_wgs84_)
{
return "merc => wgs84";
}
return "unknown";
}
} }

View file

@ -28,23 +28,14 @@
// stl // stl
#include <stdexcept> #include <stdexcept>
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
// proj4 // proj
#include <proj_api.h> #include <proj.h>
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 #include <cmath> // HUGE_VAL
#include <mutex>
static std::mutex mutex_;
#ifdef _MSC_VER
#pragma NOTE(mapnik is building against < proj 4.8, reprojection will be faster if you use >= 4.8)
#else
#warning mapnik is building against < proj 4.8, reprojection will be faster if you use >= 4.8
#endif
#endif
#endif #endif
namespace mapnik { namespace mapnik {
projection::projection(std::string const& params, bool defer_proj_init) projection::projection(std::string const& params, bool defer_proj_init)
: params_(params), : params_(params),
defer_proj_init_(defer_proj_init), defer_proj_init_(defer_proj_init),
@ -58,13 +49,13 @@ projection::projection(std::string const& params, bool defer_proj_init)
} }
else else
{ {
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
init_proj4(); init_proj();
#else #else
throw std::runtime_error(std::string("Cannot initialize projection '") + params_ + " ' without proj4 support (-DMAPNIK_USE_PROJ4)"); throw std::runtime_error(std::string("Cannot initialize projection '") + params_ + " ' without proj support (-DMAPNIK_USE_PROJ)");
#endif #endif
} }
if (!defer_proj_init_) init_proj4(); if (!defer_proj_init_) init_proj();
} }
projection::projection(projection const& rhs) projection::projection(projection const& rhs)
@ -74,7 +65,7 @@ projection::projection(projection const& rhs)
proj_(nullptr), proj_(nullptr),
proj_ctx_(nullptr) proj_ctx_(nullptr)
{ {
if (!defer_proj_init_) init_proj4(); if (!defer_proj_init_) init_proj();
} }
projection& projection::operator=(projection const& rhs) projection& projection::operator=(projection const& rhs)
@ -83,7 +74,7 @@ projection& projection::operator=(projection const& rhs)
swap(tmp); swap(tmp);
proj_ctx_ = nullptr; proj_ctx_ = nullptr;
proj_ = nullptr; proj_ = nullptr;
if (!defer_proj_init_) init_proj4(); if (!defer_proj_init_) init_proj();
return *this; return *this;
} }
@ -97,34 +88,29 @@ bool projection::operator!=(const projection& other) const
return !(*this == other); return !(*this == other);
} }
void projection::init_proj4() const void projection::init_proj() const
{ {
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
if (!proj_) if (!proj_)
{ {
#if PJ_VERSION >= 480 proj_ctx_ = proj_context_create();
proj_ctx_ = pj_ctx_alloc(); proj_ = proj_create(proj_ctx_, params_.c_str());
proj_ = pj_init_plus_ctx(proj_ctx_, params_.c_str());
if (!proj_ || !proj_ctx_) if (!proj_ || !proj_ctx_)
{ {
if (proj_ctx_) { if (proj_ctx_) {
pj_ctx_free(proj_ctx_); proj_context_destroy(proj_ctx_);
proj_ctx_ = nullptr; proj_ctx_ = nullptr;
} }
if (proj_) { if (proj_) {
pj_free(proj_); proj_destroy(proj_);
proj_ = nullptr; proj_ = nullptr;
} }
throw proj_init_error(params_); throw proj_init_error(params_);
} }
#else PJ_TYPE type = proj_get_type(proj_);
#if defined(MAPNIK_THREADSAFE) is_geographic_ = (type == PJ_TYPE_GEOGRAPHIC_2D_CRS
std::lock_guard<std::mutex> lock(mutex_); ||
#endif type == PJ_TYPE_GEOGRAPHIC_3D_CRS) ? true : false;
proj_ = pj_init_plus(params_.c_str());
if (!proj_) throw proj_init_error(params_);
#endif
is_geographic_ = pj_is_latlong(proj_) ? true : false;
} }
#endif #endif
} }
@ -151,82 +137,68 @@ std::string const& projection::params() const
void projection::forward(double & x, double &y ) const void projection::forward(double & x, double &y ) const
{ {
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
if (!proj_) if (!proj_)
{ {
throw std::runtime_error("projection::forward not supported unless proj4 is initialized"); throw std::runtime_error("projection::forward not supported unless proj is initialized");
}
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480
std::lock_guard<std::mutex> lock(mutex_);
#endif
projUV p;
p.u = x * DEG_TO_RAD;
p.v = y * DEG_TO_RAD;
p = pj_fwd(p,proj_);
x = p.u;
y = p.v;
if (is_geographic_)
{
x *=RAD_TO_DEG;
y *=RAD_TO_DEG;
} }
PJ_COORD coord;
coord.lpzt.z = 0.0;
coord.lpzt.t = HUGE_VAL;
coord.lpzt.lam = x;
coord.lpzt.phi = y;
PJ_COORD coord_out = proj_trans(proj_, PJ_FWD, coord);
x = coord_out.xy.x;
y = coord_out.xy.y;
#else #else
throw std::runtime_error("projection::forward not supported without proj4 support (-DMAPNIK_USE_PROJ4)"); throw std::runtime_error("projection::forward not supported without proj support (-DMAPNIK_USE_PROJ)");
#endif #endif
} }
void projection::inverse(double & x,double & y) const void projection::inverse(double & x,double & y) const
{ {
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
if (!proj_) if (!proj_)
{ {
throw std::runtime_error("projection::inverse not supported unless proj4 is initialized"); throw std::runtime_error("projection::forward not supported unless proj is initialized");
} }
PJ_COORD coord;
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 coord.xyzt.z = 0.0;
std::lock_guard<std::mutex> lock(mutex_); coord.xyzt.t = HUGE_VAL;
#endif coord.xyzt.x = x;
if (is_geographic_) coord.xyzt.y = y;
{ PJ_COORD coord_out = proj_trans(proj_, PJ_INV, coord);
x *=DEG_TO_RAD; x = coord_out.xy.x;
y *=DEG_TO_RAD; y = coord_out.xy.y;
}
projUV p;
p.u = x;
p.v = y;
p = pj_inv(p,proj_);
x = RAD_TO_DEG * p.u;
y = RAD_TO_DEG * p.v;
#else #else
throw std::runtime_error("projection::inverse not supported without proj4 support (-DMAPNIK_USE_PROJ4)"); throw std::runtime_error("projection::inverse not supported without proj support (-DMAPNIK_USE_PROJ)");
#endif #endif
} }
projection::~projection() projection::~projection()
{ {
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480
std::lock_guard<std::mutex> lock(mutex_);
#endif
if (proj_) if (proj_)
{ {
pj_free(proj_); proj_destroy(proj_);
proj_ = nullptr; proj_ = nullptr;
} }
#if PJ_VERSION >= 480
if (proj_ctx_) if (proj_ctx_)
{ {
pj_ctx_free(proj_ctx_); proj_context_destroy(proj_ctx_);
proj_ctx_ = nullptr; proj_ctx_ = nullptr;
} }
#endif
#endif #endif
} }
std::string projection::expanded() const std::string projection::expanded() const
{ {
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
if (proj_) return mapnik::util::trim_copy(pj_get_def( proj_, 0 )); if (proj_)
{
PJ_PROJ_INFO info = proj_pj_info(proj_);
return mapnik::util::trim_copy(info.definition);
}
#endif #endif
return params_; return params_;
} }

View file

@ -326,10 +326,9 @@ void base_symbolizer_helper::initialize_points() const
else if (type == geometry::geometry_types::Polygon) else if (type == geometry::geometry_types::Polygon)
{ {
auto const& poly = util::get<geometry::polygon<double>>(geom); auto const& poly = util::get<geometry::polygon<double>>(geom);
proj_transform backwart_transform(prj_trans_.dest(), prj_trans_.source());
view_strategy vs(t_); view_strategy vs(t_);
proj_strategy ps(backwart_transform); proj_backward_strategy ps(prj_trans_);
using transform_group_type = geometry::strategy_group<proj_strategy, view_strategy>; using transform_group_type = geometry::strategy_group<proj_backward_strategy, view_strategy>;
transform_group_type transform_group(ps, vs); transform_group_type transform_group(ps, vs);
geometry::polygon<double> tranformed_poly(geometry::transform<double>(poly, transform_group)); geometry::polygon<double> tranformed_poly(geometry::transform<double>(poly, transform_group));
if (how_placed == INTERIOR_PLACEMENT) if (how_placed == INTERIOR_PLACEMENT)

View file

@ -36,28 +36,27 @@ MAPNIK_DISABLE_WARNING_POP
namespace mapnik { namespace mapnik {
extern std::string const MAPNIK_LONGLAT_PROJ = extern std::string const MAPNIK_GEOGRAPHIC_PROJ =
"+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"; "epsg:4326"; //wgs84
extern std::string const MAPNIK_GMERC_PROJ = extern std::string const MAPNIK_WEBMERCATOR_PROJ =
"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0" "epsg:3857"; // webmercator
" +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over";
static const char * well_known_srs_strings[] = { static const char * well_known_srs_strings[] = {
"mapnik-longlat", MAPNIK_GEOGRAPHIC_PROJ.c_str(),
"mapnik-gmerc", MAPNIK_WEBMERCATOR_PROJ.c_str(),
"" ""
}; };
boost::optional<well_known_srs_e> is_well_known_srs(std::string const& srs) boost::optional<well_known_srs_e> is_well_known_srs(std::string const& srs)
{ {
if (srs == "+init=epsg:4326" || srs == MAPNIK_LONGLAT_PROJ) if (srs == MAPNIK_GEOGRAPHIC_PROJ)
{ {
return boost::optional<well_known_srs_e>(mapnik::WGS_84); return boost::optional<well_known_srs_e>(mapnik::WGS_84);
} }
else if (srs == "+init=epsg:3857" || srs == MAPNIK_GMERC_PROJ) else if (srs == MAPNIK_WEBMERCATOR_PROJ)
{ {
return boost::optional<well_known_srs_e>(mapnik::G_MERC); return boost::optional<well_known_srs_e>(mapnik::WEB_MERC);
} }
return boost::optional<well_known_srs_e>(); return boost::optional<well_known_srs_e>();
} }
@ -65,28 +64,13 @@ boost::optional<well_known_srs_e> is_well_known_srs(std::string const& srs)
boost::optional<bool> is_known_geographic(std::string const& srs) boost::optional<bool> is_known_geographic(std::string const& srs)
{ {
std::string trimmed = util::trim_copy(srs); std::string trimmed = util::trim_copy(srs);
if (trimmed == "+init=epsg:3857") if (trimmed == MAPNIK_GEOGRAPHIC_PROJ)
{
return boost::optional<bool>(false);
}
else if (trimmed == "+init=epsg:4326")
{ {
return boost::optional<bool>(true); return boost::optional<bool>(true);
} }
else if (srs.find("+proj=") != std::string::npos) else if (trimmed == MAPNIK_WEBMERCATOR_PROJ)
{ {
if ((srs.find("+proj=longlat") != std::string::npos) || return boost::optional<bool>(false);
(srs.find("+proj=latlong") != std::string::npos) ||
(srs.find("+proj=lonlat") != std::string::npos) ||
(srs.find("+proj=latlon") != std::string::npos)
)
{
return boost::optional<bool>(true);
}
else
{
return boost::optional<bool>(false);
}
} }
return boost::optional<bool>(); return boost::optional<bool>();
} }
@ -99,7 +83,7 @@ bool lonlat2merc(double & x, double & y)
auto dx = clamp(x, -180.0, 180.0); auto dx = clamp(x, -180.0, 180.0);
auto dy = clamp(y, -MERC_MAX_LATITUDE, MERC_MAX_LATITUDE); auto dy = clamp(y, -MERC_MAX_LATITUDE, MERC_MAX_LATITUDE);
x = EARTH_RADIUS * radians(dx); x = EARTH_RADIUS * radians(dx);
y = EARTH_RADIUS * std::log(std::tan(radians(90 + dy) / 2)); y = EARTH_RADIUS * std::log(std::tan(radians(90.0 + dy) / 2.0));
return true; return true;
} }
@ -127,7 +111,7 @@ bool merc2lonlat(double & x, double & y)
auto rx = clamp(x / EARTH_RADIUS, -pi, pi); auto rx = clamp(x / EARTH_RADIUS, -pi, pi);
auto ry = clamp(y / EARTH_RADIUS, -pi, pi); auto ry = clamp(y / EARTH_RADIUS, -pi, pi);
x = degrees(rx); x = degrees(rx);
y = degrees(2 * std::atan(std::exp(ry)) - pi / 2); y = degrees(2.0 * std::atan(std::exp(ry)) - pi / 2.0);
return true; return true;
} }

View file

@ -16,9 +16,6 @@ MAPNIK_DISABLE_WARNING_PUSH
#endif #endif
#include <unicode/uclean.h> #include <unicode/uclean.h>
#ifdef MAPNIK_USE_PROJ4
#include <proj_api.h>
#endif
MAPNIK_DISABLE_WARNING_POP MAPNIK_DISABLE_WARNING_POP
@ -47,15 +44,6 @@ inline void run_cleanup()
// http://icu-project.org/apiref/icu4c/uclean_8h.html#a93f27d0ddc7c196a1da864763f2d8920 // http://icu-project.org/apiref/icu4c/uclean_8h.html#a93f27d0ddc7c196a1da864763f2d8920
u_cleanup(); u_cleanup();
#ifdef MAPNIK_USE_PROJ4
// http://trac.osgeo.org/proj/ticket/149
#if PJ_VERSION >= 480
pj_clear_initcache();
#endif
// https://trac.osgeo.org/proj/wiki/ProjAPI#EnvironmentFunctions
pj_deallocate_grids();
#endif
} }
} }

@ -1 +1 @@
Subproject commit c67cf11850d65e963e6103b6141f1eca67667aa2 Subproject commit dd0c41c3f9f5dc98291a727af00bb42734d2a8c0

@ -1 +1 @@
Subproject commit bacfd251da550fa82ea56f6710dc6f85431480c2 Subproject commit 1f20cf257f35224d3c139a6015b1cf70814b0d24

View file

@ -1,4 +1,3 @@
#include "catch.hpp" #include "catch.hpp"
#include <iostream> #include <iostream>
@ -25,7 +24,7 @@ TEST_CASE("exceptions") {
SECTION("handling") { SECTION("handling") {
try { try {
mapnik::projection srs("foo"); mapnik::projection srs("FAIL");
// to avoid unused variable warning // to avoid unused variable warning
srs.params(); srs.params();
REQUIRE(false); REQUIRE(false);
@ -35,11 +34,11 @@ SECTION("handling") {
// https://github.com/mapnik/mapnik/issues/2170 // https://github.com/mapnik/mapnik/issues/2170
try { try {
mapnik::projection srs("+proj=longlat foo",true); mapnik::projection srs("epsg:4326 foo",true);
REQUIRE(srs.is_geographic()); REQUIRE(srs.is_geographic());
REQUIRE(true); REQUIRE(true);
srs.init_proj4(); srs.init_proj();
// oddly init_proj4 does not throw with old proj/ubuntu precise // oddly init_proj does not throw with old proj/ubuntu precise
//REQUIRE(false); //REQUIRE(false);
} catch (...) { } catch (...) {
REQUIRE(true); REQUIRE(true);

View file

@ -128,7 +128,7 @@ struct geometry_equal_visitor
REQUIRE(false); REQUIRE(false);
} }
for(auto const& p : zip_crange(ls1, ls2)) for (auto const p : zip_crange(ls1, ls2))
{ {
REQUIRE(p.template get<0>().x == Approx(p.template get<1>().x)); REQUIRE(p.template get<0>().x == Approx(p.template get<1>().x));
REQUIRE(p.template get<0>().y == Approx(p.template get<1>().y)); REQUIRE(p.template get<0>().y == Approx(p.template get<1>().y));
@ -143,7 +143,7 @@ struct geometry_equal_visitor
REQUIRE(false); REQUIRE(false);
} }
for (auto const& p : zip_crange(p1, p2)) for (auto const p : zip_crange(p1, p2))
{ {
(*this)(static_cast<std::vector<point<T>> const&>(p.template get<0>()), (*this)(static_cast<std::vector<point<T>> const&>(p.template get<0>()),
static_cast<std::vector<point<T>> const&>(p.template get<1>())); static_cast<std::vector<point<T>> const&>(p.template get<1>()));
@ -173,7 +173,7 @@ struct geometry_equal_visitor
REQUIRE(false); REQUIRE(false);
} }
for (auto const& ls : zip_crange(mls1, mls2)) for (auto const ls : zip_crange(mls1, mls2))
{ {
(*this)(ls.template get<0>(),ls.template get<1>()); (*this)(ls.template get<0>(),ls.template get<1>());
} }
@ -187,7 +187,7 @@ struct geometry_equal_visitor
REQUIRE(false); REQUIRE(false);
} }
for (auto const& poly : zip_crange(mpoly1, mpoly2)) for (auto const poly : zip_crange(mpoly1, mpoly2))
{ {
(*this)(poly.template get<0>(),poly.template get<1>()); (*this)(poly.template get<0>(),poly.template get<1>());
} }
@ -203,7 +203,7 @@ struct geometry_equal_visitor
REQUIRE(false); REQUIRE(false);
} }
for (auto const& g : zip_crange(c1, c2)) for (auto const g : zip_crange(c1, c2))
{ {
assert_g_equal(g.template get<0>(),g.template get<1>()); assert_g_equal(g.template get<0>(),g.template get<1>());
} }
@ -217,7 +217,7 @@ struct geometry_equal_visitor
REQUIRE(false); REQUIRE(false);
} }
for (auto const& g : zip_crange(c1, c2)) for (auto const g : zip_crange(c1, c2))
{ {
assert_g_equal(g.template get<0>(),g.template get<1>()); assert_g_equal(g.template get<0>(),g.template get<1>());
} }

View file

@ -11,8 +11,8 @@ TEST_CASE("geometry reprojection") {
SECTION("test_projection_4326_3857 - Empty Geometry Object") { SECTION("test_projection_4326_3857 - Empty Geometry Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans(source, dest); mapnik::proj_transform proj_trans(source, dest);
{ {
geometry_empty geom; geometry_empty geom;
@ -37,8 +37,8 @@ SECTION("test_projection_4326_3857 - Empty Geometry Object") {
SECTION("test_projection_4326_3857 - Empty Geometry in Geometry Variant") { SECTION("test_projection_4326_3857 - Empty Geometry in Geometry Variant") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans(source, dest); mapnik::proj_transform proj_trans(source, dest);
{ {
geometry<double> geom = geometry_empty(); geometry<double> geom = geometry_empty();
@ -66,8 +66,8 @@ SECTION("test_projection_4326_3857 - Empty Geometry in Geometry Variant") {
SECTION("test_projection_4326_3857 - Point Geometry Object") { SECTION("test_projection_4326_3857 - Point Geometry Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
point<double> geom1(-97.552175, 35.522895); point<double> geom1(-97.552175, 35.522895);
@ -119,8 +119,8 @@ SECTION("test_projection_4326_3857 - Point Geometry Object") {
SECTION("test_projection_4326_3857 - Point Geometry Variant Object") { SECTION("test_projection_4326_3857 - Point Geometry Variant Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
double x1 = -97.552175; double x1 = -97.552175;
@ -176,8 +176,8 @@ SECTION("test_projection_4326_3857 - Point Geometry Variant Object") {
SECTION("test_projection_4326_3857 - Line_String Geometry Object") { SECTION("test_projection_4326_3857 - Line_String Geometry Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
line_string<double> geom1; line_string<double> geom1;
@ -241,8 +241,8 @@ SECTION("test_projection_4326_3857 - Line_String Geometry Object") {
SECTION("test_projection_4326_3857 - Line_String Geometry Variant Object") { SECTION("test_projection_4326_3857 - Line_String Geometry Variant Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
line_string<double> geom1_; line_string<double> geom1_;
@ -316,8 +316,8 @@ SECTION("test_projection_4326_3857 - Line_String Geometry Variant Object") {
SECTION("test_projection_4326_3857 - Polygon Geometry Object") { SECTION("test_projection_4326_3857 - Polygon Geometry Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
polygon<double> geom1; polygon<double> geom1;
@ -411,8 +411,8 @@ SECTION("test_projection_4326_3857 - Polygon Geometry Object") {
SECTION("test_projection_4326_3857 - Polygon Geometry Variant Object") { SECTION("test_projection_4326_3857 - Polygon Geometry Variant Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
polygon<double> geom1_; polygon<double> geom1_;
@ -503,8 +503,8 @@ SECTION("test_projection_4326_3857 - Polygon Geometry Variant Object") {
SECTION("test_projection_4326_3857 - Multi_Point Geometry Object") { SECTION("test_projection_4326_3857 - Multi_Point Geometry Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
multi_point<double> geom1; multi_point<double> geom1;
@ -568,8 +568,8 @@ SECTION("test_projection_4326_3857 - Multi_Point Geometry Object") {
SECTION("test_projection_4326_3857 - Multi_Point Geometry Variant Object") { SECTION("test_projection_4326_3857 - Multi_Point Geometry Variant Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
multi_point<double> geom1_; multi_point<double> geom1_;
@ -643,8 +643,8 @@ SECTION("test_projection_4326_3857 - Multi_Point Geometry Variant Object") {
SECTION("test_projection_4326_3857 - Multi_Line_String Geometry Object") { SECTION("test_projection_4326_3857 - Multi_Line_String Geometry Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
line_string<double> geom1a; line_string<double> geom1a;
@ -720,8 +720,8 @@ SECTION("test_projection_4326_3857 - Multi_Line_String Geometry Object") {
SECTION("test_projection_4326_3857 - Multi_Line_String Geometry Variant Object") { SECTION("test_projection_4326_3857 - Multi_Line_String Geometry Variant Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
line_string<double> geom1a_; line_string<double> geom1a_;
@ -799,8 +799,8 @@ SECTION("test_projection_4326_3857 - Multi_Line_String Geometry Variant Object")
SECTION("test_projection_4326_3857 - Multi_Polygon Geometry Object") { SECTION("test_projection_4326_3857 - Multi_Polygon Geometry Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
polygon<double> geom1a; polygon<double> geom1a;
@ -898,8 +898,8 @@ SECTION("test_projection_4326_3857 - Multi_Polygon Geometry Object") {
SECTION("test_projection_4326_3857 - Multi_Polygon Geometry Variant Object") { SECTION("test_projection_4326_3857 - Multi_Polygon Geometry Variant Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
polygon<double> geom1a_; polygon<double> geom1a_;
@ -993,8 +993,8 @@ SECTION("test_projection_4326_3857 - Multi_Polygon Geometry Variant Object") {
SECTION("test_projection_4326_3857 - Geometry Collection Object") { SECTION("test_projection_4326_3857 - Geometry Collection Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
polygon<double> geom1a; polygon<double> geom1a;
@ -1092,8 +1092,8 @@ SECTION("test_projection_4326_3857 - Geometry Collection Object") {
SECTION("test_projection_4326_3857 - Geometry Collection Variant Object") { SECTION("test_projection_4326_3857 - Geometry Collection Variant Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
polygon<double> geom1a_; polygon<double> geom1a_;
@ -1185,11 +1185,11 @@ SECTION("test_projection_4326_3857 - Geometry Collection Variant Object") {
} }
} // END SECTION } // END SECTION
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
SECTION("test_projection_4269_3857 - Line_String Geometry Object") { SECTION("test_projection_4269_3857 - Line_String Geometry Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4269"); mapnik::projection source("epsg:4269");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
line_string<double> geom1; line_string<double> geom1;
@ -1254,8 +1254,8 @@ SECTION("test_projection_4269_3857 - Line_String Geometry Object") {
SECTION("test_projection_4269_3857 - Point Geometry Object") { SECTION("test_projection_4269_3857 - Point Geometry Object") {
using namespace mapnik::geometry; using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4269"); mapnik::projection source("epsg:4269");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans1(source, dest); mapnik::proj_transform proj_trans1(source, dest);
mapnik::proj_transform proj_trans2(dest, source); mapnik::proj_transform proj_trans2(dest, source);
point<double> geom1(-97.552175, 35.522895); point<double> geom1(-97.552175, 35.522895);
@ -1305,6 +1305,6 @@ SECTION("test_projection_4269_3857 - Point Geometry Object") {
} }
} // End Section } // End Section
#endif // MAPNIK_USE_PROJ4 #endif // MAPNIK_USE_PROJ
} // End Testcase } // End Testcase

View file

@ -18,8 +18,8 @@ SECTION("proj and view strategy") {
mapnik::view_transform vt(256, 256, e); mapnik::view_transform vt(256, 256, e);
mapnik::view_strategy vs(vt); mapnik::view_strategy vs(vt);
mapnik::unview_strategy uvs(vt); mapnik::unview_strategy uvs(vt);
mapnik::projection source("+init=epsg:4326"); mapnik::projection source("epsg:4326");
mapnik::projection dest("+init=epsg:3857"); mapnik::projection dest("epsg:3857");
mapnik::proj_transform proj_trans(source, dest); mapnik::proj_transform proj_trans(source, dest);
mapnik::proj_transform proj_trans_rev(dest, source); mapnik::proj_transform proj_trans_rev(dest, source);
mapnik::proj_strategy ps(proj_trans); mapnik::proj_strategy ps(proj_trans);

View file

@ -1,3 +1,24 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2021 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#include "catch.hpp" #include "catch.hpp"
@ -63,4 +84,3 @@ SECTION("set background - cairo") {
#endif #endif
} }

View file

@ -0,0 +1,60 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2021 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#include "catch.hpp"
#include <mapnik/map.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/featureset.hpp>
#include <mapnik/load_map.hpp>
namespace {
bool test_query_point(mapnik::Map const& map,
double x, double y,
std::string const& name, std::string const& expected_val)
{
auto featureset = map.query_map_point(0u, x, y);
while (auto feature = featureset->next())
{
auto val = feature->get(name);
return (val.to_string() == expected_val);
}
return false;
}
}
TEST_CASE("Query map point") {
SECTION("Polygons") {
mapnik::Map map(882,780);
mapnik::load_map(map, "./test/data/good_maps/wgs842merc_reprojection.xml");
map.zoom_all();
CHECK(test_query_point(map, 351, 94, "ADMIN", "Greenland"));
CHECK(test_query_point(map, 402, 182,"ADMIN", "Iceland"));
CHECK(test_query_point(map, 339, 687,"ADMIN", "Antarctica"));
CHECK(test_query_point(map, 35, 141, "ADMIN", "Russia"));
CHECK(test_query_point(map, 737, 297,"ADMIN", "Japan"));
}
}

View file

@ -3,20 +3,20 @@
#include <mapnik/projection.hpp> #include <mapnik/projection.hpp>
#include <mapnik/proj_transform.hpp> #include <mapnik/proj_transform.hpp>
#include <mapnik/geometry/box2d.hpp> #include <mapnik/geometry/box2d.hpp>
#include <cmath>
#ifdef MAPNIK_USE_PROJ4 #include <tuple>
// proj4
#include <proj_api.h>
#endif
TEST_CASE("projection transform") TEST_CASE("projection transform")
{ {
SECTION("Test bounding box transforms - 4326 to 3857") SECTION("Test bounding box transforms - 4326 to 3857")
{ {
mapnik::projection proj_4326("+init=epsg:4326"); mapnik::projection proj_4326("epsg:4326");
mapnik::projection proj_3857("+init=epsg:3857"); mapnik::projection proj_3857("epsg:3857");
CHECK(proj_4326.is_geographic());
CHECK(!proj_3857.is_geographic());
mapnik::proj_transform prj_trans(proj_4326, proj_3857); mapnik::proj_transform prj_trans(proj_4326, proj_3857);
double minx = -45.0; double minx = -45.0;
@ -45,36 +45,15 @@ SECTION("Test bounding box transforms - 4326 to 3857")
} }
#if defined(MAPNIK_USE_PROJ4) && PJ_VERSION >= 480 #if defined(MAPNIK_USE_PROJ)
SECTION("test pj_transform failure behavior") SECTION("test proj_transform failure behavior")
{ {
mapnik::projection proj_4269("+init=epsg:4269"); mapnik::projection proj_4269("epsg:4269");
mapnik::projection proj_3857("+init=epsg:3857"); mapnik::projection proj_3857("epsg:3857");
mapnik::proj_transform prj_trans(proj_4269, proj_3857); mapnik::proj_transform prj_trans(proj_4269, proj_3857);
mapnik::proj_transform prj_trans2(proj_3857, proj_4269); mapnik::proj_transform prj_trans2(proj_3857, proj_4269);
auto proj_ctx0 = pj_ctx_alloc(); // test valid coordinate
REQUIRE( proj_ctx0 != nullptr );
auto proj0 = pj_init_plus_ctx(proj_ctx0, proj_4269.params().c_str());
REQUIRE( proj0 != nullptr );
auto proj_ctx1 = pj_ctx_alloc();
REQUIRE( proj_ctx1 != nullptr );
auto proj1 = pj_init_plus_ctx(proj_ctx1, proj_3857.params().c_str());
REQUIRE( proj1 != nullptr );
// first test valid values directly against proj
double x = -180.0;
double y = -60.0;
x *= DEG_TO_RAD;
y *= DEG_TO_RAD;
CHECK( x == Approx(-3.1415926536) );
CHECK( y == Approx(-1.0471975512) );
CHECK( 0 == pj_transform(proj0, proj1, 1, 0, &x, &y, nullptr) );
CHECK( x == Approx(-20037508.3427892439) );
CHECK( y == Approx(-8399737.8896366451) );
// now test mapnik class
double x0 = -180.0; double x0 = -180.0;
double y0 = -60.0; double y0 = -60.0;
CHECK( prj_trans.forward(&x0,&y0,nullptr,1,1) ); CHECK( prj_trans.forward(&x0,&y0,nullptr,1,1) );
@ -86,45 +65,69 @@ SECTION("test pj_transform failure behavior")
CHECK( x1 == Approx(-20037508.3427892439) ); CHECK( x1 == Approx(-20037508.3427892439) );
CHECK( y1 == Approx(-8399737.8896366451) ); CHECK( y1 == Approx(-8399737.8896366451) );
// longitude value outside the value range for mercator // now test invalid coordinate
x = -181.0;
y = -91.0;
x *= DEG_TO_RAD;
y *= DEG_TO_RAD;
CHECK( x == Approx(-3.1590459461) );
CHECK( y == Approx(-1.5882496193) );
CHECK( 0 == pj_transform(proj0, proj1, 1, 0, &x, &y, nullptr) );
CHECK( std::isinf(x) );
CHECK( std::isinf(y) );
// now test mapnik class
double x2 = -181.0; double x2 = -181.0;
double y2 = -91.0; double y2 = -91.0;
CHECK( false == prj_trans.forward(&x2,&y2,nullptr,1,1) ); prj_trans.forward(&x2,&y2,nullptr,1,1);
CHECK( std::isinf(x2) ); CHECK( std::isinf(x2) );
CHECK( std::isinf(y2) ); CHECK( std::isinf(y2) );
double x3 = -181.0; double x3 = -181.0;
double y3 = -91.0; double y3 = -91.0;
CHECK( false == prj_trans2.backward(&x3,&y3,nullptr,1,1) ); prj_trans2.backward(&x3,&y3,nullptr,1,1);
CHECK( std::isinf(x3) ); CHECK( std::isinf(x3) );
CHECK( std::isinf(y3) ); CHECK( std::isinf(y3) );
}
// cleanup SECTION("test forward/backward transformations")
pj_ctx_free(proj_ctx0); {
proj_ctx0 = nullptr; //WGS 84 - World Geodetic System 1984, used in GPS
pj_free(proj0); mapnik::projection proj_4236("epsg:4236");
proj0 = nullptr; //OSGB 1936 / British National Grid -- United Kingdom Ordnance Survey
pj_ctx_free(proj_ctx1); mapnik::projection proj_27700("epsg:27700");
proj_ctx1 = nullptr; //WGS 84 / Equal Earth Greenwich
pj_free(proj1); mapnik::projection proj_8857("epsg:8857");
proj1 = nullptr; //European Terrestrial Reference System 1989 (ETRS89)
mapnik::projection proj_4937("epsg:4937");
//"Webmercator" WGS 84 / Pseudo-Mercator -- Spherical Mercator, Google Maps, OpenStreetMap, Bing, ArcGIS, ESRI
mapnik::projection proj_3857("epsg:3857");
mapnik::proj_transform tr1(proj_4236, proj_27700);
mapnik::proj_transform tr2(proj_4236, proj_8857);
mapnik::proj_transform tr3(proj_4236, proj_4236);
mapnik::proj_transform tr4(proj_4236, proj_4937);
mapnik::proj_transform tr5(proj_4236, proj_3857);
std::initializer_list<std::reference_wrapper<mapnik::proj_transform>> transforms = {
tr1, tr2, tr3, tr4, tr5
};
std::initializer_list<std::tuple<double, double>> coords = {
{-4.0278869, 57.8796955}, // Dórnach, Highland
{-4.2488787, 55.8609825}, // Glaschú, Alba
{-1.4823897, 51.8726941}, // Charlbury, England
{-3.9732612, 51.7077400} // Felindre, Cymru
};
for (auto const& c : coords)
{
double x0, y0;
std::tie(x0, y0) = c;
for (mapnik::proj_transform const& tr : transforms)
{
double x1 = x0;
double y1 = y0;
tr.forward (&x1, &y1, nullptr, 1, 1);
tr.backward(&x1, &y1, nullptr, 1, 1);
CHECK (x0 == Approx(x1));
CHECK (y0 == Approx(y1));
}
}
} }
// Github Issue https://github.com/mapnik/mapnik/issues/2648 // Github Issue https://github.com/mapnik/mapnik/issues/2648
SECTION("Test proj antimeridian bbox") SECTION("Test proj antimeridian bbox")
{ {
mapnik::projection prj_geog("+init=epsg:4326"); mapnik::projection prj_geog("epsg:4326");
mapnik::projection prj_proj("+init=epsg:2193"); mapnik::projection prj_proj("epsg:2193");
mapnik::proj_transform prj_trans_fwd(prj_proj, prj_geog); mapnik::proj_transform prj_trans_fwd(prj_proj, prj_geog);
mapnik::proj_transform prj_trans_rev(prj_geog, prj_proj); mapnik::proj_transform prj_trans_rev(prj_geog, prj_proj);
@ -132,7 +135,7 @@ SECTION("Test proj antimeridian bbox")
// reference values taken from proj4 command line tool: // reference values taken from proj4 command line tool:
// (non-corner points assume PROJ_ENVELOPE_POINTS == 20) // (non-corner points assume PROJ_ENVELOPE_POINTS == 20)
// //
// cs2cs -Ef %.10f +init=epsg:2193 +to +init=epsg:4326 <<END // cs2cs -Ef %.10f epsg:2193 +to epsg:4326 <<END
// 2105800 3087000 # left-most // 2105800 3087000 # left-most
// 1495200 3087000 # bottom-most // 1495200 3087000 # bottom-most
// 2105800 7173000 # right-most // 2105800 7173000 # right-most
@ -169,14 +172,14 @@ SECTION("Test proj antimeridian bbox")
// reference values taken from proj4 command line tool: // reference values taken from proj4 command line tool:
// //
// cs2cs -Ef %.10f +init=epsg:2193 +to +init=epsg:4326 <<END // cs2cs -Ef %.10f epsg:2193 +to epsg:4326 <<END
// 274000 3087000 # left-most // 274000 3087000 # left-most
// 276000 3087000 # bottom-most // 276000 3087000 # bottom-most
// 276000 7173000 # right-most // 276000 7173000 # right-most
// 274000 7173000 # top-most // 274000 7173000 # top-most
// END // END
// //
const mapnik::box2d<double> normal(148.7667597489, -60.1222810241, const mapnik::box2d<double> normal(148.7639922894, -60.1222810241,
159.9548489296, -24.9771195155); 159.9548489296, -24.9771195155);
{ {
@ -207,12 +210,14 @@ SECTION("Test proj antimeridian bbox")
SECTION("proj_transform of coordinate arrays with stride > 1") SECTION("proj_transform of coordinate arrays with stride > 1")
{ {
mapnik::projection const proj_4326("+init=epsg:4326");
mapnik::projection const proj_3857("+init=epsg:3857"); mapnik::projection const proj_4326("epsg:4326");
mapnik::projection const proj_3857("epsg:3857");
mapnik::projection const proj_2193("epsg:2193");
SECTION("lonlat <-> Web Mercator") SECTION("lonlat <-> Web Mercator")
{ {
// cs2cs -Ef %.10f +init=epsg:4326 +to +init=epsg:3857 <<END // cs2cs -Ef %.10f epsg:4326 +to epsg:3857 <<END
// 170.142139 -43.595056 // 170.142139 -43.595056
// 175.566667 -39.283333 // 175.566667 -39.283333
// END // END
@ -240,11 +245,12 @@ SECTION("proj_transform of coordinate arrays with stride > 1")
} }
} }
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
SECTION("lonlat <-> New Zealand Transverse Mercator 2000") SECTION("lonlat <-> New Zealand Transverse Mercator 2000")
{ {
mapnik::projection const proj_2193("+init=epsg:2193");
// cs2cs -Ef %.10f +init=epsg:4326 +to +init=epsg:2193 <<END mapnik::projection const proj_2193("epsg:2193");
// cs2cs -Ef %.10f epsg:4326 +to epsg:2193 <<END
// 170.142139 -43.595056 // 170.142139 -43.595056
// 175.566667 -39.283333 // 175.566667 -39.283333
// END // END
@ -271,7 +277,7 @@ SECTION("proj_transform of coordinate arrays with stride > 1")
CHECK(points[1].y == Approx(-39.283333)); CHECK(points[1].y == Approx(-39.283333));
} }
} }
#endif // MAPNIK_USE_PROJ4 #endif // MAPNIK_USE_PROJ
} }
} }

View file

@ -195,7 +195,7 @@ SECTION("test_renderer - apply() with single layer") {
rendering_result result; rendering_result result;
test_renderer renderer(map, result); test_renderer renderer(map, result);
std::set<std::string> attributes; std::set<std::string> attributes;
mapnik::layer & layer = map.get_layer(0); mapnik::layer const& layer = map.get_layer(0);
renderer.apply(layer, attributes); renderer.apply(layer, attributes);
REQUIRE(renderer.painted()); REQUIRE(renderer.painted());
@ -222,7 +222,7 @@ SECTION("test_renderer - apply_to_layer") {
test_renderer renderer(map, result); test_renderer renderer(map, result);
std::set<std::string> attributes; std::set<std::string> attributes;
mapnik::projection map_proj(map.srs(), true); mapnik::projection map_proj(map.srs(), true);
mapnik::layer & layer = map.get_layer(0); mapnik::layer const& layer = map.get_layer(0);
renderer.apply_to_layer(layer, renderer.apply_to_layer(layer,
renderer, renderer,
map_proj, map_proj,

View file

@ -11,7 +11,7 @@
TEST_CASE("transform_path_adapter") { TEST_CASE("transform_path_adapter") {
#ifdef MAPNIK_USE_PROJ4 #ifdef MAPNIK_USE_PROJ
SECTION("polygon closing - epsg 2330") { SECTION("polygon closing - epsg 2330") {
mapnik::geometry::polygon<double> g; mapnik::geometry::polygon<double> g;
g.emplace_back(); g.emplace_back();
@ -28,8 +28,8 @@ SECTION("polygon closing - epsg 2330") {
va_type va(g); va_type va(g);
mapnik::box2d<double> extent(16310607, 7704513, 16310621, 7704527); mapnik::box2d<double> extent(16310607, 7704513, 16310621, 7704527);
mapnik::view_transform tr(512, 512, extent); mapnik::view_transform tr(512, 512, extent);
mapnik::projection proj1("+init=epsg:2330"); mapnik::projection proj1("epsg:2330");
mapnik::projection proj2("+init=epsg:4326"); mapnik::projection proj2("epsg:4326");
mapnik::proj_transform prj_trans(proj1, proj2); mapnik::proj_transform prj_trans(proj1, proj2);
path_type path(tr, va, prj_trans); path_type path(tr, va, prj_trans);
@ -80,8 +80,8 @@ SECTION("polygon closing - epsg 32633") {
va_type va(g); va_type va(g);
mapnik::box2d<double> extent(166022, 0, 833978, 9329005); mapnik::box2d<double> extent(166022, 0, 833978, 9329005);
mapnik::view_transform tr(512, 512, extent); mapnik::view_transform tr(512, 512, extent);
mapnik::projection proj1("+init=epsg:32633"); mapnik::projection proj1("epsg:32633");
mapnik::projection proj2("+init=epsg:4326"); mapnik::projection proj2("epsg:4326");
mapnik::proj_transform prj_trans(proj1, proj2); mapnik::proj_transform prj_trans(proj1, proj2);
path_type path(tr, va, prj_trans); path_type path(tr, va, prj_trans);
@ -116,5 +116,5 @@ SECTION("polygon closing - epsg 32633") {
CHECK( y == 0 ); CHECK( y == 0 );
} }
#endif //MAPNIK_USE_PROJ4 #endif //MAPNIK_USE_PROJ
} }