Skip to content

Commit

Permalink
Initial implementation of new proj7 APIs support
Browse files Browse the repository at this point in the history
  • Loading branch information
artemp committed Jan 15, 2021
1 parent bec509d commit 88241b3
Show file tree
Hide file tree
Showing 20 changed files with 224 additions and 271 deletions.
75 changes: 32 additions & 43 deletions SConstruct
@@ -1,6 +1,6 @@
# 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
# modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -79,7 +79,7 @@ SCONF_TEMP_DIR = '.sconf_temp'
BOOST_SEARCH_PREFIXES = ['/usr/local','/opt/local','/sw','/usr',]
BOOST_MIN_VERSION = '1.61'
#CAIRO_MIN_VERSION = '1.8.0'

PROJ_MIN_VERSION = (7, 2, 0)
HARFBUZZ_MIN_VERSION = (0, 9, 34)
HARFBUZZ_MIN_VERSION_STRING = "%s.%s.%s" % HARFBUZZ_MIN_VERSION

Expand All @@ -92,7 +92,7 @@ pretty_dep_names = {
'gdal':'GDAL C++ library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/GDAL',
'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',
'proj':'Proj.4 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/',
'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',
'jpeg':'JPEG C library | configure with JPEG_LIBS & JPEG_INCLUDES',
Expand All @@ -116,7 +116,7 @@ pretty_dep_names = {
'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)',
'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',
'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'
}
Expand Down Expand Up @@ -422,7 +422,7 @@ opts.AddVariables(
BoolVariable('WEBP', 'Build Mapnik with WEBP read', 'True'),
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),
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_LIBS', 'Search path for PROJ.4 library files', '/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept),
('PG_INCLUDES', 'Search path for libpq (postgres client) include files', ''),
Expand Down Expand Up @@ -940,59 +940,48 @@ def CheckProjData(context, silent=False):
context.Message('Checking for PROJ_LIB directory...')
ret, out = context.TryRun("""
// This is narly, could eventually be replaced using https://github.com/OSGeo/proj.4/pull/551]
#include <proj_api.h>
#include <proj.h>
#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);
*posMsg += msg;
}
std::vector<std::string> output;
std::stringstream ss(paths);
std::string path;
// https://github.com/OSGeo/gdal/blob/ddbf6d39aa4b005a77ca4f27c2d61a3214f336f8/gdal/alg/gdalapplyverticalshiftgrid.cpp#L616-L633
std::string find_proj_path(const char * pszFilename) {
std::string osMsg;
std::string osFilename;
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);
}
size_t nPos = osMsg.find("fopen(");
if( nPos != std::string::npos )
for( std::string path;std::getline(ss, path, ':');)
{
osFilename = osMsg.substr(nPos + strlen("fopen("));
nPos = osFilename.find(")");
if( nPos != std::string::npos )
osFilename = osFilename.substr(0, nPos);
output.push_back(path);
}
pj_ctx_free(ctx);
return osFilename;
return output;
}
int main() {
std::string result = find_proj_path(" ");
std::cout << result;
if (result.empty()) {
return -1;
int main()
{
PJ_INFO info = proj_info();
std::string result = info.searchpath;
for (auto path : split_searchpath(result))
{
std::ifstream file(path + "/proj.db");
if (file)
{
std::cout << path;
return 0;
}
}
return 0;
return -1;
}
""", '.cpp')
value = out.strip()
if silent:
context.did_show_result=1
if ret:
context.Result('pj_open_lib returned %s' % value)
context.Result('proj_info.searchpath returned %s' % value)
else:
context.Result('Failed to detect (mapnik-config will have null value)')
return value
Expand Down Expand Up @@ -1565,7 +1554,7 @@ if not preconfigured:
env['SKIPPED_DEPS'].append('jpeg')

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']
lib_path = env['%s_LIBS' % 'PROJ']
env.AppendUnique(CPPPATH = fix_path(inc_path))
Expand Down
4 changes: 2 additions & 2 deletions benchmark/data/gdal-wgs.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Map[]>
<Map
srs="+init=epsg:4326"
srs="epsg:4326"
background-color="#dfd8c9">

<Style name="style">
Expand All @@ -10,7 +10,7 @@
</Rule>
</Style>
<Layer name="layer"
srs="+init=epsg:4326">
srs="epsg:4326">
<StyleName>style</StyleName>
<Datasource>
<Parameter name="file">./valid.geotiff.tif</Parameter>
Expand Down
4 changes: 2 additions & 2 deletions benchmark/data/raster-wgs.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Map[]>
<Map
srs="+init=epsg:4326"
srs="epsg:4326"
background-color="#dfd8c9">

<Style name="style">
Expand All @@ -10,7 +10,7 @@
</Rule>
</Style>
<Layer name="layer"
srs="+init=epsg:4326">
srs="epsg:4326">
<StyleName>style</StyleName>
<Datasource>
<Parameter name="file">./valid.geotiff.tif</Parameter>
Expand Down
4 changes: 2 additions & 2 deletions benchmark/src/test_noop_rendering.cpp
Expand Up @@ -11,7 +11,7 @@
#include <mapnik/feature_type_style.hpp>

#include <memory>

class test : public benchmark::test_case
{
public:
Expand All @@ -24,7 +24,7 @@ class test : public benchmark::test_case
}
bool operator()() const
{
mapnik::Map m(256,256,"+init=epsg:3857");
mapnik::Map m(256,256,"epsg:3857");

mapnik::parameters params;
params["type"]="memory";
Expand Down
2 changes: 1 addition & 1 deletion benchmark/src/test_polygon_clipping.cpp
Expand Up @@ -51,7 +51,7 @@ void render(mapnik::geometry::multi_polygon<double> const& geom,
agg::pixfmt_rgba32_plain pixf(buf);
ren_base renb(pixf);
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));
agg::rasterizer_scanline_aa<> ras;
for (auto const& poly : geom)
Expand Down
6 changes: 3 additions & 3 deletions benchmark/src/test_proj_transform1.cpp
Expand Up @@ -56,13 +56,13 @@ class test : public benchmark::test_case
}
};

// 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)
{
mapnik::box2d<double> from(-180,-80,180,80);
mapnik::box2d<double> to(-20037508.3427892476,-15538711.0963092316,20037508.3427892476,15538711.0963092316);
std::string from_str("+init=epsg:4326");
std::string to_str("+init=epsg:3857");
std::string from_str("epsg:4326");
std::string to_str("epsg:3857");
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");
return benchmark::sequencer(argc, argv)
Expand Down
2 changes: 1 addition & 1 deletion include/mapnik/layer.hpp
Expand Up @@ -42,7 +42,7 @@ using datasource_ptr = std::shared_ptr<datasource>;
* @brief A Mapnik map layer.
*
* 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=longlat +ellps=WGS84 +datum=WGS84 +no_defs'
*/
Expand Down
6 changes: 4 additions & 2 deletions include/mapnik/proj_transform.hpp
Expand Up @@ -27,20 +27,20 @@
#include <mapnik/config.hpp>
#include <mapnik/util/noncopyable.hpp>
#include <mapnik/geometry/point.hpp>
#include <mapnik/projection.hpp>
// stl
#include <vector>

namespace mapnik {

class projection;
template <typename T> class box2d;

class MAPNIK_DECL proj_transform : private util::noncopyable
{
public:
proj_transform(projection const& source,
projection const& dest);

~proj_transform();
bool equal() const;
bool is_known() const;
bool forward (double& x, double& y , double& z) const;
Expand All @@ -59,6 +59,8 @@ class MAPNIK_DECL proj_transform : private util::noncopyable
mapnik::projection const& dest() const;

private:
PJ_CONTEXT* ctx_ = nullptr;
PJ* transform_ = nullptr;
projection const& source_;
projection const& dest_;
bool is_source_longlat_;
Expand Down
13 changes: 10 additions & 3 deletions include/mapnik/projection.hpp
Expand Up @@ -37,6 +37,13 @@ MAPNIK_DISABLE_WARNING_POP
#include <string>
#include <stdexcept>


// fwd decl
struct projCtx_t;
struct PJconsts;
using PJ_CONTEXT = struct projCtx_t;
using PJ = struct PJconsts;

namespace mapnik {

class proj_init_error : public std::runtime_error
Expand Down Expand Up @@ -66,7 +73,7 @@ class MAPNIK_DECL projection
void forward(double & x, double & y) const;
void inverse(double & x,double & y) const;
std::string expanded() const;
void init_proj4() const;
void init_proj() const;

private:
void swap (projection& rhs);
Expand All @@ -75,8 +82,8 @@ class MAPNIK_DECL projection
std::string params_;
bool defer_proj_init_;
mutable bool is_geographic_;
mutable void * proj_;
mutable void * proj_ctx_;
mutable PJ * proj_;
mutable PJ_CONTEXT * proj_ctx_;
};

template <typename charT, typename traits>
Expand Down
2 changes: 1 addition & 1 deletion src/build.py
Expand Up @@ -76,7 +76,7 @@ def ldconfig(*args,**kwargs):
lib_env['LIBS'].append('png')
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')

if '-DHAVE_TIFF' in env['CPPDEFINES']:
Expand Down

0 comments on commit 88241b3

Please sign in to comment.