[mapnik] 01/07: Imported Upstream version 3.0.6+ds
Sebastiaan Couwenberg
sebastic at moszumanska.debian.org
Sat Oct 10 15:10:28 UTC 2015
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository mapnik.
commit fd3c511f3160a5d6e7c0bb36152cb4c45178bd31
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Sat Oct 10 11:48:40 2015 +0200
Imported Upstream version 3.0.6+ds
---
.gitattributes | 1 +
.gitignore | 1 +
.travis.yml | 12 +-
CHANGELOG.md | 18 +-
INSTALL.md | 3 -
README.md | 4 +-
SConstruct | 1961 ++++++++++----------
appveyor.yml | 26 +
benchmark/build.py | 1 +
benchmark/run | 2 +-
benchmark/test_getline.cpp | 125 ++
benchmark/test_rendering.cpp | 2 +-
bootstrap.sh | 22 +-
demo/viewer/mapwidget.cpp | 2 +-
demo/viewer/viewer.pro | 1 +
include/mapnik/css_color_grammar.hpp | 1 +
include/mapnik/css_color_grammar_impl.hpp | 9 +-
include/mapnik/csv/csv_grammar.hpp | 58 +-
include/mapnik/expression_grammar.hpp | 1 +
include/mapnik/expression_grammar_impl.hpp | 8 +
include/mapnik/feature.hpp | 3 -
include/mapnik/feature_style_processor.hpp | 2 +-
include/mapnik/feature_style_processor_impl.hpp | 31 +-
include/mapnik/geometry_is_simple.hpp | 47 +-
include/mapnik/geometry_is_valid.hpp | 178 +-
include/mapnik/image_any.hpp | 4 +-
include/mapnik/jpeg_io.hpp | 10 +-
include/mapnik/json/error_handler.hpp | 2 +-
.../mapnik/json/extract_bounding_box_grammar.hpp | 14 +-
include/mapnik/quad_tree.hpp | 172 +-
.../renderer_common/process_group_symbolizer.hpp | 4 +-
include/mapnik/simplify_converter.hpp | 4 +-
include/mapnik/text/placements/base.hpp | 4 +-
include/mapnik/text/placements/dummy.hpp | 6 +-
include/mapnik/text/placements/simple.hpp | 4 +-
include/mapnik/util/singleton.hpp | 9 +
include/mapnik/util/spatial_index.hpp | 155 ++
include/mapnik/value.hpp | 33 +-
include/mapnik/version.hpp | 2 +-
include/mapnik/webp_io.hpp | 6 +-
plugins/input/csv/build.py | 7 +-
plugins/input/csv/csv_datasource.cpp | 250 ++-
plugins/input/csv/csv_datasource.hpp | 14 +-
plugins/input/csv/csv_featureset.cpp | 5 +-
plugins/input/csv/csv_featureset.hpp | 11 +-
plugins/input/csv/csv_index_featureset.cpp | 130 ++
...csv_featureset.hpp => csv_index_featureset.hpp} | 52 +-
plugins/input/csv/csv_inline_featureset.cpp | 6 +-
plugins/input/csv/csv_inline_featureset.hpp | 14 +-
plugins/input/csv/csv_utils.hpp | 74 +-
plugins/input/gdal/build.py | 2 +-
plugins/input/geojson/build.py | 6 +-
plugins/input/geojson/geojson_datasource.cpp | 6 +-
plugins/input/ogr/build.py | 2 +-
plugins/input/pgraster/build.py | 5 +-
plugins/input/postgis/build.py | 4 +-
plugins/input/postgis/postgis_datasource.cpp | 22 +-
plugins/input/postgis/postgis_datasource.hpp | 1 +
plugins/input/postgis/postgis_featureset.cpp | 14 +-
plugins/input/postgis/postgis_featureset.hpp | 4 +-
plugins/input/raster/build.py | 6 +-
plugins/input/raster/raster_datasource.cpp | 1 +
plugins/input/shape/build.py | 6 +-
plugins/input/shape/shape_index_featureset.cpp | 21 +-
plugins/input/shape/shape_index_featureset.hpp | 4 +-
plugins/input/shape/shp_index.hpp | 103 -
plugins/input/sqlite/build.py | 6 +-
plugins/input/topojson/build.py | 6 +-
scripts/build-appveyor.bat | 70 +
scripts/build-local.bat | 32 +
scripts/parse-commit-message.ps1 | 5 +
src/cairo/process_debug_symbolizer.cpp | 1 -
src/debug.cpp | 16 +-
src/image_util.cpp | 1 -
src/svg/svg_parser.cpp | 54 +-
src/text/placements/simple.cpp | 1 +
test/standalone/csv_test.cpp | 16 +-
test/standalone/datasource_registration_test.cpp | 32 +-
test/unit/color/css_color.cpp | 131 +-
test/unit/core/comparison_test.cpp | 49 +
test/unit/datasource/spatial_index.cpp | 90 +
test/unit/geometry/geometry_is_simple.cpp | 320 ++++
test/unit/geometry/geometry_is_valid.cpp | 431 ++++-
test/unit/imaging/image_filter.cpp | 46 +
test/unit/serialization/wkb_formats_test.cpp | 12 +-
test/unit/svg/svg_parser_test.cpp | 20 +
test/visual/renderer.hpp | 17 +-
test/visual/report.cpp | 54 +-
test/visual/report.hpp | 2 +-
test/visual/run.cpp | 66 +-
test/visual/runner.cpp | 27 +-
test/visual/runner.hpp | 29 +-
utils/mapnik-index/build.py | 59 +
utils/mapnik-index/mapnik-index.cpp | 353 ++++
utils/pgsql2sqlite/pgsql2sqlite.hpp | 2 +-
utils/shapeindex/quadtree.hpp | 297 ---
utils/shapeindex/shapeindex.cpp | 8 +-
97 files changed, 4083 insertions(+), 1888 deletions(-)
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..4976173
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.svg text eol=lf
diff --git a/.gitignore b/.gitignore
index 816bc0e..ddd8581 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,7 @@ tests/python_tests/raster_colorizer_test.png
tests/python_tests/raster_colorizer_test_save.xml
utils/mapnik-config/mapnik-config
utils/shapeindex/shapeindex
+utils/mapnik-index/mapnik-index
utils/ogrindex/ogrindex
utils/pgsql2sqlite/pgsql2sqlite
utils/svg2png/svg2png
diff --git a/.travis.yml b/.travis.yml
index b9493a9..c0e2afb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -31,12 +31,12 @@ matrix:
- os: linux
compiler: gcc
env: JOBS=6
- #- os: osx
- # compiler: clang
- # env: JOBS=8 MASON_PUBLISH=true
- #- os: osx
- # compiler: clang
- # env: JOBS=8 COVERAGE=true
+ - os: osx
+ compiler: clang
+ env: JOBS=8 MASON_PUBLISH=true
+ - os: osx
+ compiler: clang
+ env: JOBS=8 COVERAGE=true
before_install:
- export COVERAGE=${COVERAGE:-false}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 538d4ca..d4ecd27 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,11 +6,23 @@ Developers: Please commit along with changes.
For a complete change history, see the git log.
-## Future
+## 3.0.6
-Released: YYYY XX, 2015
+Released: October 7, 2015
-(Packaged from xxxx)
+(Packaged from 3cebe97)
+
+#### Summary
+
+- PostGIS plugin: added `key_field_as_attribute` option. Defaults to `True` to preserve current behavior of having the `key_field` added both
+ as an attribute and as the `feature.id` value. If `key_field_as_attribute=false` is passed then the attribute is discarded (https://github.com/mapnik/mapnik/issues/3115)
+- CSV plugin has been further optimized and has gained experimental support for on-disk indexes (https://github.com/mapnik/mapnik/issues/3089)
+- SVG parser now fallsback to using `viewbox` if explicit dimensions are lacking (https://github.com/mapnik/mapnik/issues/3081)
+- Visual tests: new command line arguments `--agg`, `--cairo`, `--svg`, `--grid` for selecting renderers (https://github.com/mapnik/mapnik/pull/3074)
+- Visual tests: new command line argument `--scale-factor` or abbreviated `-s` for setting scale factor (https://github.com/mapnik/mapnik/pull/3074)
+- Fixed parsing colors in hexadecimal notation (https://github.com/mapnik/mapnik/pull/3075)
+- Removed mapnik::Feature type alias of mapnik::feature_impl (https://github.com/mapnik/mapnik/pull/3099)
+- Fixed linking order for plugins to avoid possible linking errors on linux systems (https://github.com/mapnik/mapnik/issues/3105)
## 3.0.5
diff --git a/INSTALL.md b/INSTALL.md
index b88abd2..229a315 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -94,9 +94,6 @@ Additional optional dependencies:
- pg_config - PostgreSQL installation capabilities
* libgdal - GDAL/OGR input (For gdal and ogr plugin support)
* libsqlite3 - SQLite input (needs RTree support builtin) (sqlite plugin support)
- * libocci - Oracle input plugin support
- * libcurl - OSM input plugin support
- * librasterlite - Rasterlite input plugin support
Instructions for installing many of these dependencies on
various platforms can be found at the Mapnik Wiki:
diff --git a/README.md b/README.md
index dcb049e..4d84bb4 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,9 @@ _/ _/ _/_/_/ _/_/_/ _/ _/ _/ _/ _/
_/
```
-[![Build Status](https://secure.travis-ci.org/mapnik/mapnik.png)](http://travis-ci.org/mapnik/mapnik)
+[![Build Status Linux](https://secure.travis-ci.org/mapnik/mapnik.png)](http://travis-ci.org/mapnik/mapnik)
+[![Build status Windows](https://ci.appveyor.com/api/projects/status/hc9l7okdjtucfqqn?svg=true)](https://ci.appveyor.com/project/Mapbox/mapnik)
+[![Coverage Status](https://coveralls.io/repos/mapnik/mapnik/badge.svg?branch=master&service=github)](https://coveralls.io/github/mapnik/mapnik?branch=master)
Mapnik is an open source toolkit for developing mapping applications. At the core is a C++ shared library providing algorithms and patterns for spatial data access and visualization.
diff --git a/SConstruct b/SConstruct
index b1c7f30..0474561 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1,6 +1,6 @@
# This file is part of Mapnik (c++ mapping toolkit)
#
-# Copyright (C) 2013 Artem Pavlenko
+# Copyright (C) 2015 Artem Pavlenko
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -105,28 +105,28 @@ pretty_dep_names = {
# Core plugin build configuration
# opts.AddVariables still hardcoded however...
PLUGINS = { # plugins with external dependencies
- # configured by calling project, hence 'path':None
- 'postgis': {'default':True,'path':None,'inc':'libpq-fe.h','lib':'pq','lang':'C'},
- 'pgraster': {'default':True,'path':None,'inc':'libpq-fe.h','lib':'pq','lang':'C'},
- 'gdal': {'default':True,'path':None,'inc':'gdal_priv.h','lib':'gdal','lang':'C++'},
- 'ogr': {'default':True,'path':None,'inc':'ogrsf_frmts.h','lib':'gdal','lang':'C++'},
- 'sqlite': {'default':True,'path':'SQLITE','inc':'sqlite3.h','lib':'sqlite3','lang':'C'},
- # plugins without external dependencies requiring CheckLibWithHeader...
- 'shape': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
- 'csv': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
- 'raster': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
- 'geojson': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
- 'topojson':{'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}
- }
+ # configured by calling project, hence 'path':None
+ 'postgis': {'default':True,'path':None,'inc':'libpq-fe.h','lib':'pq','lang':'C'},
+ 'pgraster': {'default':True,'path':None,'inc':'libpq-fe.h','lib':'pq','lang':'C'},
+ 'gdal': {'default':True,'path':None,'inc':'gdal_priv.h','lib':'gdal','lang':'C++'},
+ 'ogr': {'default':True,'path':None,'inc':'ogrsf_frmts.h','lib':'gdal','lang':'C++'},
+ 'sqlite': {'default':True,'path':'SQLITE','inc':'sqlite3.h','lib':'sqlite3','lang':'C'},
+ # plugins without external dependencies requiring CheckLibWithHeader...
+ 'shape': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
+ 'csv': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
+ 'raster': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
+ 'geojson': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
+ 'topojson':{'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}
+ }
def init_environment(env):
env.Decider('MD5-timestamp')
env.SourceCode(".", None)
if os.environ.get('RANLIB'):
- env['RANLIB'] = os.environ['RANLIB']
+ env['RANLIB'] = os.environ['RANLIB']
if os.environ.get('AR'):
- env['AR'] = os.environ['AR']
+ env['AR'] = os.environ['AR']
#### SCons build options and initial setup ####
env = Environment(ENV=os.environ)
@@ -142,58 +142,58 @@ def color_print(color,text,newline=True):
# 4 - blue
text = "\033[9%sm%s\033[0m" % (color,text)
if not newline:
- print text,
+ print text,
else:
- print text
+ print text
def regular_print(color,text,newline=True):
if not newline:
- print text,
+ print text,
else:
- print text
+ print text
def call(cmd, silent=False):
stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate()
if not stderr:
- return stdin.strip()
+ return stdin.strip()
elif not silent:
- color_print(1,'Problem encounted with SCons scripts, please post bug report to: https://github.com/mapnik/mapnik/issues \nError was: %s' % stderr)
+ color_print(1,'Problem encounted with SCons scripts, please post bug report to: https://github.com/mapnik/mapnik/issues \nError was: %s' % stderr)
def strip_first(string,find,replace=''):
if string.startswith(find):
- return string.replace(find,replace,1)
+ return string.replace(find,replace,1)
return string
# http://www.scons.org/wiki/InstallTargets
def create_uninstall_target(env, path, is_glob=False):
if 'uninstall' in COMMAND_LINE_TARGETS:
- if is_glob:
- all_files = Glob(path,strings=True)
- for filei in all_files:
- env.Command( "uninstall-"+filei, filei,
- [
- Delete("$SOURCE"),
- ])
- env.Alias("uninstall", "uninstall-"+filei)
- else:
- if os.path.exists(path):
- env.Command( "uninstall-"+path, path,
- [
- Delete("$SOURCE"),
- ])
- env.Alias("uninstall", "uninstall-"+path)
+ if is_glob:
+ all_files = Glob(path,strings=True)
+ for filei in all_files:
+ env.Command( "uninstall-"+filei, filei,
+ [
+ Delete("$SOURCE"),
+ ])
+ env.Alias("uninstall", "uninstall-"+filei)
+ else:
+ if os.path.exists(path):
+ env.Command( "uninstall-"+path, path,
+ [
+ Delete("$SOURCE"),
+ ])
+ env.Alias("uninstall", "uninstall-"+path)
def shortest_name(libs):
name = '-'*200
for lib in libs:
- if len(name) > len(lib):
- name = lib
+ if len(name) > len(lib):
+ name = lib
return name
def rm_path(item,set,_env):
for i in _env[set]:
- if i.startswith(item):
- _env[set].remove(i)
+ if i.startswith(item):
+ _env[set].remove(i)
def sort_paths(items,priority):
"""Sort paths such that compiling and linking will globally prefer custom or local libs
@@ -217,57 +217,57 @@ def sort_paths(items,priority):
# parse types of paths into logical/meaningful groups
# based on commonly encountered lib directories on linux and osx
for i in items:
- # internal paths for code kept inside
- # the mapnik sources
- if i.startswith('#'):
- path_types['internal'].append(i)
- # Mac OS X user installed frameworks
- elif '/Library/Frameworks' in i:
- path_types['frameworks'].append(i)
- # various 'local' installs like /usr/local or /opt/local
- elif 'local' in i or '/sw' in i:
- if '/usr/local' in i:
- path_types['user'].insert(0,i)
- else:
- path_types['user'].append(i)
- # key system libs (likely others will fall into 'other')
- elif '/usr/' in i or '/System' in i or i.startswith('/lib'):
- path_types['system'].append(i)
- # anything not yet matched...
- # likely a combo of rare system lib paths and
- # very custom user paths that should ideally be
- # in 'user'
- else:
- path_types['other'].append(i)
+ # internal paths for code kept inside
+ # the mapnik sources
+ if i.startswith('#'):
+ path_types['internal'].append(i)
+ # Mac OS X user installed frameworks
+ elif '/Library/Frameworks' in i:
+ path_types['frameworks'].append(i)
+ # various 'local' installs like /usr/local or /opt/local
+ elif 'local' in i or '/sw' in i:
+ if '/usr/local' in i:
+ path_types['user'].insert(0,i)
+ else:
+ path_types['user'].append(i)
+ # key system libs (likely others will fall into 'other')
+ elif '/usr/' in i or '/System' in i or i.startswith('/lib'):
+ path_types['system'].append(i)
+ # anything not yet matched...
+ # likely a combo of rare system lib paths and
+ # very custom user paths that should ideally be
+ # in 'user'
+ else:
+ path_types['other'].append(i)
# build up new list based on priority list
for path in priority:
- if path_types.has_key(path):
- dirs = path_types[path]
- new.extend(dirs)
- path_types.pop(path)
- else:
- color_print(1,'\nSorry, "%s" is NOT a valid value for option "LINK_PRIORITY": values include: %s' % (path,','.join(path_types.keys())))
- color_print(1,'\tinternal: the local directory of the Mapnik sources (prefix #) (eg. used to link internal agg)')
- color_print(1,'\tframeworks: on osx the /Library/Frameworks directory')
- color_print(1,'\tuser: any path with "local" or "/sw" inside it')
- color_print(1,'\tsystem: any path not yet matched with "/usr/","/lib", or "/System" (osx) inside it')
- color_print(1,'\tother: any paths you specified not matched by criteria used to parse the others')
- color_print(1,'\tother: any paths you specified not matched by criteria used to parse the others')
- color_print(1,'The Default priority is: %s' % ','.join(DEFAULT_LINK_PRIORITY))
- color_print(1,'Any priority groups not listed will be appended to the list at the end')
- Exit(1)
+ if path_types.has_key(path):
+ dirs = path_types[path]
+ new.extend(dirs)
+ path_types.pop(path)
+ else:
+ color_print(1,'\nSorry, "%s" is NOT a valid value for option "LINK_PRIORITY": values include: %s' % (path,','.join(path_types.keys())))
+ color_print(1,'\tinternal: the local directory of the Mapnik sources (prefix #) (eg. used to link internal agg)')
+ color_print(1,'\tframeworks: on osx the /Library/Frameworks directory')
+ color_print(1,'\tuser: any path with "local" or "/sw" inside it')
+ color_print(1,'\tsystem: any path not yet matched with "/usr/","/lib", or "/System" (osx) inside it')
+ color_print(1,'\tother: any paths you specified not matched by criteria used to parse the others')
+ color_print(1,'\tother: any paths you specified not matched by criteria used to parse the others')
+ color_print(1,'The Default priority is: %s' % ','.join(DEFAULT_LINK_PRIORITY))
+ color_print(1,'Any priority groups not listed will be appended to the list at the end')
+ Exit(1)
# append remaining paths potentially not requested
# by any custom priority list defined by user
for k,v in path_types.items():
- new.extend(v)
+ new.extend(v)
return new
def pretty_dep(dep):
pretty = pretty_dep_names.get(dep)
if pretty:
- return '%s (%s)' % (dep,pretty)
+ return '%s (%s)' % (dep,pretty)
elif 'boost' in dep:
- return '%s (%s)' % (dep,'more info see: https://github.com/mapnik/mapnik/wiki/Mapnik-Installation & http://www.boost.org')
+ return '%s (%s)' % (dep,'more info see: https://github.com/mapnik/mapnik/wiki/Mapnik-Installation & http://www.boost.org')
return dep
@@ -400,6 +400,7 @@ opts.AddVariables(
BoolVariable('DEMO', 'Compile demo c++ application', 'True'),
BoolVariable('PGSQL2SQLITE', 'Compile and install a utility to convert postgres tables to sqlite', 'False'),
BoolVariable('SHAPEINDEX', 'Compile and install a utility to generate shapefile indexes in the custom format (.index) Mapnik supports', 'True'),
+ BoolVariable('MAPNIK_INDEX', 'Compile and install a utility to generate file indexes for CSV and GeoJSON in the custom format (.index) Mapnik supports', 'True'),
BoolVariable('SVG2PNG', 'Compile and install a utility to generate render an svg file to a png on the command line', 'False'),
BoolVariable('NIK2IMG', 'Compile and install a utility to generate render a map to an image', 'True'),
BoolVariable('COLOR_PRINT', 'Print build status information in color', 'True'),
@@ -410,74 +411,74 @@ opts.AddVariables(
# these include all scons core variables as well as custom
# env variables needed in SConscript files
pickle_store = [# Scons internal variables
- 'CC', # compiler user to check if c deps compile during configure
- 'CXX', # C++ compiler to compile mapnik
- 'CFLAGS',
- 'CPPDEFINES',
- 'CPPFLAGS', # c preprocessor flags
- 'CPPPATH',
- 'CXXFLAGS', # C++ flags built up during configure
- 'LIBPATH',
- 'LIBS',
- 'LINKFLAGS',
- 'CUSTOM_LDFLAGS', # user submitted
- 'CUSTOM_DEFINES', # user submitted
- 'CUSTOM_CXXFLAGS', # user submitted
- 'CUSTOM_CFLAGS', # user submitted
- 'MAPNIK_LIB_NAME',
- 'LINK',
- 'RUNTIME_LINK',
- # Mapnik's SConstruct build variables
- 'PLUGINS',
- 'ABI_VERSION',
- 'MAPNIK_VERSION_STRING',
- 'MAPNIK_VERSION',
- 'PLATFORM',
- 'BOOST_ABI',
- 'BOOST_APPEND',
- 'LIBDIR_SCHEMA',
- 'REQUESTED_PLUGINS',
- 'COLOR_PRINT',
- 'HAS_CAIRO',
- 'MAPNIK_HAS_DLFCN',
- 'HAS_PYCAIRO',
- 'PYCAIRO_PATHS',
- 'HAS_LIBXML2',
- 'PKG_CONFIG_PATH',
- 'PATH',
- 'PATH_REMOVE',
- 'PATH_REPLACE',
- 'MAPNIK_LIB_DIR',
- 'MAPNIK_LIB_DIR_DEST',
- 'INSTALL_PREFIX',
- 'MAPNIK_INPUT_PLUGINS',
- 'MAPNIK_INPUT_PLUGINS_DEST',
- 'MAPNIK_FONTS',
- 'MAPNIK_FONTS_DEST',
- 'MAPNIK_BUNDLED_SHARE_DIRECTORY',
- 'MAPNIK_LIB_BASE',
- 'MAPNIK_LIB_BASE_DEST',
- 'EXTRA_FREETYPE_LIBS',
- 'LIBMAPNIK_CPPATHS',
- 'LIBMAPNIK_DEFINES',
- 'LIBMAPNIK_CXXFLAGS',
- 'CAIRO_LIBPATHS',
- 'CAIRO_ALL_LIBS',
- 'CAIRO_CPPPATHS',
- 'GRID_RENDERER',
- 'SVG_RENDERER',
- 'SQLITE_LINKFLAGS',
- 'BOOST_LIB_VERSION_FROM_HEADER',
- 'BIGINT',
- 'HOST'
- ]
+ 'CC', # compiler user to check if c deps compile during configure
+ 'CXX', # C++ compiler to compile mapnik
+ 'CFLAGS',
+ 'CPPDEFINES',
+ 'CPPFLAGS', # c preprocessor flags
+ 'CPPPATH',
+ 'CXXFLAGS', # C++ flags built up during configure
+ 'LIBPATH',
+ 'LIBS',
+ 'LINKFLAGS',
+ 'CUSTOM_LDFLAGS', # user submitted
+ 'CUSTOM_DEFINES', # user submitted
+ 'CUSTOM_CXXFLAGS', # user submitted
+ 'CUSTOM_CFLAGS', # user submitted
+ 'MAPNIK_LIB_NAME',
+ 'LINK',
+ 'RUNTIME_LINK',
+ # Mapnik's SConstruct build variables
+ 'PLUGINS',
+ 'ABI_VERSION',
+ 'MAPNIK_VERSION_STRING',
+ 'MAPNIK_VERSION',
+ 'PLATFORM',
+ 'BOOST_ABI',
+ 'BOOST_APPEND',
+ 'LIBDIR_SCHEMA',
+ 'REQUESTED_PLUGINS',
+ 'COLOR_PRINT',
+ 'HAS_CAIRO',
+ 'MAPNIK_HAS_DLFCN',
+ 'HAS_PYCAIRO',
+ 'PYCAIRO_PATHS',
+ 'HAS_LIBXML2',
+ 'PKG_CONFIG_PATH',
+ 'PATH',
+ 'PATH_REMOVE',
+ 'PATH_REPLACE',
+ 'MAPNIK_LIB_DIR',
+ 'MAPNIK_LIB_DIR_DEST',
+ 'INSTALL_PREFIX',
+ 'MAPNIK_INPUT_PLUGINS',
+ 'MAPNIK_INPUT_PLUGINS_DEST',
+ 'MAPNIK_FONTS',
+ 'MAPNIK_FONTS_DEST',
+ 'MAPNIK_BUNDLED_SHARE_DIRECTORY',
+ 'MAPNIK_LIB_BASE',
+ 'MAPNIK_LIB_BASE_DEST',
+ 'EXTRA_FREETYPE_LIBS',
+ 'LIBMAPNIK_CPPATHS',
+ 'LIBMAPNIK_DEFINES',
+ 'LIBMAPNIK_CXXFLAGS',
+ 'CAIRO_LIBPATHS',
+ 'CAIRO_ALL_LIBS',
+ 'CAIRO_CPPPATHS',
+ 'GRID_RENDERER',
+ 'SVG_RENDERER',
+ 'SQLITE_LINKFLAGS',
+ 'BOOST_LIB_VERSION_FROM_HEADER',
+ 'BIGINT',
+ 'HOST'
+ ]
# Add all other user configurable options to pickle pickle_store
# We add here more options than are needed for the build stage
# but helpful so that scons -h shows the exact cached options
for opt in opts.options:
if opt.key not in pickle_store:
- pickle_store.append(opt.key)
+ pickle_store.append(opt.key)
# Method of adding configure behavior to Scons adapted from:
# http://freeorion.svn.sourceforge.net/svnroot/freeorion/trunk/FreeOrion/SConstruct
@@ -509,24 +510,24 @@ opts.Update(env)
# if we are not configuring overwrite environment with pickled settings
if not force_configure:
if os.path.exists(SCONS_CONFIGURE_CACHE):
- try:
- pickled_environment = open(SCONS_CONFIGURE_CACHE, 'r')
- pickled_values = pickle.load(pickled_environment)
- for key, value in pickled_values.items():
- env[key] = value
- preconfigured = True
- except:
- preconfigured = False
+ try:
+ pickled_environment = open(SCONS_CONFIGURE_CACHE, 'r')
+ pickled_values = pickle.load(pickled_environment)
+ for key, value in pickled_values.items():
+ env[key] = value
+ preconfigured = True
+ except:
+ preconfigured = False
else:
- preconfigured = False
+ preconfigured = False
# check for missing keys in pickled settings
# which can occur when keys are added or changed between
# rebuilds, e.g. for folks following trunk
for opt in pickle_store:
if not opt in env:
- #print 'missing opt', opt
- preconfigured = False
+ #print 'missing opt', opt
+ preconfigured = False
# if custom arguments are supplied make sure to accept them
if opts.args:
@@ -539,8 +540,8 @@ if opts.args:
elif preconfigured:
if not HELP_REQUESTED:
- color_print(4,'Using previous successful configuration...')
- color_print(4,'Re-configure by running "python scons/scons.py configure".')
+ color_print(4,'Using previous successful configuration...')
+ color_print(4,'Re-configure by running "python scons/scons.py configure".')
if env.has_key('COLOR_PRINT') and env['COLOR_PRINT'] == False:
color_print = regular_print
@@ -556,11 +557,11 @@ def prioritize_paths(context,silent=True):
env = context.env
prefs = env['LINK_PRIORITY'].split(',')
if not silent:
- context.Message( 'Sorting lib and inc compiler paths...')
+ context.Message( 'Sorting lib and inc compiler paths...')
env['LIBPATH'] = sort_paths(env['LIBPATH'],prefs)
env['CPPPATH'] = sort_paths(env['CPPPATH'],prefs)
if silent:
- context.did_show_result=1
+ context.did_show_result=1
ret = context.Result( True )
return ret
@@ -587,42 +588,42 @@ def parse_config(context, config, checks='--libs --cflags'):
tool = config.lower().replace('_','-')
toolname = tool
if config in ('GDAL_CONFIG'):
- toolname += ' %s' % checks
+ toolname += ' %s' % checks
context.Message( 'Checking for %s... ' % toolname)
cmd = '%s %s' % (env[config],checks)
ret = context.TryAction(cmd)[0]
parsed = False
if ret:
- try:
- if 'gdal-config' in cmd:
- env.ParseConfig(cmd)
- # hack for potential -framework GDAL syntax
- # which will not end up being added to env['LIBS']
- # and thus breaks knowledge below that gdal worked
- # TODO - upgrade our scons logic to support Framework linking
- if env['PLATFORM'] == 'Darwin':
- value = call(cmd,silent=True)
- if value and '-framework GDAL' in value:
- env['LIBS'].append('gdal')
- if os.path.exists('/Library/Frameworks/GDAL.framework/unix/lib'):
- env['LIBPATH'].insert(0,'/Library/Frameworks/GDAL.framework/unix/lib')
- if 'GDAL' in env.get('FRAMEWORKS',[]):
- env["FRAMEWORKS"].remove("GDAL")
- else:
- env.ParseConfig(cmd)
- parsed = True
- except OSError, e:
- ret = False
- print ' (xml2-config not found!)'
+ try:
+ if 'gdal-config' in cmd:
+ env.ParseConfig(cmd)
+ # hack for potential -framework GDAL syntax
+ # which will not end up being added to env['LIBS']
+ # and thus breaks knowledge below that gdal worked
+ # TODO - upgrade our scons logic to support Framework linking
+ if env['PLATFORM'] == 'Darwin':
+ value = call(cmd,silent=True)
+ if value and '-framework GDAL' in value:
+ env['LIBS'].append('gdal')
+ if os.path.exists('/Library/Frameworks/GDAL.framework/unix/lib'):
+ env['LIBPATH'].insert(0,'/Library/Frameworks/GDAL.framework/unix/lib')
+ if 'GDAL' in env.get('FRAMEWORKS',[]):
+ env["FRAMEWORKS"].remove("GDAL")
+ else:
+ env.ParseConfig(cmd)
+ parsed = True
+ except OSError, e:
+ ret = False
+ print ' (xml2-config not found!)'
if not parsed:
- if config in ('GDAL_CONFIG'):
- # optional deps...
- if tool not in env['SKIPPED_DEPS']:
- env['SKIPPED_DEPS'].append(tool)
- conf.rollback_option(config)
- else: # freetype and libxml2, not optional
- if tool not in env['MISSING_DEPS']:
- env['MISSING_DEPS'].append(tool)
+ if config in ('GDAL_CONFIG'):
+ # optional deps...
+ if tool not in env['SKIPPED_DEPS']:
+ env['SKIPPED_DEPS'].append(tool)
+ conf.rollback_option(config)
+ else: # freetype and libxml2, not optional
+ if tool not in env['MISSING_DEPS']:
+ env['MISSING_DEPS'].append(tool)
context.Result( ret )
return ret
@@ -635,22 +636,22 @@ def get_pkg_lib(context, config, lib):
ret = context.TryAction(cmd)[0]
parsed = False
if ret:
- try:
- value = call(cmd,silent=True)
- if ' ' in value:
- parts = value.split(' ')
- if len(parts) > 1:
- value = parts[1]
- libnames = re.findall(libpattern,value)
- if libnames:
- libname = libnames[0]
- else:
- # osx 1.8 install gives '-framework GDAL'
- libname = 'gdal'
- except Exception, e:
- ret = False
- print ' unable to determine library name:'# %s' % str(e)
- return None
+ try:
+ value = call(cmd,silent=True)
+ if ' ' in value:
+ parts = value.split(' ')
+ if len(parts) > 1:
+ value = parts[1]
+ libnames = re.findall(libpattern,value)
+ if libnames:
+ libname = libnames[0]
+ else:
+ # osx 1.8 install gives '-framework GDAL'
+ libname = 'gdal'
+ except Exception, e:
+ ret = False
+ print ' unable to determine library name:'# %s' % str(e)
+ return None
context.Result( libname )
return libname
@@ -661,15 +662,15 @@ def parse_pg_config(context, config):
context.Message( 'Checking for %s... ' % tool)
ret = context.TryAction(env[config])[0]
if ret:
- lib_path = call('%s --libdir' % env[config])
- inc_path = call('%s --includedir' % env[config])
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- env.AppendUnique(LIBPATH = fix_path(lib_path))
- lpq = env['PLUGINS']['postgis']['lib']
- env.Append(LIBS = lpq)
+ lib_path = call('%s --libdir' % env[config])
+ inc_path = call('%s --includedir' % env[config])
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
+ lpq = env['PLUGINS']['postgis']['lib']
+ env.Append(LIBS = lpq)
else:
- env['SKIPPED_DEPS'].append(tool)
- conf.rollback_option(config)
+ env['SKIPPED_DEPS'].append(tool)
+ conf.rollback_option(config)
context.Result( ret )
return ret
@@ -678,8 +679,8 @@ def ogr_enabled(context):
context.Message( 'Checking if gdal is ogr enabled... ')
ret = context.TryAction('%s --ogr-enabled' % env['GDAL_CONFIG'])[0]
if not ret:
- if 'ogr' not in env['SKIPPED_DEPS']:
- env['SKIPPED_DEPS'].append('ogr')
+ if 'ogr' not in env['SKIPPED_DEPS']:
+ env['SKIPPED_DEPS'].append('ogr')
context.Result( ret )
return ret
@@ -687,8 +688,8 @@ def rollback_option(context,variable):
global opts
env = context.env
for item in opts.options:
- if item.key == variable:
- env[variable] = item.default
+ if item.key == variable:
+ env[variable] = item.default
def FindBoost(context, prefixes, thread_flag):
"""Routine to auto-find boost header dir, lib dir, and library naming structure.
@@ -703,72 +704,72 @@ def FindBoost(context, prefixes, thread_flag):
env['BOOST_APPEND'] = str()
if env['THREADING'] == 'multi':
- search_lib = 'libboost_thread'
+ search_lib = 'libboost_thread'
else:
- search_lib = 'libboost_filesystem'
+ search_lib = 'libboost_filesystem'
# note: must call normpath to strip trailing slash otherwise dirname
# does not remove 'lib' and 'include'
prefixes.insert(0,os.path.dirname(os.path.normpath(env['BOOST_INCLUDES'])))
prefixes.insert(0,os.path.dirname(os.path.normpath(env['BOOST_LIBS'])))
for searchDir in prefixes:
- libItems = glob(os.path.join(searchDir, env['LIBDIR_SCHEMA'], '%s*.*' % search_lib))
- if not libItems:
- libItems = glob(os.path.join(searchDir, 'lib/%s*.*' % search_lib))
- incItems = glob(os.path.join(searchDir, 'include/boost*/'))
- if len(libItems) >= 1 and len(incItems) >= 1:
- BOOST_LIB_DIR = os.path.dirname(libItems[0])
- BOOST_INCLUDE_DIR = incItems[0].rstrip('boost/')
- shortest_lib_name = shortest_name(libItems)
- match = re.search(r'%s(.*)\..*' % search_lib, shortest_lib_name)
- if hasattr(match,'groups'):
- BOOST_APPEND = match.groups()[0]
- break
+ libItems = glob(os.path.join(searchDir, env['LIBDIR_SCHEMA'], '%s*.*' % search_lib))
+ if not libItems:
+ libItems = glob(os.path.join(searchDir, 'lib/%s*.*' % search_lib))
+ incItems = glob(os.path.join(searchDir, 'include/boost*/'))
+ if len(libItems) >= 1 and len(incItems) >= 1:
+ BOOST_LIB_DIR = os.path.dirname(libItems[0])
+ BOOST_INCLUDE_DIR = incItems[0].rstrip('boost/')
+ shortest_lib_name = shortest_name(libItems)
+ match = re.search(r'%s(.*)\..*' % search_lib, shortest_lib_name)
+ if hasattr(match,'groups'):
+ BOOST_APPEND = match.groups()[0]
+ break
msg = str()
if BOOST_LIB_DIR:
- msg += '\nFound boost libs: %s' % BOOST_LIB_DIR
- env['BOOST_LIBS'] = BOOST_LIB_DIR
+ msg += '\nFound boost libs: %s' % BOOST_LIB_DIR
+ env['BOOST_LIBS'] = BOOST_LIB_DIR
elif not env['BOOST_LIBS']:
- env['BOOST_LIBS'] = '/usr/' + env['LIBDIR_SCHEMA']
- msg += '\nUsing default boost lib dir: %s' % env['BOOST_LIBS']
+ env['BOOST_LIBS'] = '/usr/' + env['LIBDIR_SCHEMA']
+ msg += '\nUsing default boost lib dir: %s' % env['BOOST_LIBS']
else:
- msg += '\nUsing boost lib dir: %s' % env['BOOST_LIBS']
+ msg += '\nUsing boost lib dir: %s' % env['BOOST_LIBS']
if BOOST_INCLUDE_DIR:
- msg += '\nFound boost headers: %s' % BOOST_INCLUDE_DIR
- env['BOOST_INCLUDES'] = BOOST_INCLUDE_DIR
+ msg += '\nFound boost headers: %s' % BOOST_INCLUDE_DIR
+ env['BOOST_INCLUDES'] = BOOST_INCLUDE_DIR
elif not env['BOOST_INCLUDES']:
- env['BOOST_INCLUDES'] = '/usr/include'
- msg += '\nUsing default boost include dir: %s' % env['BOOST_INCLUDES']
+ env['BOOST_INCLUDES'] = '/usr/include'
+ msg += '\nUsing default boost include dir: %s' % env['BOOST_INCLUDES']
else:
- msg += '\nUsing boost include dir: %s' % env['BOOST_INCLUDES']
+ msg += '\nUsing boost include dir: %s' % env['BOOST_INCLUDES']
if not env['BOOST_TOOLKIT'] and not env['BOOST_ABI'] and not env['BOOST_VERSION']:
- if BOOST_APPEND:
- msg += '\nFound boost lib name extension: %s' % BOOST_APPEND
- env['BOOST_APPEND'] = BOOST_APPEND
+ if BOOST_APPEND:
+ msg += '\nFound boost lib name extension: %s' % BOOST_APPEND
+ env['BOOST_APPEND'] = BOOST_APPEND
else:
- # Creating BOOST_APPEND according to the Boost library naming order,
- # which goes <toolset>-<threading>-<abi>-<version>. See:
- # http://www.boost.org/doc/libs/1_35_0/more/getting_started/unix-variants.html#library-naming
- append_params = ['']
- if env['BOOST_TOOLKIT']: append_params.append(env['BOOST_TOOLKIT'])
- if thread_flag: append_params.append(thread_flag)
- if env['BOOST_ABI']: append_params.append(env['BOOST_ABI'])
- if env['BOOST_VERSION']: append_params.append(env['BOOST_VERSION'])
-
- # Constructing the BOOST_APPEND setting that will be used to find the
- # Boost libraries.
- if len(append_params) > 1:
- env['BOOST_APPEND'] = '-'.join(append_params)
- msg += '\nFound boost lib name extension: %s' % env['BOOST_APPEND']
+ # Creating BOOST_APPEND according to the Boost library naming order,
+ # which goes <toolset>-<threading>-<abi>-<version>. See:
+ # http://www.boost.org/doc/libs/1_35_0/more/getting_started/unix-variants.html#library-naming
+ append_params = ['']
+ if env['BOOST_TOOLKIT']: append_params.append(env['BOOST_TOOLKIT'])
+ if thread_flag: append_params.append(thread_flag)
+ if env['BOOST_ABI']: append_params.append(env['BOOST_ABI'])
+ if env['BOOST_VERSION']: append_params.append(env['BOOST_VERSION'])
+
+ # Constructing the BOOST_APPEND setting that will be used to find the
+ # Boost libraries.
+ if len(append_params) > 1:
+ env['BOOST_APPEND'] = '-'.join(append_params)
+ msg += '\nFound boost lib name extension: %s' % env['BOOST_APPEND']
env.AppendUnique(CPPPATH = fix_path(env['BOOST_INCLUDES']))
env.AppendUnique(LIBPATH = fix_path(env['BOOST_LIBS']))
if env['COLOR_PRINT']:
- msg = "\033[94m%s\033[0m" % (msg)
+ msg = "\033[94m%s\033[0m" % (msg)
ret = context.Result(msg)
return ret
@@ -777,14 +778,14 @@ def CheckBoost(context, version, silent=False):
v_arr = version.split(".")
version_n = 0
if len(v_arr) > 0:
- version_n += int(v_arr[0])*100000
+ version_n += int(v_arr[0])*100000
if len(v_arr) > 1:
- version_n += int(v_arr[1])*100
+ version_n += int(v_arr[1])*100
if len(v_arr) > 2:
- version_n += int(v_arr[2])
+ version_n += int(v_arr[2])
if not silent:
- context.Message('Checking for Boost version >= %s... ' % (version))
+ context.Message('Checking for Boost version >= %s... ' % (version))
ret = context.TryRun("""
#include <boost/version.hpp>
@@ -796,13 +797,13 @@ int main()
""" % version_n, '.cpp')[0]
if silent:
- context.did_show_result=1
+ context.did_show_result=1
context.Result(ret)
return ret
def CheckCairoHasFreetype(context, silent=False):
if not silent:
- context.Message('Checking for cairo freetype font support ... ')
+ context.Message('Checking for cairo freetype font support ... ')
context.env.AppendUnique(CPPPATH=copy(env['CAIRO_CPPPATHS']))
ret = context.TryRun("""
@@ -820,15 +821,15 @@ int main()
""", '.cpp')[0]
if silent:
- context.did_show_result=1
+ context.did_show_result=1
context.Result(ret)
for item in env['CAIRO_CPPPATHS']:
- rm_path(item,'CPPPATH',context.env)
+ rm_path(item,'CPPPATH',context.env)
return ret
def CheckHasDlfcn(context, silent=False):
if not silent:
- context.Message('Checking for dlfcn.h support ... ')
+ context.Message('Checking for dlfcn.h support ... ')
ret = context.TryCompile("""
#include <dlfcn.h>
@@ -840,7 +841,7 @@ int main()
""", '.cpp')
if silent:
- context.did_show_result=1
+ context.did_show_result=1
context.Result(ret)
return ret
@@ -865,7 +866,7 @@ return 0;
def CheckBoostScopedEnum(context, silent=False):
if not silent:
- context.Message('Checking whether Boost was compiled with C++11 scoped enums ... ')
+ context.Message('Checking whether Boost was compiled with C++11 scoped enums ... ')
ret = context.TryLink("""
#include <boost/filesystem.hpp>
@@ -877,7 +878,7 @@ int main()
}
""", '.cpp')
if silent:
- context.did_show_result=1
+ context.did_show_result=1
context.Result(ret)
return ret
@@ -899,13 +900,13 @@ int main()
context.did_show_result=1
result = ret[1].strip()
if not result:
- context.Result('error, could not get major and minor version from unicode/uversion.h')
- return False
+ context.Result('error, could not get major and minor version from unicode/uversion.h')
+ return False
major, minor = map(int,result.split('.'))
if major >= 4 and minor >= 0:
- color_print(4,'found: icu %s' % result)
- return True
+ color_print(4,'found: icu %s' % result)
+ return True
color_print(1,'\nFound insufficient icu version... %s' % result)
return False
@@ -928,24 +929,24 @@ int main()
context.did_show_result=1
result = ret[1].strip()
if not result:
- context.Result('error, could not get version from hb.h')
- return False
+ context.Result('error, could not get version from hb.h')
+ return False
items = result.split(';')
if items[0] == '1':
- color_print(4,'found: HarfBuzz %s' % items[1])
- return True
+ color_print(4,'found: HarfBuzz %s' % items[1])
+ return True
color_print(1,'\nHarfbuzz >= %s required but found ... %s' % (HARFBUZZ_MIN_VERSION_STRING,items[1]))
return False
def boost_regex_has_icu(context):
if env['RUNTIME_LINK'] == 'static':
- # re-order icu libs to ensure linux linker is happy
- for lib_name in ['icui18n',env['ICU_LIB_NAME'],'icudata']:
- if lib_name in context.env['LIBS']:
- context.env['LIBS'].remove(lib_name)
- context.env.Append(LIBS=lib_name)
+ # re-order icu libs to ensure linux linker is happy
+ for lib_name in ['icui18n',env['ICU_LIB_NAME'],'icudata']:
+ if lib_name in context.env['LIBS']:
+ context.env['LIBS'].remove(lib_name)
+ context.env.Append(LIBS=lib_name)
ret = context.TryRun("""
#include <boost/regex/icu.hpp>
@@ -955,12 +956,12 @@ int main()
{
U_NAMESPACE_QUALIFIER UnicodeString ustr;
try {
- boost::u32regex pattern = boost::make_u32regex(ustr);
+ boost::u32regex pattern = boost::make_u32regex(ustr);
}
// an exception is fine, still indicates support is
// likely compiled into regex
catch (...) {
- return 0;
+ return 0;
}
return 0;
}
@@ -969,7 +970,7 @@ int main()
context.Message('Checking if boost_regex was built with ICU unicode support... ')
context.Result(ret[0])
if ret[0]:
- return True
+ return True
return False
def sqlite_has_rtree(context, silent=False):
@@ -991,20 +992,20 @@ int main()
rc = sqlite3_open(":memory:", &db);
if (rc != SQLITE_OK)
{
- printf("error 1: %s\\n", sqlite3_errmsg(db));
+ printf("error 1: %s\\n", sqlite3_errmsg(db));
}
const char * sql = "create virtual table foo using rtree(pkid, xmin, xmax, ymin, ymax)";
rc = sqlite3_exec(db, sql, 0, 0, 0);
if (rc != SQLITE_OK)
{
- printf("error 2: %s\\n", sqlite3_errmsg(db));
- sqlite3_close(db);
+ printf("error 2: %s\\n", sqlite3_errmsg(db));
+ sqlite3_close(db);
}
else
{
- printf("yes, has rtree!\\n");
- sqlite3_close(db);
- return 0;
+ printf("yes, has rtree!\\n");
+ sqlite3_close(db);
+ return 0;
}
return -1;
@@ -1012,12 +1013,12 @@ int main()
""", '.c')
if not silent:
- context.Message('Checking if SQLite supports RTREE... ')
+ context.Message('Checking if SQLite supports RTREE... ')
if silent:
- context.did_show_result=1
+ context.did_show_result=1
context.Result(ret[0])
if ret[0]:
- return True
+ return True
return False
def supports_cxx11(context,silent=False):
@@ -1034,54 +1035,54 @@ int main()
""", '.cpp')
if not silent:
- context.Message('Checking if compiler (%s) supports -std=c++11 flag... ' % context.env.get('CXX','CXX'))
+ context.Message('Checking if compiler (%s) supports -std=c++11 flag... ' % context.env.get('CXX','CXX'))
if silent:
- context.did_show_result=1
+ context.did_show_result=1
context.Result(ret[0])
if ret[0]:
- return True
+ return True
return False
conf_tests = { 'prioritize_paths' : prioritize_paths,
- 'CheckPKGConfig' : CheckPKGConfig,
- 'CheckPKG' : CheckPKG,
- 'CheckPKGVersion' : CheckPKGVersion,
- 'FindBoost' : FindBoost,
- 'CheckBoost' : CheckBoost,
- 'CheckCairoHasFreetype' : CheckCairoHasFreetype,
- 'CheckHasDlfcn' : CheckHasDlfcn,
- 'GetBoostLibVersion' : GetBoostLibVersion,
- 'parse_config' : parse_config,
- 'parse_pg_config' : parse_pg_config,
- 'ogr_enabled' : ogr_enabled,
- 'get_pkg_lib' : get_pkg_lib,
- 'rollback_option' : rollback_option,
- 'icu_at_least_four_two' : icu_at_least_four_two,
- 'harfbuzz_version' : harfbuzz_version,
- 'boost_regex_has_icu' : boost_regex_has_icu,
- 'sqlite_has_rtree' : sqlite_has_rtree,
- 'supports_cxx11' : supports_cxx11,
- 'CheckBoostScopedEnum' : CheckBoostScopedEnum,
- }
+ 'CheckPKGConfig' : CheckPKGConfig,
+ 'CheckPKG' : CheckPKG,
+ 'CheckPKGVersion' : CheckPKGVersion,
+ 'FindBoost' : FindBoost,
+ 'CheckBoost' : CheckBoost,
+ 'CheckCairoHasFreetype' : CheckCairoHasFreetype,
+ 'CheckHasDlfcn' : CheckHasDlfcn,
+ 'GetBoostLibVersion' : GetBoostLibVersion,
+ 'parse_config' : parse_config,
+ 'parse_pg_config' : parse_pg_config,
+ 'ogr_enabled' : ogr_enabled,
+ 'get_pkg_lib' : get_pkg_lib,
+ 'rollback_option' : rollback_option,
+ 'icu_at_least_four_two' : icu_at_least_four_two,
+ 'harfbuzz_version' : harfbuzz_version,
+ 'boost_regex_has_icu' : boost_regex_has_icu,
+ 'sqlite_has_rtree' : sqlite_has_rtree,
+ 'supports_cxx11' : supports_cxx11,
+ 'CheckBoostScopedEnum' : CheckBoostScopedEnum,
+ }
def GetMapnikLibVersion():
ver = []
is_pre = False
for line in open('include/mapnik/version.hpp').readlines():
- if line.startswith('#define MAPNIK_MAJOR_VERSION'):
- ver.append(line.split(' ')[2].strip())
- if line.startswith('#define MAPNIK_MINOR_VERSION'):
- ver.append(line.split(' ')[2].strip())
- if line.startswith('#define MAPNIK_PATCH_VERSION'):
- ver.append(line.split(' ')[2].strip())
- if line.startswith('#define MAPNIK_VERSION_IS_RELEASE'):
- if line.split(' ')[2].strip() == "0":
- is_pre = True
+ if line.startswith('#define MAPNIK_MAJOR_VERSION'):
+ ver.append(line.split(' ')[2].strip())
+ if line.startswith('#define MAPNIK_MINOR_VERSION'):
+ ver.append(line.split(' ')[2].strip())
+ if line.startswith('#define MAPNIK_PATCH_VERSION'):
+ ver.append(line.split(' ')[2].strip())
+ if line.startswith('#define MAPNIK_VERSION_IS_RELEASE'):
+ if line.split(' ')[2].strip() == "0":
+ is_pre = True
version_string = ".".join(ver)
if is_pre:
- version_string += '-pre'
+ version_string += '-pre'
return version_string
if not preconfigured:
@@ -1089,40 +1090,40 @@ if not preconfigured:
color_print(4,'Configuring build environment...')
if not env['FAST']:
- SetCacheMode('force')
+ SetCacheMode('force')
if env['USE_CONFIG']:
- if not env['CONFIG'].endswith('.py'):
- color_print(1,'SCons CONFIG file specified is not a python file, will not be read...')
- else:
- # Accept more than one file as comma-delimited list
- user_confs = env['CONFIG'].split(',')
- # If they exist add the files to the existing `opts`
- for conf in user_confs:
- if os.path.exists(conf):
- opts.files.append(conf)
- color_print(4,"SCons CONFIG found: '%s', variables will be inherited..." % conf)
- optfile = file(conf)
- #print optfile.read().replace("\n", " ").replace("'","").replace(" = ","=")
- optfile.close()
-
- elif not conf == SCONS_LOCAL_CONFIG:
- # if default missing, no worries
- # but if the default is overridden and the file is not found, give warning
- color_print(1,"SCons CONFIG not found: '%s'" % conf)
- # Recreate the base environment using modified `opts`
- env = Environment(ENV=os.environ,options=opts)
- init_environment(env)
- env['USE_CONFIG'] = True
+ if not env['CONFIG'].endswith('.py'):
+ color_print(1,'SCons CONFIG file specified is not a python file, will not be read...')
+ else:
+ # Accept more than one file as comma-delimited list
+ user_confs = env['CONFIG'].split(',')
+ # If they exist add the files to the existing `opts`
+ for conf in user_confs:
+ if os.path.exists(conf):
+ opts.files.append(conf)
+ color_print(4,"SCons CONFIG found: '%s', variables will be inherited..." % conf)
+ optfile = file(conf)
+ #print optfile.read().replace("\n", " ").replace("'","").replace(" = ","=")
+ optfile.close()
+
+ elif not conf == SCONS_LOCAL_CONFIG:
+ # if default missing, no worries
+ # but if the default is overridden and the file is not found, give warning
+ color_print(1,"SCons CONFIG not found: '%s'" % conf)
+ # Recreate the base environment using modified `opts`
+ env = Environment(ENV=os.environ,options=opts)
+ init_environment(env)
+ env['USE_CONFIG'] = True
else:
- color_print(4,'SCons USE_CONFIG specified as false, will not inherit variables python config file...')
+ color_print(4,'SCons USE_CONFIG specified as false, will not inherit variables python config file...')
conf = Configure(env, custom_tests = conf_tests)
if env['DEBUG']:
- mode = 'debug mode'
+ mode = 'debug mode'
else:
- mode = 'release mode'
+ mode = 'release mode'
env['PLATFORM'] = platform.uname()[0]
color_print(4,"Configuring on %s in *%s*..." % (env['PLATFORM'],mode))
@@ -1147,7 +1148,7 @@ if not preconfigured:
# previously a leading / was expected for LIB_DIR_NAME
# now strip it to ensure expected behavior
if env['LIB_DIR_NAME'].startswith(os.path.sep):
- env['LIB_DIR_NAME'] = strip_first(env['LIB_DIR_NAME'],os.path.sep)
+ env['LIB_DIR_NAME'] = strip_first(env['LIB_DIR_NAME'],os.path.sep)
# base install location
env['MAPNIK_LIB_BASE'] = os.path.join(env['PREFIX'],env['LIBDIR_SCHEMA'])
@@ -1157,9 +1158,9 @@ if not preconfigured:
env['MAPNIK_INPUT_PLUGINS'] = os.path.join(env['MAPNIK_LIB_DIR'],'input')
# fonts sub directory
if env['SYSTEM_FONTS']:
- env['MAPNIK_FONTS'] = os.path.normpath(env['SYSTEM_FONTS'])
+ env['MAPNIK_FONTS'] = os.path.normpath(env['SYSTEM_FONTS'])
else:
- env['MAPNIK_FONTS'] = os.path.join(env['MAPNIK_LIB_DIR'],'fonts')
+ env['MAPNIK_FONTS'] = os.path.join(env['MAPNIK_LIB_DIR'],'fonts')
# install prefix is a pre-pended base location to
# re-route the install and only intended for package building
@@ -1172,9 +1173,9 @@ if not preconfigured:
env['MAPNIK_LIB_DIR_DEST'] = os.path.join(env['MAPNIK_LIB_BASE_DEST'],env['LIB_DIR_NAME'])
env['MAPNIK_INPUT_PLUGINS_DEST'] = os.path.join(env['MAPNIK_LIB_DIR_DEST'],'input')
if env['SYSTEM_FONTS']:
- env['MAPNIK_FONTS_DEST'] = os.path.normpath(env['SYSTEM_FONTS'])
+ env['MAPNIK_FONTS_DEST'] = os.path.normpath(env['SYSTEM_FONTS'])
else:
- env['MAPNIK_FONTS_DEST'] = os.path.join(env['MAPNIK_LIB_DIR_DEST'],'fonts')
+ env['MAPNIK_FONTS_DEST'] = os.path.join(env['MAPNIK_LIB_DIR_DEST'],'fonts')
if env['LINKING'] == 'static':
env['MAPNIK_LIB_NAME'] = '${LIBPREFIX}${MAPNIK_NAME}${LIBSUFFIX}'
@@ -1182,15 +1183,15 @@ if not preconfigured:
env['MAPNIK_LIB_NAME'] = '${SHLIBPREFIX}${MAPNIK_NAME}${SHLIBSUFFIX}'
if env['PKG_CONFIG_PATH']:
- env['ENV']['PKG_CONFIG_PATH'] = fix_path(env['PKG_CONFIG_PATH'])
- # otherwise this variable == os.environ["PKG_CONFIG_PATH"]
+ env['ENV']['PKG_CONFIG_PATH'] = fix_path(env['PKG_CONFIG_PATH'])
+ # otherwise this variable == os.environ["PKG_CONFIG_PATH"]
if env['PATH']:
- env['ENV']['PATH'] = fix_path(env['PATH']) + ':' + env['ENV']['PATH']
+ env['ENV']['PATH'] = fix_path(env['PATH']) + ':' + env['ENV']['PATH']
if env['SYSTEM_FONTS']:
- if not os.path.isdir(env['SYSTEM_FONTS']):
- color_print(1,'Warning: Directory specified for SYSTEM_FONTS does not exist!')
+ if not os.path.isdir(env['SYSTEM_FONTS']):
+ color_print(1,'Warning: Directory specified for SYSTEM_FONTS does not exist!')
# Set up for libraries and headers dependency checks
env['CPPPATH'] = ['#include']
@@ -1198,8 +1199,8 @@ if not preconfigured:
# set any custom cxxflags and ldflags to come first
if sys.platform == 'darwin' and not env['HOST']:
- DEFAULT_CXX11_CXXFLAGS += ' -stdlib=libc++'
- DEFAULT_CXX11_LINKFLAGS = ' -stdlib=libc++'
+ DEFAULT_CXX11_CXXFLAGS += ' -stdlib=libc++'
+ DEFAULT_CXX11_LINKFLAGS = ' -stdlib=libc++'
env.Append(CPPDEFINES = env['CUSTOM_DEFINES'])
env.Append(CXXFLAGS = DEFAULT_CXX11_CXXFLAGS)
env.Append(CXXFLAGS = env['CUSTOM_CXXFLAGS'])
@@ -1211,11 +1212,11 @@ if not preconfigured:
thread_suffix = 'mt'
if env['PLATFORM'] == 'FreeBSD':
- thread_suffix = ''
- env.Append(LIBS = 'pthread')
+ thread_suffix = ''
+ env.Append(LIBS = 'pthread')
if env['SHAPE_MEMORY_MAPPED_FILE']:
- env.Append(CPPDEFINES = '-DSHAPE_MEMORY_MAPPED_FILE')
+ env.Append(CPPDEFINES = '-DSHAPE_MEMORY_MAPPED_FILE')
# allow for mac osx /usr/lib/libicucore.dylib compatibility
# requires custom supplied headers since Apple does not include them
@@ -1224,365 +1225,365 @@ if not preconfigured:
# http://www.opensource.apple.com/tarballs/ICU/
# then copy the headers to a location that mapnik will find
if 'core' in env['ICU_LIB_NAME']:
- env.Append(CPPDEFINES = '-DU_HIDE_DRAFT_API')
- env.Append(CPPDEFINES = '-DUDISABLE_RENAMING')
- if os.path.exists(env['ICU_LIB_NAME']):
- #-sICU_LINK=" -L/usr/lib -licucore
- env['ICU_LIB_NAME'] = os.path.basename(env['ICU_LIB_NAME']).replace('.dylib','').replace('lib','')
+ env.Append(CPPDEFINES = '-DU_HIDE_DRAFT_API')
+ env.Append(CPPDEFINES = '-DUDISABLE_RENAMING')
+ if os.path.exists(env['ICU_LIB_NAME']):
+ #-sICU_LINK=" -L/usr/lib -licucore
+ env['ICU_LIB_NAME'] = os.path.basename(env['ICU_LIB_NAME']).replace('.dylib','').replace('lib','')
# Adding the required prerequisite library directories to the include path for
# compiling and the library path for linking, respectively.
for required in ('ICU', 'SQLITE', 'HB'):
- inc_path = env['%s_INCLUDES' % required]
- lib_path = env['%s_LIBS' % required]
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- env.AppendUnique(LIBPATH = fix_path(lib_path))
+ inc_path = env['%s_INCLUDES' % required]
+ lib_path = env['%s_LIBS' % required]
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
REQUIRED_LIBSHEADERS = [
- ['z', 'zlib.h', True,'C'],
- [env['ICU_LIB_NAME'],'unicode/unistr.h',True,'C++'],
- ['harfbuzz', 'harfbuzz/hb.h',True,'C++']
+ ['z', 'zlib.h', True,'C'],
+ [env['ICU_LIB_NAME'],'unicode/unistr.h',True,'C++'],
+ ['harfbuzz', 'harfbuzz/hb.h',True,'C++']
]
if env.get('FREETYPE_LIBS') or env.get('FREETYPE_INCLUDES'):
- REQUIRED_LIBSHEADERS.insert(0,['freetype','ft2build.h',True,'C'])
- if env.get('FREETYPE_INCLUDES'):
- inc_path = env['FREETYPE_INCLUDES']
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- if env.get('FREETYPE_LIBS'):
- lib_path = env['FREETYPE_LIBS']
- env.AppendUnique(LIBPATH = fix_path(lib_path))
+ REQUIRED_LIBSHEADERS.insert(0,['freetype','ft2build.h',True,'C'])
+ if env.get('FREETYPE_INCLUDES'):
+ inc_path = env['FREETYPE_INCLUDES']
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ if env.get('FREETYPE_LIBS'):
+ lib_path = env['FREETYPE_LIBS']
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
elif conf.parse_config('FREETYPE_CONFIG'):
- # check if freetype links to bz2
- if env['RUNTIME_LINK'] == 'static':
- temp_env = env.Clone()
- temp_env['LIBS'] = []
- try:
- # TODO - freetype-config accepts --static as of v2.5.3
- temp_env.ParseConfig('%s --libs' % env['FREETYPE_CONFIG'])
- if 'bz2' in temp_env['LIBS']:
- env['EXTRA_FREETYPE_LIBS'].append('bz2')
- except OSError,e:
- pass
+ # check if freetype links to bz2
+ if env['RUNTIME_LINK'] == 'static':
+ temp_env = env.Clone()
+ temp_env['LIBS'] = []
+ try:
+ # TODO - freetype-config accepts --static as of v2.5.3
+ temp_env.ParseConfig('%s --libs' % env['FREETYPE_CONFIG'])
+ if 'bz2' in temp_env['LIBS']:
+ env['EXTRA_FREETYPE_LIBS'].append('bz2')
+ except OSError,e:
+ pass
# libxml2 should be optional but is currently not
# https://github.com/mapnik/mapnik/issues/913
if env.get('XMLPARSER') and env['XMLPARSER'] == 'libxml2':
- if env.get('XML2_LIBS') or env.get('XML2_INCLUDES'):
- OPTIONAL_LIBSHEADERS.insert(0,['libxml2','libxml/parser.h',True,'C'])
- if env.get('XML2_INCLUDES'):
- inc_path = env['XML2_INCLUDES']
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- if env.get('XML2_LIBS'):
- lib_path = env['XML2_LIBS']
- env.AppendUnique(LIBPATH = fix_path(lib_path))
- elif conf.parse_config('XML2_CONFIG',checks='--cflags'):
- env['HAS_LIBXML2'] = True
- else:
- env['MISSING_DEPS'].append('libxml2')
+ if env.get('XML2_LIBS') or env.get('XML2_INCLUDES'):
+ OPTIONAL_LIBSHEADERS.insert(0,['libxml2','libxml/parser.h',True,'C'])
+ if env.get('XML2_INCLUDES'):
+ inc_path = env['XML2_INCLUDES']
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ if env.get('XML2_LIBS'):
+ lib_path = env['XML2_LIBS']
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
+ elif conf.parse_config('XML2_CONFIG',checks='--cflags'):
+ env['HAS_LIBXML2'] = True
+ else:
+ env['MISSING_DEPS'].append('libxml2')
if not env['HOST']:
- if conf.CheckHasDlfcn():
- env.Append(CPPDEFINES = '-DMAPNIK_HAS_DLCFN')
- else:
- env['SKIPPED_DEPS'].extend(['dlfcn'])
+ if conf.CheckHasDlfcn():
+ env.Append(CPPDEFINES = '-DMAPNIK_HAS_DLCFN')
+ else:
+ env['SKIPPED_DEPS'].extend(['dlfcn'])
OPTIONAL_LIBSHEADERS = []
if env['JPEG']:
- OPTIONAL_LIBSHEADERS.append(['jpeg', ['stdio.h', 'jpeglib.h'], False,'C','-DHAVE_JPEG'])
- inc_path = env['%s_INCLUDES' % 'JPEG']
- lib_path = env['%s_LIBS' % 'JPEG']
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- env.AppendUnique(LIBPATH = fix_path(lib_path))
+ OPTIONAL_LIBSHEADERS.append(['jpeg', ['stdio.h', 'jpeglib.h'], False,'C','-DHAVE_JPEG'])
+ inc_path = env['%s_INCLUDES' % 'JPEG']
+ lib_path = env['%s_LIBS' % 'JPEG']
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
else:
- env['SKIPPED_DEPS'].extend(['jpeg'])
+ env['SKIPPED_DEPS'].extend(['jpeg'])
if env['PROJ']:
- OPTIONAL_LIBSHEADERS.append(['proj', 'proj_api.h', False,'C','-DMAPNIK_USE_PROJ4'])
- inc_path = env['%s_INCLUDES' % 'PROJ']
- lib_path = env['%s_LIBS' % 'PROJ']
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- env.AppendUnique(LIBPATH = fix_path(lib_path))
+ OPTIONAL_LIBSHEADERS.append(['proj', 'proj_api.h', False,'C','-DMAPNIK_USE_PROJ4'])
+ inc_path = env['%s_INCLUDES' % 'PROJ']
+ lib_path = env['%s_LIBS' % 'PROJ']
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
else:
- env['SKIPPED_DEPS'].extend(['proj'])
+ env['SKIPPED_DEPS'].extend(['proj'])
if env['PNG']:
- OPTIONAL_LIBSHEADERS.append(['png', 'png.h', False,'C','-DHAVE_PNG'])
- inc_path = env['%s_INCLUDES' % 'PNG']
- lib_path = env['%s_LIBS' % 'PNG']
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- env.AppendUnique(LIBPATH = fix_path(lib_path))
+ OPTIONAL_LIBSHEADERS.append(['png', 'png.h', False,'C','-DHAVE_PNG'])
+ inc_path = env['%s_INCLUDES' % 'PNG']
+ lib_path = env['%s_LIBS' % 'PNG']
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
else:
- env['SKIPPED_DEPS'].extend(['png'])
+ env['SKIPPED_DEPS'].extend(['png'])
if env['WEBP']:
- OPTIONAL_LIBSHEADERS.append(['webp', 'webp/decode.h', False,'C','-DHAVE_WEBP'])
- inc_path = env['%s_INCLUDES' % 'WEBP']
- lib_path = env['%s_LIBS' % 'WEBP']
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- env.AppendUnique(LIBPATH = fix_path(lib_path))
+ OPTIONAL_LIBSHEADERS.append(['webp', 'webp/decode.h', False,'C','-DHAVE_WEBP'])
+ inc_path = env['%s_INCLUDES' % 'WEBP']
+ lib_path = env['%s_LIBS' % 'WEBP']
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
else:
- env['SKIPPED_DEPS'].extend(['webp'])
+ env['SKIPPED_DEPS'].extend(['webp'])
if env['TIFF']:
- OPTIONAL_LIBSHEADERS.append(['tiff', 'tiff.h', False,'C','-DHAVE_TIFF'])
- inc_path = env['%s_INCLUDES' % 'TIFF']
- lib_path = env['%s_LIBS' % 'TIFF']
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- env.AppendUnique(LIBPATH = fix_path(lib_path))
+ OPTIONAL_LIBSHEADERS.append(['tiff', 'tiff.h', False,'C','-DHAVE_TIFF'])
+ inc_path = env['%s_INCLUDES' % 'TIFF']
+ lib_path = env['%s_LIBS' % 'TIFF']
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
else:
- env['SKIPPED_DEPS'].extend(['tiff'])
+ env['SKIPPED_DEPS'].extend(['tiff'])
# if requested, sort LIBPATH and CPPPATH before running CheckLibWithHeader tests
if env['PRIORITIZE_LINKING']:
- conf.prioritize_paths(silent=True)
+ conf.prioritize_paths(silent=True)
# test for C++11 support, which is required
if not env['HOST'] and not conf.supports_cxx11():
- color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler to at least g++ 4.7 (ideally 4.8)")
- Exit(1)
+ color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler to at least g++ 4.7 (ideally 4.8)")
+ Exit(1)
if not env['HOST']:
- for libname, headers, required, lang in REQUIRED_LIBSHEADERS:
- if not conf.CheckLibWithHeader(libname, headers, lang):
- if required:
- color_print(1, 'Could not find required header or shared library for %s' % libname)
- env['MISSING_DEPS'].append(libname)
- else:
- color_print(4, 'Could not find optional header or shared library for %s' % libname)
- env['SKIPPED_DEPS'].append(libname)
- else:
- if libname == env['ICU_LIB_NAME']:
- if env['ICU_LIB_NAME'] not in env['MISSING_DEPS']:
- if not conf.icu_at_least_four_two():
- # expression_string.cpp and map.cpp use fromUTF* function only available in >= ICU 4.2
- env['MISSING_DEPS'].append(env['ICU_LIB_NAME'])
- elif libname == 'harfbuzz':
- if not conf.harfbuzz_version():
- env['SKIPPED_DEPS'].append('harfbuzz-min-version')
+ for libname, headers, required, lang in REQUIRED_LIBSHEADERS:
+ if not conf.CheckLibWithHeader(libname, headers, lang):
+ if required:
+ color_print(1, 'Could not find required header or shared library for %s' % libname)
+ env['MISSING_DEPS'].append(libname)
+ else:
+ color_print(4, 'Could not find optional header or shared library for %s' % libname)
+ env['SKIPPED_DEPS'].append(libname)
+ else:
+ if libname == env['ICU_LIB_NAME']:
+ if env['ICU_LIB_NAME'] not in env['MISSING_DEPS']:
+ if not conf.icu_at_least_four_two():
+ # expression_string.cpp and map.cpp use fromUTF* function only available in >= ICU 4.2
+ env['MISSING_DEPS'].append(env['ICU_LIB_NAME'])
+ elif libname == 'harfbuzz':
+ if not conf.harfbuzz_version():
+ env['SKIPPED_DEPS'].append('harfbuzz-min-version')
if env['BIGINT']:
- env.Append(CPPDEFINES = '-DBIGINT')
+ env.Append(CPPDEFINES = '-DBIGINT')
if env['THREADING'] == 'multi':
- thread_flag = thread_suffix
+ thread_flag = thread_suffix
else:
- thread_flag = ''
+ thread_flag = ''
conf.FindBoost(BOOST_SEARCH_PREFIXES,thread_flag)
has_boost_devel = True
if not env['HOST']:
- if not conf.CheckHeader(header='boost/version.hpp',language='C++'):
- env['MISSING_DEPS'].append('boost development headers')
- has_boost_devel = False
+ if not conf.CheckHeader(header='boost/version.hpp',language='C++'):
+ env['MISSING_DEPS'].append('boost development headers')
+ has_boost_devel = False
if has_boost_devel:
- if not env['HOST']:
- env['BOOST_LIB_VERSION_FROM_HEADER'] = conf.GetBoostLibVersion()
-
- # The other required boost headers.
- BOOST_LIBSHEADERS = [
- ['system', 'boost/system/system_error.hpp', True],
- ['filesystem', 'boost/filesystem/operations.hpp', True],
- ['regex', 'boost/regex.hpp', True],
- ['program_options', 'boost/program_options.hpp', False]
- ]
-
- if env['THREADING'] == 'multi':
- BOOST_LIBSHEADERS.append(['thread', 'boost/thread/mutex.hpp', True])
- # on solaris the configure checks for boost_thread
- # require the -pthreads flag to be able to check for
- # threading support, so we add as a global library instead
- # of attaching to cxxflags after configure
- if env['PLATFORM'] == 'SunOS':
- env.Append(CXXFLAGS = '-pthreads')
-
- # if requested, sort LIBPATH and CPPPATH before running CheckLibWithHeader tests
- if env['PRIORITIZE_LINKING']:
- conf.prioritize_paths(silent=True)
-
- if not env['HOST']:
- # if the user is not setting custom boost configuration
- # enforce boost version greater than or equal to BOOST_MIN_VERSION
- if not conf.CheckBoost(BOOST_MIN_VERSION):
- color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') )
- color_print(1,'Boost version %s or greater is required' % BOOST_MIN_VERSION)
- if not env['BOOST_VERSION']:
- env['MISSING_DEPS'].append('boost version >= %s' % BOOST_MIN_VERSION)
- else:
- color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') )
-
- if not env['HOST']:
- for count, libinfo in enumerate(BOOST_LIBSHEADERS):
- if not conf.CheckLibWithHeader('boost_%s%s' % (libinfo[0],env['BOOST_APPEND']), libinfo[1], 'C++'):
- if libinfo[2]:
- color_print(1,'Could not find required header or shared library for boost %s' % libinfo[0])
- env['MISSING_DEPS'].append('boost ' + libinfo[0])
- else:
- color_print(4,'Could not find optional header or shared library for boost %s' % libinfo[0])
- env['SKIPPED_DEPS'].append('boost ' + libinfo[0])
-
- # Boost versions before 1.57 are broken when the system package and
- # Mapnik are compiled against different standards. On Ubuntu 14.04
- # using boost 1.54, it breaks scoped enums. It's a bit of a hack to
- # just turn it off like this, but seems the only available work-
- # around. See https://svn.boost.org/trac/boost/ticket/6779 for more
- # details.
- boost_version = [int(x) for x in env.get('BOOST_LIB_VERSION_FROM_HEADER').split('_')]
- if not conf.CheckBoostScopedEnum():
- if boost_version < [1, 51]:
- env.Append(CXXFLAGS = '-DBOOST_NO_SCOPED_ENUMS')
- elif boost_version < [1, 57]:
- env.Append(CXXFLAGS = '-DBOOST_NO_CXX11_SCOPED_ENUMS')
+ if not env['HOST']:
+ env['BOOST_LIB_VERSION_FROM_HEADER'] = conf.GetBoostLibVersion()
+
+ # The other required boost headers.
+ BOOST_LIBSHEADERS = [
+ ['system', 'boost/system/system_error.hpp', True],
+ ['filesystem', 'boost/filesystem/operations.hpp', True],
+ ['regex', 'boost/regex.hpp', True],
+ ['program_options', 'boost/program_options.hpp', False]
+ ]
+
+ if env['THREADING'] == 'multi':
+ BOOST_LIBSHEADERS.append(['thread', 'boost/thread/mutex.hpp', True])
+ # on solaris the configure checks for boost_thread
+ # require the -pthreads flag to be able to check for
+ # threading support, so we add as a global library instead
+ # of attaching to cxxflags after configure
+ if env['PLATFORM'] == 'SunOS':
+ env.Append(CXXFLAGS = '-pthreads')
+
+ # if requested, sort LIBPATH and CPPPATH before running CheckLibWithHeader tests
+ if env['PRIORITIZE_LINKING']:
+ conf.prioritize_paths(silent=True)
+
+ if not env['HOST']:
+ # if the user is not setting custom boost configuration
+ # enforce boost version greater than or equal to BOOST_MIN_VERSION
+ if not conf.CheckBoost(BOOST_MIN_VERSION):
+ color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') )
+ color_print(1,'Boost version %s or greater is required' % BOOST_MIN_VERSION)
+ if not env['BOOST_VERSION']:
+ env['MISSING_DEPS'].append('boost version >= %s' % BOOST_MIN_VERSION)
+ else:
+ color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') )
+
+ if not env['HOST']:
+ for count, libinfo in enumerate(BOOST_LIBSHEADERS):
+ if not conf.CheckLibWithHeader('boost_%s%s' % (libinfo[0],env['BOOST_APPEND']), libinfo[1], 'C++'):
+ if libinfo[2]:
+ color_print(1,'Could not find required header or shared library for boost %s' % libinfo[0])
+ env['MISSING_DEPS'].append('boost ' + libinfo[0])
+ else:
+ color_print(4,'Could not find optional header or shared library for boost %s' % libinfo[0])
+ env['SKIPPED_DEPS'].append('boost ' + libinfo[0])
+
+ # Boost versions before 1.57 are broken when the system package and
+ # Mapnik are compiled against different standards. On Ubuntu 14.04
+ # using boost 1.54, it breaks scoped enums. It's a bit of a hack to
+ # just turn it off like this, but seems the only available work-
+ # around. See https://svn.boost.org/trac/boost/ticket/6779 for more
+ # details.
+ boost_version = [int(x) for x in env.get('BOOST_LIB_VERSION_FROM_HEADER').split('_')]
+ if not conf.CheckBoostScopedEnum():
+ if boost_version < [1, 51]:
+ env.Append(CXXFLAGS = '-DBOOST_NO_SCOPED_ENUMS')
+ elif boost_version < [1, 57]:
+ env.Append(CXXFLAGS = '-DBOOST_NO_CXX11_SCOPED_ENUMS')
if not env['HOST'] and env['ICU_LIB_NAME'] not in env['MISSING_DEPS']:
- # http://lists.boost.org/Archives/boost/2009/03/150076.php
- # we need libicui18n if using static boost libraries, so it is
- # important to try this check with the library linked
- if conf.boost_regex_has_icu():
- # TODO - should avoid having this be globally defined...
- env.Append(CPPDEFINES = '-DBOOST_REGEX_HAS_ICU')
- else:
- env['SKIPPED_DEPS'].append('boost_regex_icu')
-
- for libname, headers, required, lang, define in OPTIONAL_LIBSHEADERS:
- if not env['HOST']:
- if not conf.CheckLibWithHeader(libname, headers, lang):
- if required:
- color_print(1, 'Could not find required header or shared library for %s' % libname)
- env['MISSING_DEPS'].append(libname)
- else:
- color_print(4, 'Could not find optional header or shared library for %s' % libname)
- env['SKIPPED_DEPS'].append(libname)
- else:
- env.Append(CPPDEFINES = define)
- else:
- env.Append(CPPDEFINES = define)
+ # http://lists.boost.org/Archives/boost/2009/03/150076.php
+ # we need libicui18n if using static boost libraries, so it is
+ # important to try this check with the library linked
+ if conf.boost_regex_has_icu():
+ # TODO - should avoid having this be globally defined...
+ env.Append(CPPDEFINES = '-DBOOST_REGEX_HAS_ICU')
+ else:
+ env['SKIPPED_DEPS'].append('boost_regex_icu')
+
+ for libname, headers, required, lang, define in OPTIONAL_LIBSHEADERS:
+ if not env['HOST']:
+ if not conf.CheckLibWithHeader(libname, headers, lang):
+ if required:
+ color_print(1, 'Could not find required header or shared library for %s' % libname)
+ env['MISSING_DEPS'].append(libname)
+ else:
+ color_print(4, 'Could not find optional header or shared library for %s' % libname)
+ env['SKIPPED_DEPS'].append(libname)
+ else:
+ env.Append(CPPDEFINES = define)
+ else:
+ env.Append(CPPDEFINES = define)
env['REQUESTED_PLUGINS'] = [ driver.strip() for driver in Split(env['INPUT_PLUGINS'])]
SQLITE_HAS_RTREE = None
if env['HOST']:
- SQLITE_HAS_RTREE = True
+ SQLITE_HAS_RTREE = True
CHECK_PKG_CONFIG = conf.CheckPKGConfig('0.15.0')
if len(env['REQUESTED_PLUGINS']):
- if env['HOST']:
- for plugin in env['REQUESTED_PLUGINS']:
- details = env['PLUGINS'][plugin]
- if details['lib']:
- env.AppendUnique(LIBS=details['lib'])
- else:
- color_print(4,'Checking for requested plugins dependencies...')
- for plugin in env['REQUESTED_PLUGINS']:
- details = env['PLUGINS'][plugin]
- if plugin == 'gdal':
- if conf.parse_config('GDAL_CONFIG',checks='--libs'):
- conf.parse_config('GDAL_CONFIG',checks='--cflags')
- libname = conf.get_pkg_lib('GDAL_CONFIG','gdal')
- if libname:
- if not conf.CheckLibWithHeader(libname, details['inc'], details['lang']):
- env['SKIPPED_DEPS'].append('gdal')
- if libname in env['LIBS']:
- env['LIBS'].remove(libname)
- else:
- details['lib'] = libname
- elif plugin == 'postgis' or plugin == 'pgraster':
- if env.get('PG_LIBS') or env.get('PG_INCLUDES'):
- libname = details['lib']
- if env.get('PG_INCLUDES'):
- inc_path = env['PG_INCLUDES']
- env.AppendUnique(CPPPATH = fix_path(inc_path))
- if env.get('PG_LIBS'):
- lib_path = env['PG_LIBS']
- env.AppendUnique(LIBPATH = fix_path(lib_path))
- if not conf.CheckLibWithHeader(libname, details['inc'], details['lang']):
- env['SKIPPED_DEPS'].append(libname)
- if libname in env['LIBS']:
- env['LIBS'].remove(libname)
- else:
- details['lib'] = libname
- else:
- conf.parse_pg_config('PG_CONFIG')
- elif plugin == 'ogr':
- if conf.ogr_enabled():
- if conf.parse_config('GDAL_CONFIG',checks='--libs'):
- conf.parse_config('GDAL_CONFIG',checks='--cflags')
- libname = conf.get_pkg_lib('GDAL_CONFIG','ogr')
- if libname:
- if not conf.CheckLibWithHeader(libname, details['inc'], details['lang']):
- if 'gdal' not in env['SKIPPED_DEPS']:
- env['SKIPPED_DEPS'].append('gdal')
- if libname in env['LIBS']:
- env['LIBS'].remove(libname)
- else:
- details['lib'] = libname
- elif details['path'] and details['lib'] and details['inc']:
- backup = env.Clone().Dictionary()
- # Note, the 'delete_existing' keyword makes sure that these paths are prepended
- # to the beginning of the path list even if they already exist
- incpath = env['%s_INCLUDES' % details['path']]
- libpath = env['%s_LIBS' % details['path']]
- env.PrependUnique(CPPPATH = fix_path(incpath),delete_existing=True)
- env.PrependUnique(LIBPATH = fix_path(libpath),delete_existing=True)
- if not conf.CheckLibWithHeader(details['lib'], details['inc'], details['lang']):
- env.Replace(**backup)
- env['SKIPPED_DEPS'].append(details['lib'])
- if plugin == 'sqlite':
- sqlite_backup = env.Clone().Dictionary()
- # if statically linking, on linux we likely
- # need to link sqlite to pthreads and dl
- if env['RUNTIME_LINK'] == 'static' and not env['PLATFORM'] == 'Darwin':
- if CHECK_PKG_CONFIG and conf.CheckPKG('sqlite3'):
- sqlite_env = env.Clone()
- try:
- sqlite_env.ParseConfig('pkg-config --static --libs sqlite3')
- for lib in sqlite_env['LIBS']:
- if not lib in env['LIBS']:
- env["SQLITE_LINKFLAGS"].append(lib)
- env.Append(LIBS=lib)
- except OSError,e:
- for lib in ["sqlite3","dl","pthread"]:
- if not lib in env['LIBS']:
- env["SQLITE_LINKFLAGS"].append("lib")
- env.Append(LIBS=lib)
- else:
- for lib in ["sqlite3","dl","pthread"]:
- if not lib in env['LIBS']:
- env["SQLITE_LINKFLAGS"].append("lib")
- env.Append(LIBS=lib)
- SQLITE_HAS_RTREE = conf.sqlite_has_rtree()
- if not SQLITE_HAS_RTREE:
- env.Replace(**sqlite_backup)
- if details['lib'] in env['LIBS']:
- env['LIBS'].remove(details['lib'])
- env['SKIPPED_DEPS'].append('sqlite_rtree')
- else:
- env.Replace(**sqlite_backup)
- elif details['lib'] and details['inc']:
- if not conf.CheckLibWithHeader(details['lib'], details['inc'], details['lang']):
- env['SKIPPED_DEPS'].append(details['lib'])
-
- # re-append the local paths for mapnik sources to the beginning of the list
- # to make sure they come before any plugins that were 'prepended'
- env.PrependUnique(CPPPATH = '#include', delete_existing=True)
- env.PrependUnique(LIBPATH = '#src', delete_existing=True)
+ if env['HOST']:
+ for plugin in env['REQUESTED_PLUGINS']:
+ details = env['PLUGINS'][plugin]
+ if details['lib']:
+ env.AppendUnique(LIBS=details['lib'])
+ else:
+ color_print(4,'Checking for requested plugins dependencies...')
+ for plugin in env['REQUESTED_PLUGINS']:
+ details = env['PLUGINS'][plugin]
+ if plugin == 'gdal':
+ if conf.parse_config('GDAL_CONFIG',checks='--libs'):
+ conf.parse_config('GDAL_CONFIG',checks='--cflags')
+ libname = conf.get_pkg_lib('GDAL_CONFIG','gdal')
+ if libname:
+ if not conf.CheckLibWithHeader(libname, details['inc'], details['lang']):
+ env['SKIPPED_DEPS'].append('gdal')
+ if libname in env['LIBS']:
+ env['LIBS'].remove(libname)
+ else:
+ details['lib'] = libname
+ elif plugin == 'postgis' or plugin == 'pgraster':
+ if env.get('PG_LIBS') or env.get('PG_INCLUDES'):
+ libname = details['lib']
+ if env.get('PG_INCLUDES'):
+ inc_path = env['PG_INCLUDES']
+ env.AppendUnique(CPPPATH = fix_path(inc_path))
+ if env.get('PG_LIBS'):
+ lib_path = env['PG_LIBS']
+ env.AppendUnique(LIBPATH = fix_path(lib_path))
+ if not conf.CheckLibWithHeader(libname, details['inc'], details['lang']):
+ env['SKIPPED_DEPS'].append(libname)
+ if libname in env['LIBS']:
+ env['LIBS'].remove(libname)
+ else:
+ details['lib'] = libname
+ else:
+ conf.parse_pg_config('PG_CONFIG')
+ elif plugin == 'ogr':
+ if conf.ogr_enabled():
+ if conf.parse_config('GDAL_CONFIG',checks='--libs'):
+ conf.parse_config('GDAL_CONFIG',checks='--cflags')
+ libname = conf.get_pkg_lib('GDAL_CONFIG','ogr')
+ if libname:
+ if not conf.CheckLibWithHeader(libname, details['inc'], details['lang']):
+ if 'gdal' not in env['SKIPPED_DEPS']:
+ env['SKIPPED_DEPS'].append('gdal')
+ if libname in env['LIBS']:
+ env['LIBS'].remove(libname)
+ else:
+ details['lib'] = libname
+ elif details['path'] and details['lib'] and details['inc']:
+ backup = env.Clone().Dictionary()
+ # Note, the 'delete_existing' keyword makes sure that these paths are prepended
+ # to the beginning of the path list even if they already exist
+ incpath = env['%s_INCLUDES' % details['path']]
+ libpath = env['%s_LIBS' % details['path']]
+ env.PrependUnique(CPPPATH = fix_path(incpath),delete_existing=True)
+ env.PrependUnique(LIBPATH = fix_path(libpath),delete_existing=True)
+ if not conf.CheckLibWithHeader(details['lib'], details['inc'], details['lang']):
+ env.Replace(**backup)
+ env['SKIPPED_DEPS'].append(details['lib'])
+ if plugin == 'sqlite':
+ sqlite_backup = env.Clone().Dictionary()
+ # if statically linking, on linux we likely
+ # need to link sqlite to pthreads and dl
+ if env['RUNTIME_LINK'] == 'static' and not env['PLATFORM'] == 'Darwin':
+ if CHECK_PKG_CONFIG and conf.CheckPKG('sqlite3'):
+ sqlite_env = env.Clone()
+ try:
+ sqlite_env.ParseConfig('pkg-config --static --libs sqlite3')
+ for lib in sqlite_env['LIBS']:
+ if not lib in env['LIBS']:
+ env["SQLITE_LINKFLAGS"].append(lib)
+ env.Append(LIBS=lib)
+ except OSError,e:
+ for lib in ["sqlite3","dl","pthread"]:
+ if not lib in env['LIBS']:
+ env["SQLITE_LINKFLAGS"].append("lib")
+ env.Append(LIBS=lib)
+ else:
+ for lib in ["sqlite3","dl","pthread"]:
+ if not lib in env['LIBS']:
+ env["SQLITE_LINKFLAGS"].append("lib")
+ env.Append(LIBS=lib)
+ SQLITE_HAS_RTREE = conf.sqlite_has_rtree()
+ if not SQLITE_HAS_RTREE:
+ env.Replace(**sqlite_backup)
+ if details['lib'] in env['LIBS']:
+ env['LIBS'].remove(details['lib'])
+ env['SKIPPED_DEPS'].append('sqlite_rtree')
+ else:
+ env.Replace(**sqlite_backup)
+ elif details['lib'] and details['inc']:
+ if not conf.CheckLibWithHeader(details['lib'], details['inc'], details['lang']):
+ env['SKIPPED_DEPS'].append(details['lib'])
+
+ # re-append the local paths for mapnik sources to the beginning of the list
+ # to make sure they come before any plugins that were 'prepended'
+ env.PrependUnique(CPPPATH = '#include', delete_existing=True)
+ env.PrependUnique(LIBPATH = '#src', delete_existing=True)
if not env['HOST']:
- if env['PGSQL2SQLITE']:
- if 'sqlite3' not in env['LIBS']:
- env.AppendUnique(LIBS='sqlite3')
- env.AppendUnique(CPPPATH = fix_path(env['SQLITE_INCLUDES']))
- env.AppendUnique(LIBPATH = fix_path(env['SQLITE_LIBS']))
- if 'pq' not in env['LIBS']:
- if not conf.parse_pg_config('PG_CONFIG'):
- env['PGSQL2SQLITE'] = False
- if not SQLITE_HAS_RTREE:
- env['SKIPPED_DEPS'].append('pgsql2sqlite_rtree')
- env['PGSQL2SQLITE'] = False
+ if env['PGSQL2SQLITE']:
+ if 'sqlite3' not in env['LIBS']:
+ env.AppendUnique(LIBS='sqlite3')
+ env.AppendUnique(CPPPATH = fix_path(env['SQLITE_INCLUDES']))
+ env.AppendUnique(LIBPATH = fix_path(env['SQLITE_LIBS']))
+ if 'pq' not in env['LIBS']:
+ if not conf.parse_pg_config('PG_CONFIG'):
+ env['PGSQL2SQLITE'] = False
+ if not SQLITE_HAS_RTREE:
+ env['SKIPPED_DEPS'].append('pgsql2sqlite_rtree')
+ env['PGSQL2SQLITE'] = False
# we rely on an internal, patched copy of agg with critical fixes
# prepend to make sure we link locally
@@ -1592,236 +1593,236 @@ if not preconfigured:
env.Prepend(CPPPATH = '#deps')
if env['CAIRO']:
- if env['CAIRO_LIBS'] or env['CAIRO_INCLUDES']:
- c_inc = env['CAIRO_INCLUDES']
- if env['CAIRO_LIBS']:
- env["CAIRO_LIBPATHS"].append(fix_path(env['CAIRO_LIBS']))
- if not env['CAIRO_INCLUDES']:
- c_inc = env['CAIRO_LIBS'].replace('lib','',1)
- if c_inc:
- c_inc = os.path.normpath(fix_path(env['CAIRO_INCLUDES']))
- if c_inc.endswith('include'):
- c_inc = os.path.dirname(c_inc)
- env["CAIRO_CPPPATHS"].extend(
- [
- os.path.join(c_inc,'include/cairo'),
- os.path.join(c_inc,'include/pixman-1'),
- #os.path.join(c_inc,'include/freetype2'),
- #os.path.join(c_inc,'include/libpng'),
- ]
- )
- env["CAIRO_ALL_LIBS"] = ['cairo']
- if env['RUNTIME_LINK'] == 'static':
- env["CAIRO_ALL_LIBS"].extend(
- ['pixman-1','expat']
- )
- # todo - run actual checkLib?
- env['HAS_CAIRO'] = True
- else:
- if not CHECK_PKG_CONFIG:
- env['HAS_CAIRO'] = False
- env['SKIPPED_DEPS'].append('pkg-config')
- env['SKIPPED_DEPS'].append('cairo')
- elif not conf.CheckPKG('cairo'):
- env['HAS_CAIRO'] = False
- env['SKIPPED_DEPS'].append('cairo')
- else:
- print 'Checking for cairo lib and include paths... ',
- cmd = 'pkg-config --libs --cflags cairo'
- if env['RUNTIME_LINK'] == 'static':
- cmd += ' --static'
- cairo_env = env.Clone()
- try:
- cairo_env.ParseConfig(cmd)
- for lib in cairo_env['LIBS']:
- if not lib in env['LIBS']:
- env["CAIRO_ALL_LIBS"].append(lib)
- for lpath in cairo_env['LIBPATH']:
- if not lpath in env['LIBPATH']:
- env["CAIRO_LIBPATHS"].append(lpath)
- for inc in cairo_env['CPPPATH']:
- if not inc in env['CPPPATH']:
- env["CAIRO_CPPPATHS"].append(inc)
- env['HAS_CAIRO'] = True
- print 'yes'
- except OSError,e:
- color_print(1,'no')
- env['SKIPPED_DEPS'].append('cairo')
- color_print(1,'pkg-config reported: %s' % e)
+ if env['CAIRO_LIBS'] or env['CAIRO_INCLUDES']:
+ c_inc = env['CAIRO_INCLUDES']
+ if env['CAIRO_LIBS']:
+ env["CAIRO_LIBPATHS"].append(fix_path(env['CAIRO_LIBS']))
+ if not env['CAIRO_INCLUDES']:
+ c_inc = env['CAIRO_LIBS'].replace('lib','',1)
+ if c_inc:
+ c_inc = os.path.normpath(fix_path(env['CAIRO_INCLUDES']))
+ if c_inc.endswith('include'):
+ c_inc = os.path.dirname(c_inc)
+ env["CAIRO_CPPPATHS"].extend(
+ [
+ os.path.join(c_inc,'include/cairo'),
+ os.path.join(c_inc,'include/pixman-1'),
+ #os.path.join(c_inc,'include/freetype2'),
+ #os.path.join(c_inc,'include/libpng'),
+ ]
+ )
+ env["CAIRO_ALL_LIBS"] = ['cairo']
+ if env['RUNTIME_LINK'] == 'static':
+ env["CAIRO_ALL_LIBS"].extend(
+ ['pixman-1','expat']
+ )
+ # todo - run actual checkLib?
+ env['HAS_CAIRO'] = True
+ else:
+ if not CHECK_PKG_CONFIG:
+ env['HAS_CAIRO'] = False
+ env['SKIPPED_DEPS'].append('pkg-config')
+ env['SKIPPED_DEPS'].append('cairo')
+ elif not conf.CheckPKG('cairo'):
+ env['HAS_CAIRO'] = False
+ env['SKIPPED_DEPS'].append('cairo')
+ else:
+ print 'Checking for cairo lib and include paths... ',
+ cmd = 'pkg-config --libs --cflags cairo'
+ if env['RUNTIME_LINK'] == 'static':
+ cmd += ' --static'
+ cairo_env = env.Clone()
+ try:
+ cairo_env.ParseConfig(cmd)
+ for lib in cairo_env['LIBS']:
+ if not lib in env['LIBS']:
+ env["CAIRO_ALL_LIBS"].append(lib)
+ for lpath in cairo_env['LIBPATH']:
+ if not lpath in env['LIBPATH']:
+ env["CAIRO_LIBPATHS"].append(lpath)
+ for inc in cairo_env['CPPPATH']:
+ if not inc in env['CPPPATH']:
+ env["CAIRO_CPPPATHS"].append(inc)
+ env['HAS_CAIRO'] = True
+ print 'yes'
+ except OSError,e:
+ color_print(1,'no')
+ env['SKIPPED_DEPS'].append('cairo')
+ color_print(1,'pkg-config reported: %s' % e)
else:
- color_print(4,'Not building with cairo support, pass CAIRO=True to enable')
+ color_print(4,'Not building with cairo support, pass CAIRO=True to enable')
if not env['HOST'] and env['HAS_CAIRO']:
- if not conf.CheckCairoHasFreetype():
- env['SKIPPED_DEPS'].append('cairo')
- env['HAS_CAIRO'] = False
+ if not conf.CheckCairoHasFreetype():
+ env['SKIPPED_DEPS'].append('cairo')
+ env['HAS_CAIRO'] = False
#### End Config Stage for Required Dependencies ####
if env['MISSING_DEPS']:
- # if required dependencies are missing, print warnings and then let SCons finish without building or saving local config
- color_print(1,'\nExiting... the following required dependencies were not found:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['MISSING_DEPS']]))
- color_print(1,"\nSee '%s' for details on possible problems." % (fix_path(SCONS_LOCAL_LOG)))
- if env['SKIPPED_DEPS']:
- color_print(4,'\nAlso, these OPTIONAL dependencies were not found:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['SKIPPED_DEPS']]))
- color_print(4,"\nSet custom paths to these libraries and header files on the command-line or in a file called '%s'" % SCONS_LOCAL_CONFIG)
- color_print(4," ie. $ python scons/scons.py BOOST_INCLUDES=/usr/local/include BOOST_LIBS=/usr/local/lib")
- color_print(4, "\nOnce all required dependencies are found a local '%s' will be saved and then install:" % SCONS_LOCAL_CONFIG)
- color_print(4," $ sudo python scons/scons.py install")
- color_print(4,"\nTo view available path variables:\n $ python scons/scons.py --help or -h")
- color_print(4,'\nTo view overall SCons help options:\n $ python scons/scons.py --help-options or -H\n')
- color_print(4,'More info: https://github.com/mapnik/mapnik/wiki/Mapnik-Installation')
- if not HELP_REQUESTED:
- Exit(1)
+ # if required dependencies are missing, print warnings and then let SCons finish without building or saving local config
+ color_print(1,'\nExiting... the following required dependencies were not found:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['MISSING_DEPS']]))
+ color_print(1,"\nSee '%s' for details on possible problems." % (fix_path(SCONS_LOCAL_LOG)))
+ if env['SKIPPED_DEPS']:
+ color_print(4,'\nAlso, these OPTIONAL dependencies were not found:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['SKIPPED_DEPS']]))
+ color_print(4,"\nSet custom paths to these libraries and header files on the command-line or in a file called '%s'" % SCONS_LOCAL_CONFIG)
+ color_print(4," ie. $ python scons/scons.py BOOST_INCLUDES=/usr/local/include BOOST_LIBS=/usr/local/lib")
+ color_print(4, "\nOnce all required dependencies are found a local '%s' will be saved and then install:" % SCONS_LOCAL_CONFIG)
+ color_print(4," $ sudo python scons/scons.py install")
+ color_print(4,"\nTo view available path variables:\n $ python scons/scons.py --help or -h")
+ color_print(4,'\nTo view overall SCons help options:\n $ python scons/scons.py --help-options or -H\n')
+ color_print(4,'More info: https://github.com/mapnik/mapnik/wiki/Mapnik-Installation')
+ if not HELP_REQUESTED:
+ Exit(1)
else:
- # Save the custom variables in a SCONS_LOCAL_CONFIG
- # that will be reloaded to allow for `install` without re-specifying custom variables
- color_print(4,"\nAll Required dependencies found!\n")
- if env['USE_CONFIG']:
- if os.path.exists(SCONS_LOCAL_CONFIG):
- action = 'Overwriting and re-saving'
- os.unlink(SCONS_LOCAL_CONFIG)
- else:
- action = 'Saving new'
- color_print(4,"%s file '%s'..." % (action,SCONS_LOCAL_CONFIG))
- color_print(4,"Will hold custom path variables from commandline and python config file(s)...")
- opts.Save(SCONS_LOCAL_CONFIG,env)
- else:
- color_print(4,"Did not use user config file, no custom path variables will be saved...")
-
- if env['SKIPPED_DEPS']:
- color_print(4,'\nNote: will build without these OPTIONAL dependencies:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['SKIPPED_DEPS']]))
- print
-
- # fetch the mapnik version header in order to set the
- # ABI version used to build libmapnik.so on linux in src/build.py
- abi = GetMapnikLibVersion()
- abi_no_pre = abi.replace('-pre','').split('.')
- env['ABI_VERSION'] = abi_no_pre
- env['MAPNIK_VERSION_STRING'] = abi
- env['MAPNIK_VERSION'] = str(int(abi_no_pre[0])*100000+int(abi_no_pre[1])*100+int(abi_no_pre[2]))
-
- # Common DEFINES.
- env.Append(CPPDEFINES = '-D%s' % env['PLATFORM'].upper())
- if env['THREADING'] == 'multi':
- env.Append(CPPDEFINES = '-DMAPNIK_THREADSAFE')
-
- if env['NO_ATEXIT']:
- env.Append(CPPDEFINES = '-DMAPNIK_NO_ATEXIT')
-
- # Mac OSX (Darwin) special settings
- if env['PLATFORM'] == 'Darwin':
- pthread = ''
- else:
- pthread = '-pthread'
-
- # Common debugging flags.
- # http://lists.fedoraproject.org/pipermail/devel/2010-November/144952.html
- debug_flags = ['-g', '-fno-omit-frame-pointer']
- debug_defines = ['-DDEBUG', '-DMAPNIK_DEBUG']
- ndebug_defines = ['-DNDEBUG']
-
- # faster compile
- # http://www.boost.org/doc/libs/1_47_0/libs/spirit/doc/html/spirit/what_s_new/spirit_2_5.html#spirit.what_s_new.spirit_2_5.breaking_changes
- env.Append(CPPDEFINES = '-DBOOST_SPIRIT_NO_PREDEFINED_TERMINALS=1')
- env.Append(CPPDEFINES = '-DBOOST_PHOENIX_NO_PREDEFINED_TERMINALS=1')
- # c++11 support / https://github.com/mapnik/mapnik/issues/1683
- # - upgrade to PHOENIX_V3 since that is needed for c++11 compile
- env.Append(CPPDEFINES = '-DBOOST_SPIRIT_USE_PHOENIX_V3=1')
-
- # Enable logging in debug mode (always) and release mode (when specified)
- if env['DEFAULT_LOG_SEVERITY']:
- if env['DEFAULT_LOG_SEVERITY'] not in severities:
- severities_list = ', '.join(["'%s'" % s for s in severities])
- color_print(1,"Cannot set default logger severity to '%s', available options are %s." % (env['DEFAULT_LOG_SEVERITY'], severities_list))
- Exit(1)
- else:
- log_severity = severities.index(env['DEFAULT_LOG_SEVERITY'])
- else:
- severities_list = ', '.join(["'%s'" % s for s in severities])
- color_print(1,"No logger severity specified, available options are %s." % severities_list)
- Exit(1)
-
- log_enabled = ['-DMAPNIK_LOG', '-DMAPNIK_DEFAULT_LOG_SEVERITY=%d' % log_severity]
-
- if env['DEBUG']:
- debug_defines += log_enabled
- else:
- if env['ENABLE_LOG']:
- ndebug_defines += log_enabled
-
- # Enable statistics reporting
- if env['ENABLE_STATS']:
- debug_defines.append('-DMAPNIK_STATS')
- ndebug_defines.append('-DMAPNIK_STATS')
-
- # Add rdynamic to allow using statics between application and plugins
- # http://stackoverflow.com/questions/8623657/multiple-instances-of-singleton-across-shared-libraries-on-linux
- if env['PLATFORM'] != 'Darwin' and env['CXX'] == 'g++':
- env.MergeFlags('-rdynamic')
-
- if env['DEBUG']:
- env.Append(CXXFLAGS = debug_flags)
- env.Append(CPPDEFINES = debug_defines)
- else:
- env.Append(CPPDEFINES = ndebug_defines)
-
- # Common flags for g++/clang++ CXX compiler.
- # TODO: clean up code more to make -Wextra -Wsign-compare -Wsign-conversion -Wconversion viable
- common_cxx_flags = '-Wall %s %s -ftemplate-depth-300 -Wsign-compare -Wshadow ' % (env['WARNING_CXXFLAGS'], pthread)
-
- if 'clang++' in env['CXX']:
- common_cxx_flags += ' -Wno-unknown-pragmas -Wno-unsequenced '
- elif 'g++' in env['CXX']:
- common_cxx_flags += ' -Wno-pragmas '
-
- if env['DEBUG']:
- env.Append(CXXFLAGS = common_cxx_flags + '-O0')
- else:
- # TODO - add back -fvisibility-inlines-hidden
- # https://github.com/mapnik/mapnik/issues/1863
- env.Append(CXXFLAGS = common_cxx_flags + '-O%s' % (env['OPTIMIZATION']))
- if env['DEBUG_UNDEFINED']:
- env.Append(CXXFLAGS = '-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -ftrapv -fwrapv')
-
- # if requested, sort LIBPATH and CPPPATH one last time before saving...
- if env['PRIORITIZE_LINKING']:
- conf.prioritize_paths(silent=True)
-
- # finish config stage and pickle results
- env = conf.Finish()
- env_cache = open(SCONS_CONFIGURE_CACHE, 'w')
- pickle_dict = {}
- for i in pickle_store:
- pickle_dict[i] = env.get(i)
- pickle.dump(pickle_dict,env_cache)
- env_cache.close()
- # fix up permissions on configure outputs
- # this is hackish but avoids potential problems
- # with a non-root configure following a root install
- # that also triggered a re-configure
- try:
- os.chmod(SCONS_CONFIGURE_CACHE,0666)
- except: pass
- try:
- os.chmod(SCONS_LOCAL_CONFIG,0666)
- except: pass
- try:
- os.chmod('.sconsign.dblite',0666)
- except: pass
- try:
- os.chmod(SCONS_LOCAL_LOG,0666)
- except: pass
- try:
- for item in glob('%s/*' % SCONF_TEMP_DIR):
- os.chmod(item,0666)
- except: pass
-
- if 'configure' in command_line_args:
- color_print(4,'\nConfigure completed: run `make` to build or `make install`')
- if not HELP_REQUESTED:
- Exit(0)
+ # Save the custom variables in a SCONS_LOCAL_CONFIG
+ # that will be reloaded to allow for `install` without re-specifying custom variables
+ color_print(4,"\nAll Required dependencies found!\n")
+ if env['USE_CONFIG']:
+ if os.path.exists(SCONS_LOCAL_CONFIG):
+ action = 'Overwriting and re-saving'
+ os.unlink(SCONS_LOCAL_CONFIG)
+ else:
+ action = 'Saving new'
+ color_print(4,"%s file '%s'..." % (action,SCONS_LOCAL_CONFIG))
+ color_print(4,"Will hold custom path variables from commandline and python config file(s)...")
+ opts.Save(SCONS_LOCAL_CONFIG,env)
+ else:
+ color_print(4,"Did not use user config file, no custom path variables will be saved...")
+
+ if env['SKIPPED_DEPS']:
+ color_print(4,'\nNote: will build without these OPTIONAL dependencies:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['SKIPPED_DEPS']]))
+ print
+
+ # fetch the mapnik version header in order to set the
+ # ABI version used to build libmapnik.so on linux in src/build.py
+ abi = GetMapnikLibVersion()
+ abi_no_pre = abi.replace('-pre','').split('.')
+ env['ABI_VERSION'] = abi_no_pre
+ env['MAPNIK_VERSION_STRING'] = abi
+ env['MAPNIK_VERSION'] = str(int(abi_no_pre[0])*100000+int(abi_no_pre[1])*100+int(abi_no_pre[2]))
+
+ # Common DEFINES.
+ env.Append(CPPDEFINES = '-D%s' % env['PLATFORM'].upper())
+ if env['THREADING'] == 'multi':
+ env.Append(CPPDEFINES = '-DMAPNIK_THREADSAFE')
+
+ if env['NO_ATEXIT']:
+ env.Append(CPPDEFINES = '-DMAPNIK_NO_ATEXIT')
+
+ # Mac OSX (Darwin) special settings
+ if env['PLATFORM'] == 'Darwin':
+ pthread = ''
+ else:
+ pthread = '-pthread'
+
+ # Common debugging flags.
+ # http://lists.fedoraproject.org/pipermail/devel/2010-November/144952.html
+ debug_flags = ['-g', '-fno-omit-frame-pointer']
+ debug_defines = ['-DDEBUG', '-DMAPNIK_DEBUG']
+ ndebug_defines = ['-DNDEBUG']
+
+ # faster compile
+ # http://www.boost.org/doc/libs/1_47_0/libs/spirit/doc/html/spirit/what_s_new/spirit_2_5.html#spirit.what_s_new.spirit_2_5.breaking_changes
+ env.Append(CPPDEFINES = '-DBOOST_SPIRIT_NO_PREDEFINED_TERMINALS=1')
+ env.Append(CPPDEFINES = '-DBOOST_PHOENIX_NO_PREDEFINED_TERMINALS=1')
+ # c++11 support / https://github.com/mapnik/mapnik/issues/1683
+ # - upgrade to PHOENIX_V3 since that is needed for c++11 compile
+ env.Append(CPPDEFINES = '-DBOOST_SPIRIT_USE_PHOENIX_V3=1')
+
+ # Enable logging in debug mode (always) and release mode (when specified)
+ if env['DEFAULT_LOG_SEVERITY']:
+ if env['DEFAULT_LOG_SEVERITY'] not in severities:
+ severities_list = ', '.join(["'%s'" % s for s in severities])
+ color_print(1,"Cannot set default logger severity to '%s', available options are %s." % (env['DEFAULT_LOG_SEVERITY'], severities_list))
+ Exit(1)
+ else:
+ log_severity = severities.index(env['DEFAULT_LOG_SEVERITY'])
+ else:
+ severities_list = ', '.join(["'%s'" % s for s in severities])
+ color_print(1,"No logger severity specified, available options are %s." % severities_list)
+ Exit(1)
+
+ log_enabled = ['-DMAPNIK_LOG', '-DMAPNIK_DEFAULT_LOG_SEVERITY=%d' % log_severity]
+
+ if env['DEBUG']:
+ debug_defines += log_enabled
+ else:
+ if env['ENABLE_LOG']:
+ ndebug_defines += log_enabled
+
+ # Enable statistics reporting
+ if env['ENABLE_STATS']:
+ debug_defines.append('-DMAPNIK_STATS')
+ ndebug_defines.append('-DMAPNIK_STATS')
+
+ # Add rdynamic to allow using statics between application and plugins
+ # http://stackoverflow.com/questions/8623657/multiple-instances-of-singleton-across-shared-libraries-on-linux
+ if env['PLATFORM'] != 'Darwin' and env['CXX'] == 'g++':
+ env.MergeFlags('-rdynamic')
+
+ if env['DEBUG']:
+ env.Append(CXXFLAGS = debug_flags)
+ env.Append(CPPDEFINES = debug_defines)
+ else:
+ env.Append(CPPDEFINES = ndebug_defines)
+
+ # Common flags for g++/clang++ CXX compiler.
+ # TODO: clean up code more to make -Wextra -Wsign-compare -Wsign-conversion -Wconversion viable
+ common_cxx_flags = '-Wall %s %s -ftemplate-depth-300 -Wsign-compare -Wshadow ' % (env['WARNING_CXXFLAGS'], pthread)
+
+ if 'clang++' in env['CXX']:
+ common_cxx_flags += ' -Wno-unknown-pragmas -Wno-unsequenced '
+ elif 'g++' in env['CXX']:
+ common_cxx_flags += ' -Wno-pragmas '
+
+ if env['DEBUG']:
+ env.Append(CXXFLAGS = common_cxx_flags + '-O0')
+ else:
+ # TODO - add back -fvisibility-inlines-hidden
+ # https://github.com/mapnik/mapnik/issues/1863
+ env.Append(CXXFLAGS = common_cxx_flags + '-O%s' % (env['OPTIMIZATION']))
+ if env['DEBUG_UNDEFINED']:
+ env.Append(CXXFLAGS = '-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -ftrapv -fwrapv')
+
+ # if requested, sort LIBPATH and CPPPATH one last time before saving...
+ if env['PRIORITIZE_LINKING']:
+ conf.prioritize_paths(silent=True)
+
+ # finish config stage and pickle results
+ env = conf.Finish()
+ env_cache = open(SCONS_CONFIGURE_CACHE, 'w')
+ pickle_dict = {}
+ for i in pickle_store:
+ pickle_dict[i] = env.get(i)
+ pickle.dump(pickle_dict,env_cache)
+ env_cache.close()
+ # fix up permissions on configure outputs
+ # this is hackish but avoids potential problems
+ # with a non-root configure following a root install
+ # that also triggered a re-configure
+ try:
+ os.chmod(SCONS_CONFIGURE_CACHE,0666)
+ except: pass
+ try:
+ os.chmod(SCONS_LOCAL_CONFIG,0666)
+ except: pass
+ try:
+ os.chmod('.sconsign.dblite',0666)
+ except: pass
+ try:
+ os.chmod(SCONS_LOCAL_LOG,0666)
+ except: pass
+ try:
+ for item in glob('%s/*' % SCONF_TEMP_DIR):
+ os.chmod(item,0666)
+ except: pass
+
+ if 'configure' in command_line_args:
+ color_print(4,'\nConfigure completed: run `make` to build or `make install`')
+ if not HELP_REQUESTED:
+ Exit(0)
# autogenerate help on default/current SCons options
Help(opts.GenerateHelpText(env))
@@ -1830,43 +1831,43 @@ Help(opts.GenerateHelpText(env))
if not HELP_REQUESTED:
if 'uninstall' in COMMAND_LINE_TARGETS:
- # dummy action in case there is nothing to uninstall, to avoid phony error..
- env.Alias("uninstall", "")
+ # dummy action in case there is nothing to uninstall, to avoid phony error..
+ env.Alias("uninstall", "")
env['create_uninstall_target'] = create_uninstall_target
if env['PKG_CONFIG_PATH']:
- env['ENV']['PKG_CONFIG_PATH'] = fix_path(env['PKG_CONFIG_PATH'])
- # otherwise this variable == os.environ["PKG_CONFIG_PATH"]
+ env['ENV']['PKG_CONFIG_PATH'] = fix_path(env['PKG_CONFIG_PATH'])
+ # otherwise this variable == os.environ["PKG_CONFIG_PATH"]
if env['PATH']:
- env['ENV']['PATH'] = fix_path(env['PATH']) + ':' + env['ENV']['PATH']
+ env['ENV']['PATH'] = fix_path(env['PATH']) + ':' + env['ENV']['PATH']
if env['PATH_REMOVE']:
- for p in env['PATH_REMOVE'].split(':'):
- if p in env['ENV']['PATH']:
- env['ENV']['PATH'].replace(p,'')
- rm_path(p,'LIBPATH',env)
- rm_path(p,'CPPPATH',env)
- rm_path(p,'CXXFLAGS',env)
- rm_path(p,'CAIRO_LIBPATHS',env)
- rm_path(p,'CAIRO_CPPPATHS',env)
+ for p in env['PATH_REMOVE'].split(':'):
+ if p in env['ENV']['PATH']:
+ env['ENV']['PATH'].replace(p,'')
+ rm_path(p,'LIBPATH',env)
+ rm_path(p,'CPPPATH',env)
+ rm_path(p,'CXXFLAGS',env)
+ rm_path(p,'CAIRO_LIBPATHS',env)
+ rm_path(p,'CAIRO_CPPPATHS',env)
if env['PATH_REPLACE']:
- searches,replace = env['PATH_REPLACE'].split(':')
- for search in searches.split(','):
- if search in env['ENV']['PATH']:
- env['ENV']['PATH'] = os.path.abspath(env['ENV']['PATH'].replace(search,replace))
- def replace_path(set,s,r):
- idx = 0
- for i in env[set]:
- if s in i:
- env[set][idx] = os.path.abspath(env[set][idx].replace(s,r))
- idx +=1
- replace_path('LIBPATH',search,replace)
- replace_path('CPPPATH',search,replace)
- replace_path('CXXFLAGS',search,replace)
- replace_path('CAIRO_LIBPATHS',search,replace)
- replace_path('CAIRO_CPPPATHS',search,replace)
+ searches,replace = env['PATH_REPLACE'].split(':')
+ for search in searches.split(','):
+ if search in env['ENV']['PATH']:
+ env['ENV']['PATH'] = os.path.abspath(env['ENV']['PATH'].replace(search,replace))
+ def replace_path(set,s,r):
+ idx = 0
+ for i in env[set]:
+ if s in i:
+ env[set][idx] = os.path.abspath(env[set][idx].replace(s,r))
+ idx +=1
+ replace_path('LIBPATH',search,replace)
+ replace_path('CPPPATH',search,replace)
+ replace_path('CXXFLAGS',search,replace)
+ replace_path('CAIRO_LIBPATHS',search,replace)
+ replace_path('CAIRO_CPPPATHS',search,replace)
# export env so it is available in build.py files
Export('env')
@@ -1876,15 +1877,15 @@ if not HELP_REQUESTED:
Export('plugin_base')
if env['FAST']:
- # caching is 'auto' by default in SCons
- # But let's also cache implicit deps...
- EnsureSConsVersion(0,98)
- SetOption('implicit_cache', 1)
- SetOption('max_drift', 1)
+ # caching is 'auto' by default in SCons
+ # But let's also cache implicit deps...
+ EnsureSConsVersion(0,98)
+ SetOption('implicit_cache', 1)
+ SetOption('max_drift', 1)
# Build agg first, doesn't need anything special
if env['RUNTIME_LINK'] == 'shared':
- SConscript('deps/agg/build.py')
+ SConscript('deps/agg/build.py')
# Build spirit grammars
SConscript('src/json/build.py')
@@ -1905,76 +1906,78 @@ if not HELP_REQUESTED:
POSTGIS_BUILT = False
PGRASTER_BUILT = False
for plugin in env['PLUGINS']:
- if env['PLUGIN_LINKING'] == 'static' or plugin not in env['REQUESTED_PLUGINS']:
- if os.path.exists('plugins/input/%s.input' % plugin):
- os.unlink('plugins/input/%s.input' % plugin)
- elif plugin in env['REQUESTED_PLUGINS']:
- details = env['PLUGINS'][plugin]
- if details['lib'] in env['LIBS']:
- if env['PLUGIN_LINKING'] == 'shared':
- SConscript('plugins/input/%s/build.py' % plugin)
- # hack to avoid breaking on plugins with the same dep
- if plugin == 'ogr': OGR_BUILT = True
- if plugin == 'gdal': GDAL_BUILT = True
- if plugin == 'postgis': POSTGIS_BUILT = True
- if plugin == 'pgraster': PGRASTER_BUILT = True
- if plugin == 'ogr' or plugin == 'gdal':
- if GDAL_BUILT and OGR_BUILT:
- env['LIBS'].remove(details['lib'])
- elif plugin == 'postgis' or plugin == 'pgraster':
- if POSTGIS_BUILT and PGRASTER_BUILT:
- env['LIBS'].remove(details['lib'])
- else:
- env['LIBS'].remove(details['lib'])
- elif not details['lib']:
- if env['PLUGIN_LINKING'] == 'shared':
- # build internal datasource input plugins
- SConscript('plugins/input/%s/build.py' % plugin)
- else:
- color_print(1,"Notice: dependencies not met for plugin '%s', not building..." % plugin)
- if os.path.exists('plugins/input/%s.input' % plugin):
- os.unlink('plugins/input/%s.input' % plugin)
+ if env['PLUGIN_LINKING'] == 'static' or plugin not in env['REQUESTED_PLUGINS']:
+ if os.path.exists('plugins/input/%s.input' % plugin):
+ os.unlink('plugins/input/%s.input' % plugin)
+ elif plugin in env['REQUESTED_PLUGINS']:
+ details = env['PLUGINS'][plugin]
+ if details['lib'] in env['LIBS']:
+ if env['PLUGIN_LINKING'] == 'shared':
+ SConscript('plugins/input/%s/build.py' % plugin)
+ # hack to avoid breaking on plugins with the same dep
+ if plugin == 'ogr': OGR_BUILT = True
+ if plugin == 'gdal': GDAL_BUILT = True
+ if plugin == 'postgis': POSTGIS_BUILT = True
+ if plugin == 'pgraster': PGRASTER_BUILT = True
+ if plugin == 'ogr' or plugin == 'gdal':
+ if GDAL_BUILT and OGR_BUILT:
+ env['LIBS'].remove(details['lib'])
+ elif plugin == 'postgis' or plugin == 'pgraster':
+ if POSTGIS_BUILT and PGRASTER_BUILT:
+ env['LIBS'].remove(details['lib'])
+ else:
+ env['LIBS'].remove(details['lib'])
+ elif not details['lib']:
+ if env['PLUGIN_LINKING'] == 'shared':
+ # build internal datasource input plugins
+ SConscript('plugins/input/%s/build.py' % plugin)
+ else:
+ color_print(1,"Notice: dependencies not met for plugin '%s', not building..." % plugin)
+ if os.path.exists('plugins/input/%s.input' % plugin):
+ os.unlink('plugins/input/%s.input' % plugin)
create_uninstall_target(env, env['MAPNIK_LIB_DIR_DEST'], False)
create_uninstall_target(env, env['MAPNIK_INPUT_PLUGINS_DEST'] , False)
if 'install' in COMMAND_LINE_TARGETS:
- # if statically linking plugins still make sure
- # to create the dynamic plugins directory
- if env['PLUGIN_LINKING'] == 'static':
- if not os.path.exists(env['MAPNIK_INPUT_PLUGINS_DEST']):
- os.makedirs(env['MAPNIK_INPUT_PLUGINS_DEST'])
- # before installing plugins, wipe out any previously
- # installed plugins that we are no longer building
- for plugin in PLUGINS.keys():
- plugin_path = os.path.join(env['MAPNIK_INPUT_PLUGINS_DEST'],'%s.input' % plugin)
- if os.path.exists(plugin_path):
- if plugin not in env['REQUESTED_PLUGINS'] or env['PLUGIN_LINKING'] == 'static':
- color_print(4,"Notice: removing out of date plugin: '%s'" % plugin_path)
- os.unlink(plugin_path)
+ # if statically linking plugins still make sure
+ # to create the dynamic plugins directory
+ if env['PLUGIN_LINKING'] == 'static':
+ if not os.path.exists(env['MAPNIK_INPUT_PLUGINS_DEST']):
+ os.makedirs(env['MAPNIK_INPUT_PLUGINS_DEST'])
+ # before installing plugins, wipe out any previously
+ # installed plugins that we are no longer building
+ for plugin in PLUGINS.keys():
+ plugin_path = os.path.join(env['MAPNIK_INPUT_PLUGINS_DEST'],'%s.input' % plugin)
+ if os.path.exists(plugin_path):
+ if plugin not in env['REQUESTED_PLUGINS'] or env['PLUGIN_LINKING'] == 'static':
+ color_print(4,"Notice: removing out of date plugin: '%s'" % plugin_path)
+ os.unlink(plugin_path)
# Build the c++ rundemo app if requested
if not env['HOST']:
- if env['DEMO']:
- SConscript('demo/c++/build.py')
+ if env['DEMO']:
+ SConscript('demo/c++/build.py')
# Build shapeindex and remove its dependency from the LIBS
if not env['HOST']:
- if 'boost_program_options%s' % env['BOOST_APPEND'] in env['LIBS']:
- if env['SHAPEINDEX']:
- SConscript('utils/shapeindex/build.py')
- # Build the pgsql2psqlite app if requested
- if env['PGSQL2SQLITE']:
- SConscript('utils/pgsql2sqlite/build.py')
- if env['SVG2PNG']:
- SConscript('utils/svg2png/build.py')
- if env['NIK2IMG']:
- SConscript('utils/nik2img/build.py')
- # devtools not ready for public
- #SConscript('utils/ogrindex/build.py')
- env['LIBS'].remove('boost_program_options%s' % env['BOOST_APPEND'])
- else :
- color_print(1,"WARNING: Cannot find boost_program_options. 'shapeindex' and other command line programs will not be available")
+ if 'boost_program_options%s' % env['BOOST_APPEND'] in env['LIBS']:
+ if env['SHAPEINDEX']:
+ SConscript('utils/shapeindex/build.py')
+ if env['MAPNIK_INDEX']:
+ SConscript('utils/mapnik-index/build.py')
+ # Build the pgsql2psqlite app if requested
+ if env['PGSQL2SQLITE']:
+ SConscript('utils/pgsql2sqlite/build.py')
+ if env['SVG2PNG']:
+ SConscript('utils/svg2png/build.py')
+ if env['NIK2IMG']:
+ SConscript('utils/nik2img/build.py')
+ # devtools not ready for public
+ #SConscript('utils/ogrindex/build.py')
+ env['LIBS'].remove('boost_program_options%s' % env['BOOST_APPEND'])
+ else :
+ color_print(1,"WARNING: Cannot find boost_program_options. 'shapeindex' and other command line programs will not be available")
# Configure fonts and if requested install the bundled DejaVu fonts
SConscript('fonts/build.py')
@@ -1983,10 +1986,10 @@ if not HELP_REQUESTED:
SConscript('test/build.py')
if env['BENCHMARK']:
- SConscript('benchmark/build.py')
+ SConscript('benchmark/build.py')
if os.path.exists('./bindings/python/build.py'):
- SConscript('./bindings/python/build.py')
+ SConscript('./bindings/python/build.py')
# install mapnik-config script
SConscript('utils/mapnik-config/build.py')
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..b227544
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,26 @@
+environment:
+ msvs_toolset: 14
+ BOOST_VERSION: 58
+ FASTBUILD: 1
+ matrix:
+ - platform: x64
+ configuration: Release
+
+os: Visual Studio 2015
+
+shallow_clone: true
+
+install:
+ - scripts\build-appveyor.bat
+
+artifacts:
+ - path: mapnik-gyp\msbuild-summary.txt
+ name: msbuild-summary.txt
+ - path: mapnik-gyp\msbuild-errors.txt
+ name: msbuild-errors.txt
+ - path: mapnik-gyp\msbuild-warnings.txt
+ name: msbuild-warnings.txt
+
+build: off
+test: off
+deploy: off
diff --git a/benchmark/build.py b/benchmark/build.py
index 800a9ab..37ba867 100644
--- a/benchmark/build.py
+++ b/benchmark/build.py
@@ -47,6 +47,7 @@ benchmarks = [
"test_marker_cache.cpp",
"test_quad_tree.cpp",
"test_noop_rendering.cpp",
+ "test_getline.cpp",
# "test_numeric_cast_vs_static_cast.cpp",
]
for cpp_test in benchmarks:
diff --git a/benchmark/run b/benchmark/run
index f918539..00285b2 100755
--- a/benchmark/run
+++ b/benchmark/run
@@ -9,7 +9,7 @@ function run {
${BASE}/$1 --threads 0 --iterations $3;
${BASE}/$1 --threads $2 --iterations $(expr $3 / $2);
}
-
+run test_getline 30 10000000
#run test_array_allocation 20 100000
#run test_png_encoding1 10 1000
#run test_png_encoding2 10 50
diff --git a/benchmark/test_getline.cpp b/benchmark/test_getline.cpp
new file mode 100644
index 0000000..1791b06
--- /dev/null
+++ b/benchmark/test_getline.cpp
@@ -0,0 +1,125 @@
+#include "bench_framework.hpp"
+#include <cstring>
+#include <cstdlib>
+#include "../plugins/input/csv/csv_utils.hpp"
+
+class test : public benchmark::test_case
+{
+public:
+ std::string line_data_;
+ test(mapnik::parameters const& params)
+ : test_case(params),
+ line_data_("this is one line\nand this is a second line\nand a third line")
+ {
+ boost::optional<std::string> line_data = params.get<std::string>("line");
+ if (line_data)
+ {
+ line_data_ = *line_data;
+ }
+ }
+
+ bool validate() const
+ {
+ std::string first = line_data_.substr(line_data_.find_first_not_of('\n'));
+ char newline = '\n';
+ std::string csv_line;
+ std::stringstream s;
+ s << line_data_;
+ std::getline(s,csv_line,newline);
+ if (csv_line != first)
+ {
+ return true;
+ }
+ else
+ {
+ std::clog << "Error: the parsed line (" << csv_line << ") should be a subset of the original line (" << line_data_ << ") (ensure you pass a line with a \\n)\n";
+ }
+ return true;
+ }
+ bool operator()() const
+ {
+ char newline = '\n';
+ std::string csv_line;
+ std::stringstream s;
+ s << line_data_;
+ for (unsigned i=0;i<iterations_;++i)
+ {
+ std::getline(s,csv_line,newline);
+ }
+ return true;
+ }
+};
+
+
+class test2 : public benchmark::test_case
+{
+public:
+ std::string line_data_;
+ test2(mapnik::parameters const& params)
+ : test_case(params),
+ line_data_("this is one line\nand this is a second line\nand a third line")
+ {
+ boost::optional<std::string> line_data = params.get<std::string>("line");
+ if (line_data)
+ {
+ line_data_ = *line_data;
+ }
+ }
+
+ bool validate() const
+ {
+ std::string first = line_data_.substr(line_data_.find_first_not_of('\n'));
+ char newline = '\n';
+ char quote = '"';
+ std::string csv_line;
+ std::stringstream s;
+ s << line_data_;
+ csv_utils::getline_csv(s,csv_line,newline,quote);
+ if (csv_line != first)
+ {
+ return true;
+ }
+ else
+ {
+ std::clog << "Error: the parsed line (" << csv_line << ") should be a subset of the original line (" << line_data_ << ") (ensure you pass a line with a \\n)\n";
+ }
+ return true;
+ }
+ bool operator()() const
+ {
+ char newline = '\n';
+ char quote = '"';
+ std::string csv_line;
+ std::stringstream s;
+ s << line_data_;
+ for (unsigned i=0;i<iterations_;++i)
+ {
+ csv_utils::getline_csv(s,csv_line,newline,quote);
+ }
+ return true;
+ }
+};
+
+int main(int argc, char** argv)
+{
+ int return_value = 0;
+ try
+ {
+ mapnik::parameters params;
+ benchmark::handle_args(argc,argv,params);
+ {
+ test test_runner(params);
+ return_value = return_value | run(test_runner,"std::getline");
+ }
+ {
+ test2 test_runner2(params);
+ return_value = return_value | run(test_runner2,"csv_utils::getline_csv");
+ }
+ }
+ catch (std::exception const& ex)
+ {
+ std::clog << ex.what() << "\n";
+ return -1;
+ }
+ return return_value;
+}
diff --git a/benchmark/test_rendering.cpp b/benchmark/test_rendering.cpp
index 593307b..beea289 100644
--- a/benchmark/test_rendering.cpp
+++ b/benchmark/test_rendering.cpp
@@ -28,7 +28,7 @@ public:
boost::optional<std::string> map = params.get<std::string>("map");
if (!map)
{
- throw std::runtime_error("please provide a --map=<path to xml> arg");
+ throw std::runtime_error("please provide a --map <path to xml> arg");
}
xml_ = *map;
diff --git a/bootstrap.sh b/bootstrap.sh
index 5d38b16..b148139 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -48,29 +48,29 @@ function install() {
fi
}
+ICU_VERSION="55.1"
+
function install_mason_deps() {
install gdal 1.11.2 libgdal &
- install boost 1.57.0 &
- install boost_libsystem 1.57.0 &
- install boost_libthread 1.57.0 &
- install boost_libfilesystem 1.57.0 &
- install boost_libprogram_options 1.57.0 &
- install boost_libregex 1.57.0 &
- install boost_libpython 1.57.0 &
- install freetype 2.5.5 libfreetype &
+ install boost 1.59.0 &
+ install boost_liball 1.59.0 &
+ install freetype 2.6 libfreetype &
install harfbuzz 0.9.40 libharfbuzz &
install jpeg_turbo 1.4.0 libjpeg &
install libpng 1.6.17 libpng &
install webp 0.4.2 libwebp &
- install icu 54.1 &
+ install icu ${ICU_VERSION} &
install proj 4.8.0 libproj &
install libtiff 4.0.4beta libtiff &
install libpq 9.4.0 &
install sqlite 3.8.8.1 libsqlite3 &
install expat 2.1.0 libexpat &
install pixman 0.32.6 libpixman-1 &
- install cairo 1.12.18 libcairo &
+ install cairo 1.14.2 libcairo &
+ install protobuf 2.6.1 &
wait
+ # technically protobuf is not a mapnik core dep, but installing
+ # here by default helps make mapnik-vector-tile builds easier
}
MASON_LINKED_ABS=$(pwd)/mason_packages/.link
@@ -133,7 +133,7 @@ SAMPLE_INPUT_PLUGINS = True
# NOTE: the `mapnik-settings.env` is used by test/run (which is run by `make test`)
function setup_runtime_settings() {
echo "export PROJ_LIB=${MASON_LINKED_ABS}/share/proj" > mapnik-settings.env
- echo "export ICU_DATA=${MASON_LINKED_ABS}/share/icu/54.1" >> mapnik-settings.env
+ echo "export ICU_DATA=${MASON_LINKED_ABS}/share/icu/${ICU_VERSION}" >> mapnik-settings.env
echo "export GDAL_DATA=${MASON_LINKED_ABS}/share/gdal" >> mapnik-settings.env
source mapnik-settings.env
}
diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp
index efcab89..e35d131 100644
--- a/demo/viewer/mapwidget.cpp
+++ b/demo/viewer/mapwidget.cpp
@@ -31,10 +31,10 @@
#include <mapnik/feature_kv_iterator.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/util/timer.hpp>
-#include <mapnik/cairo/cairo_image_util.hpp>
#ifdef HAVE_CAIRO
// cairo
+#include <mapnik/cairo/cairo_image_util.hpp>
#include <mapnik/cairo/cairo_renderer.hpp>
#endif
diff --git a/demo/viewer/viewer.pro b/demo/viewer/viewer.pro
index aad00b4..8a97477 100644
--- a/demo/viewer/viewer.pro
+++ b/demo/viewer/viewer.pro
@@ -1,6 +1,7 @@
######################################################################
# Mapnik viewer - Copyright (C) 2007 Artem Pavlenko
######################################################################
+QMAKE_MAC_SDK = macosx10.11
TEMPLATE = app
QT += core gui widgets
QMAKE_CXX = $$system(mapnik-config --cxx)
diff --git a/include/mapnik/css_color_grammar.hpp b/include/mapnik/css_color_grammar.hpp
index 4403d34..04ff02d 100644
--- a/include/mapnik/css_color_grammar.hpp
+++ b/include/mapnik/css_color_grammar.hpp
@@ -37,6 +37,7 @@
#pragma GCC diagnostic ignored "-Wconversion"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_action.hpp>
+#include <boost/spirit/include/qi_lexeme.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
diff --git a/include/mapnik/css_color_grammar_impl.hpp b/include/mapnik/css_color_grammar_impl.hpp
index 4ce3134..c978194 100644
--- a/include/mapnik/css_color_grammar_impl.hpp
+++ b/include/mapnik/css_color_grammar_impl.hpp
@@ -39,6 +39,7 @@ css_color_grammar<Iterator>::css_color_grammar()
qi::_a_type _a;
qi::_b_type _b;
qi::_c_type _c;
+ qi::lexeme_type lexeme;
ascii::no_case_type no_case;
using phoenix::at_c;
@@ -49,18 +50,18 @@ css_color_grammar<Iterator>::css_color_grammar()
| hex_color_small
| no_case[named];
- hex_color = lit('#')
+ hex_color = lexeme[ lit('#')
>> hex2 [ at_c<0>(_val) = _1 ]
>> hex2 [ at_c<1>(_val) = _1 ]
>> hex2 [ at_c<2>(_val) = _1 ]
- >>-hex2 [ at_c<3>(_val) = _1 ]
+ >>-hex2 [ at_c<3>(_val) = _1 ] ]
;
- hex_color_small = lit('#')
+ hex_color_small = lexeme[ lit('#')
>> hex1 [ at_c<0>(_val) = _1 | _1 << 4 ]
>> hex1 [ at_c<1>(_val) = _1 | _1 << 4 ]
>> hex1 [ at_c<2>(_val) = _1 | _1 << 4 ]
- >>-hex1 [ at_c<3>(_val) = _1 | _1 << 4 ]
+ >>-hex1 [ at_c<3>(_val) = _1 | _1 << 4 ] ]
;
rgba_color = lit("rgb") >> -lit('a')
diff --git a/include/mapnik/csv/csv_grammar.hpp b/include/mapnik/csv/csv_grammar.hpp
index 2bd0f52..f665dae 100644
--- a/include/mapnik/csv/csv_grammar.hpp
+++ b/include/mapnik/csv/csv_grammar.hpp
@@ -36,15 +36,30 @@ using csv_line = std::vector<csv_value>;
using csv_data = std::vector<csv_line>;
template <typename Iterator>
-struct csv_line_grammar : qi::grammar<Iterator, csv_line(std::string const&), qi::blank_type>
+struct csv_white_space_skipper : qi::grammar<Iterator>
{
- csv_line_grammar() : csv_line_grammar::base_type(line)
+ csv_white_space_skipper()
+ : csv_white_space_skipper::base_type(skip)
+ {
+ using namespace qi;
+ qi::lit_type lit;
+ skip = +lit(' ')
+ ;
+ }
+ qi::rule<Iterator> skip;
+};
+
+template <typename Iterator, typename Skipper = csv_white_space_skipper<Iterator> >
+struct csv_line_grammar : qi::grammar<Iterator, csv_line(char, char), Skipper>
+{
+ csv_line_grammar()
+ : csv_line_grammar::base_type(line)
{
using namespace qi;
qi::_a_type _a;
qi::_r1_type _r1;
+ qi::_r2_type _r2;
qi::lit_type lit;
- //qi::eol_type eol;
qi::_1_type _1;
qi::char_type char_;
qi::omit_type omit;
@@ -61,43 +76,24 @@ struct csv_line_grammar : qi::grammar<Iterator, csv_line(std::string const&), qi
("\\\"", '\"')
("\"\"", '\"') // double quote
;
-
- line = column(_r1) % char_(_r1)
+ line = -omit[char_("\n\r")] >> column(_r1, _r2) % lit(_r1)
;
- column = -omit[char_("\n\r")] >> quoted | *(char_ - (lit(_r1) /*| eol*/))
+ column = quoted(_r2) | *(char_ - (lit(_r1)))
;
- quoted = omit[char_("\"'")[_a = _1]] > text(_a) > -lit(_a)
+ quoted = omit[char_(_r1)[_a = _1]] > text(_a) > -lit(_a) // support unmatched quotes or not (??)
;
- text = *(unesc_char | (char_ - char_(_r1)))
+ text = *(unesc_char | (char_ - lit(_r1)))
;
BOOST_SPIRIT_DEBUG_NODES((line)(column)(quoted));
}
- private:
- qi::rule<Iterator, csv_line(std::string const&), qi::blank_type> line;
- qi::rule<Iterator, csv_value(std::string const&)> column; // no-skip
- qi::rule<Iterator, csv_value(char)> text;
- qi::rule<Iterator, qi::locals<char>, csv_value()> quoted;
+private:
+ qi::rule<Iterator, csv_line(char, char), Skipper> line;
+ qi::rule<Iterator, csv_value(char, char)> column; // no-skip
+ qi::rule<Iterator, csv_value(char)> text; // no-skip
+ qi::rule<Iterator, qi::locals<char>, csv_value(char)> quoted; //no-skip
qi::symbols<char const, char const> unesc_char;
};
-template <typename Iterator>
-struct csv_file_grammar : qi::grammar<Iterator, csv_data(std::string const&), qi::blank_type>
-{
- csv_file_grammar() : csv_file_grammar::base_type(start)
- {
- using namespace qi;
- qi::eol_type eol;
- qi::_r1_type _r1;
- start = -line(_r1) % eol
- ;
- BOOST_SPIRIT_DEBUG_NODES((start));
- }
- private:
- qi::rule<Iterator, csv_data(std::string const&), qi::blank_type> start;
- csv_line_grammar<Iterator> line;
-};
-
-
}
#endif // MAPNIK_CVS_GRAMMAR_HPP
diff --git a/include/mapnik/expression_grammar.hpp b/include/mapnik/expression_grammar.hpp
index 7a71976..5bb132f 100644
--- a/include/mapnik/expression_grammar.hpp
+++ b/include/mapnik/expression_grammar.hpp
@@ -36,6 +36,7 @@
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wshadow"
#pragma GCC diagnostic ignored "-Wsign-conversion"
+#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wconversion"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_locals.hpp>
diff --git a/include/mapnik/expression_grammar_impl.hpp b/include/mapnik/expression_grammar_impl.hpp
index d123b3b..93b6d86 100644
--- a/include/mapnik/expression_grammar_impl.hpp
+++ b/include/mapnik/expression_grammar_impl.hpp
@@ -31,9 +31,17 @@
#include <mapnik/function_call.hpp>
// boost
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wunused-local-typedef"
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wconversion"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
+#pragma GCC diagnostic pop
// fwd declare
namespace mapnik {
diff --git a/include/mapnik/feature.hpp b/include/mapnik/feature.hpp
index eb084bc..fff06a2 100644
--- a/include/mapnik/feature.hpp
+++ b/include/mapnik/feature.hpp
@@ -273,9 +273,6 @@ inline std::ostream& operator<< (std::ostream & out,feature_impl const& f)
return out;
}
-// TODO - remove at Mapnik 3.x
-using Feature = feature_impl;
-
using feature_ptr = std::shared_ptr<feature_impl>;
}
diff --git a/include/mapnik/feature_style_processor.hpp b/include/mapnik/feature_style_processor.hpp
index 062c9d6..c0ba4f3 100644
--- a/include/mapnik/feature_style_processor.hpp
+++ b/include/mapnik/feature_style_processor.hpp
@@ -110,7 +110,7 @@ private:
/*!
* \brief render features list queued when they are available.
*/
- void render_material(layer_rendering_material & mat, Processor & p );
+ void render_material(layer_rendering_material const & mat, Processor & p );
Map const& m_;
};
diff --git a/include/mapnik/feature_style_processor_impl.hpp b/include/mapnik/feature_style_processor_impl.hpp
index 0c77821..89e0c3a 100644
--- a/include/mapnik/feature_style_processor_impl.hpp
+++ b/include/mapnik/feature_style_processor_impl.hpp
@@ -69,10 +69,9 @@ struct layer_rendering_material
lay_(lay),
proj0_(dest),
proj1_(lay.srs(),true) {}
-};
-
-using layer_rendering_material_ptr = std::shared_ptr<layer_rendering_material>;
+ layer_rendering_material(layer_rendering_material && rhs) = default;
+};
template <typename Processor>
feature_style_processor<Processor>::feature_style_processor(Map const& m, double scale_factor)
@@ -102,7 +101,7 @@ void feature_style_processor<Processor>::apply(double scale_denom)
// in a second time, we fetch the results and
// do the actual rendering
- std::vector<layer_rendering_material_ptr> mat_list;
+ std::vector<layer_rendering_material> mat_list;
// Define processing context map used by datasources
// implementing asynchronous queries
@@ -113,9 +112,9 @@ void feature_style_processor<Processor>::apply(double scale_denom)
if (lyr.visible(scale_denom))
{
std::set<std::string> names;
- layer_rendering_material_ptr mat = std::make_shared<layer_rendering_material>(lyr, proj);
+ layer_rendering_material mat(lyr, proj);
- prepare_layer(*mat,
+ prepare_layer(mat,
ctx_map,
p,
m_.scale(),
@@ -127,18 +126,18 @@ void feature_style_processor<Processor>::apply(double scale_denom)
names);
// Store active material
- if (!mat->active_styles_.empty())
+ if (!mat.active_styles_.empty())
{
- mat_list.push_back(mat);
+ mat_list.emplace_back(std::move(mat));
}
}
}
- for ( layer_rendering_material_ptr mat : mat_list )
+ for ( layer_rendering_material const & mat : mat_list )
{
- if (!mat->active_styles_.empty())
+ if (!mat.active_styles_.empty())
{
- render_material(*mat,p);
+ render_material(mat, p);
}
}
@@ -443,11 +442,11 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
template <typename Processor>
-void feature_style_processor<Processor>::render_material(layer_rendering_material & mat,
+void feature_style_processor<Processor>::render_material(layer_rendering_material const & mat,
Processor & p )
{
- std::vector<feature_type_style const*> & active_styles = mat.active_styles_;
- std::vector<featureset_ptr> & featureset_ptr_list = mat.featureset_ptr_list_;
+ std::vector<feature_type_style const*> const & active_styles = mat.active_styles_;
+ std::vector<featureset_ptr> const & featureset_ptr_list = mat.featureset_ptr_list_;
if (featureset_ptr_list.empty())
{
// The datasource wasn't queried because of early return
@@ -464,7 +463,7 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
layer const& lay = mat.lay_;
- std::vector<rule_cache> & rule_caches = mat.rule_caches_;
+ std::vector<rule_cache> const & rule_caches = mat.rule_caches_;
proj_transform prj_trans(mat.proj0_,mat.proj1_);
@@ -544,7 +543,7 @@ void feature_style_processor<Processor>::render_material(layer_rendering_materia
else
{
std::size_t i = 0;
- std::vector<featureset_ptr>::iterator featuresets = featureset_ptr_list.begin();
+ std::vector<featureset_ptr>::const_iterator featuresets = featureset_ptr_list.cbegin();
for (feature_type_style const* style : active_styles)
{
featureset_ptr features = *featuresets++;
diff --git a/include/mapnik/geometry_is_simple.hpp b/include/mapnik/geometry_is_simple.hpp
index 30fff6d..868b41a 100644
--- a/include/mapnik/geometry_is_simple.hpp
+++ b/include/mapnik/geometry_is_simple.hpp
@@ -48,7 +48,9 @@ struct geometry_is_simple
result_type operator() (geometry_empty const& ) const
{
- return false;
+ // An empty geometry has no anomalous geometric points, such as self intersection or self tangency.
+ // Therefore, we will return true
+ return true;
}
template <typename T>
@@ -69,6 +71,13 @@ struct geometry_is_simple
template <typename T>
result_type operator() (line_string<T> const& line) const
{
+ if (line.empty())
+ {
+ // Prevent an empty line_string from segfaulting in boost geometry 1.58
+ // once it is fixed this can be removed
+ // https://svn.boost.org/trac/boost/ticket/11709
+ return true;
+ }
return boost::geometry::is_simple(line);
}
template <typename T>
@@ -79,17 +88,43 @@ struct geometry_is_simple
template <typename T>
result_type operator() (multi_point<T> const& multi_pt) const
{
+ if (multi_pt.empty())
+ {
+ // This return is due to bug in boost geometry once it is fixed it can be removed
+ // https://svn.boost.org/trac/boost/ticket/11710
+ return true;
+ }
return boost::geometry::is_simple(multi_pt);
}
template <typename T>
result_type operator() (multi_line_string<T> const& multi_line) const
{
- return boost::geometry::is_simple(multi_line);
+ if (multi_line.empty())
+ {
+ // This return is due to bug in boost geometry once it is fixed it can be removed
+ // https://svn.boost.org/trac/boost/ticket/11710
+ return true;
+ }
+ for (auto const& line : multi_line)
+ {
+ if (!(*this)(line)) return false;
+ }
+ return true;
}
template <typename T>
result_type operator() (multi_polygon<T> const& multi_poly) const
{
- return boost::geometry::is_simple(multi_poly);
+ if (multi_poly.empty())
+ {
+ // This return is due to bug in boost geometry once it is fixed it can be removed
+ // https://svn.boost.org/trac/boost/ticket/11710
+ return true;
+ }
+ for (auto const& poly : multi_poly)
+ {
+ if (!(*this)(poly)) return false;
+ }
+ return true;
}
};
@@ -102,6 +137,12 @@ inline bool is_simple(T const& geom)
return detail::geometry_is_simple() (geom);
}
+template <typename T>
+inline bool is_simple(mapnik::geometry::geometry<T> const& geom)
+{
+ return util::apply_visitor(detail::geometry_is_simple(), geom);
+}
+
}}
#endif // BOOST_VERSION >= 1.56
diff --git a/include/mapnik/geometry_is_valid.hpp b/include/mapnik/geometry_is_valid.hpp
index aa7f139..95319cc 100644
--- a/include/mapnik/geometry_is_valid.hpp
+++ b/include/mapnik/geometry_is_valid.hpp
@@ -25,12 +25,13 @@
#include <boost/version.hpp>
-// only Boost >= 1.56 contains the is_valid function
-#if BOOST_VERSION >= 105600
+// only Boost >= 1.58 contains the is_valid function
+#if BOOST_VERSION >= 105800
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_adapters.hpp>
#include <boost/geometry/algorithms/is_valid.hpp>
+#include <boost/geometry/algorithms/validity_failure_type.hpp>
namespace mapnik { namespace geometry {
@@ -48,7 +49,7 @@ struct geometry_is_valid
result_type operator() (geometry_empty const& ) const
{
- return false;
+ return true;
}
template <typename T>
@@ -98,6 +99,143 @@ struct geometry_is_valid
}
};
+struct geometry_is_valid_reason
+{
+ using result_type = bool;
+
+ boost::geometry::validity_failure_type & failure_;
+
+ geometry_is_valid_reason(boost::geometry::validity_failure_type & failure):
+ failure_(failure) {}
+
+ template <typename T>
+ result_type operator() (geometry<T> const& geom) const
+ {
+ return mapnik::util::apply_visitor(*this, geom);
+ }
+
+ result_type operator() (geometry_empty const& ) const
+ {
+ failure_ = boost::geometry::no_failure;
+ return true;
+ }
+
+ template <typename T>
+ result_type operator() (geometry_collection<T> const& collection) const
+ {
+ for (auto const& geom : collection)
+ {
+ if ( !(*this)(geom)) return false;
+ }
+ return true;
+ }
+
+ template <typename T>
+ result_type operator() (point<T> const& pt) const
+ {
+ return boost::geometry::is_valid(pt, failure_);
+ }
+
+ template <typename T>
+ result_type operator() (line_string<T> const& line) const
+ {
+ return boost::geometry::is_valid(line, failure_);
+ }
+
+ template <typename T>
+ result_type operator() (polygon<T> const& poly) const
+ {
+ return boost::geometry::is_valid(poly, failure_);
+ }
+
+ template <typename T>
+ result_type operator() (multi_point<T> const& multi_pt) const
+ {
+ return boost::geometry::is_valid(multi_pt, failure_);
+ }
+
+ template <typename T>
+ result_type operator() (multi_line_string<T> const& multi_line) const
+ {
+ return boost::geometry::is_valid(multi_line, failure_);
+ }
+
+ template <typename T>
+ result_type operator() (multi_polygon<T> const& multi_poly) const
+ {
+ return boost::geometry::is_valid(multi_poly, failure_);
+ }
+};
+
+struct geometry_is_valid_string
+{
+ using result_type = bool;
+
+ std::string & message_;
+
+ geometry_is_valid_string(std::string & message):
+ message_(message) {}
+
+ template <typename T>
+ result_type operator() (geometry<T> const& geom) const
+ {
+ return mapnik::util::apply_visitor(*this, geom);
+ }
+
+ result_type operator() (geometry_empty const& ) const
+ {
+ message_ = "Geometry is valid";
+ return true;
+ }
+
+ template <typename T>
+ result_type operator() (geometry_collection<T> const& collection) const
+ {
+ for (auto const& geom : collection)
+ {
+ if ( !(*this)(geom)) return false;
+ }
+ return true;
+ }
+
+ template <typename T>
+ result_type operator() (point<T> const& pt) const
+ {
+ return boost::geometry::is_valid(pt, message_);
+ }
+
+ template <typename T>
+ result_type operator() (line_string<T> const& line) const
+ {
+ return boost::geometry::is_valid(line, message_);
+ }
+
+ template <typename T>
+ result_type operator() (polygon<T> const& poly) const
+ {
+ return boost::geometry::is_valid(poly, message_);
+ }
+
+ template <typename T>
+ result_type operator() (multi_point<T> const& multi_pt) const
+ {
+ return boost::geometry::is_valid(multi_pt, message_);
+ }
+
+ template <typename T>
+ result_type operator() (multi_line_string<T> const& multi_line) const
+ {
+ return boost::geometry::is_valid(multi_line, message_);
+ }
+
+ template <typename T>
+ result_type operator() (multi_polygon<T> const& multi_poly) const
+ {
+ return boost::geometry::is_valid(multi_poly, message_);
+ }
+};
+
+
}
template <typename T>
@@ -106,7 +244,39 @@ inline bool is_valid(T const& geom)
return detail::geometry_is_valid() (geom);
}
+template <typename T>
+inline bool is_valid(mapnik::geometry::geometry<T> const& geom)
+{
+ return util::apply_visitor(detail::geometry_is_valid(), geom);
+}
+
+template <typename T>
+inline bool is_valid(T const& geom, boost::geometry::validity_failure_type & failure)
+{
+ return detail::geometry_is_valid_reason(failure) (geom);
+}
+
+template <typename T>
+inline bool is_valid(mapnik::geometry::geometry<T> const& geom,
+ boost::geometry::validity_failure_type & failure)
+{
+ return util::apply_visitor(detail::geometry_is_valid_reason(failure), geom);
+}
+
+template <typename T>
+inline bool is_valid(T const& geom, std::string & message)
+{
+ return detail::geometry_is_valid_string(message) (geom);
+}
+
+template <typename T>
+inline bool is_valid(mapnik::geometry::geometry<T> const& geom,
+ std::string & message)
+{
+ return util::apply_visitor(detail::geometry_is_valid_string(message), geom);
+}
+
}}
-#endif // BOOST_VERSION >= 1.56
+#endif // BOOST_VERSION >= 1.58
#endif // MAPNIK_GEOMETRY_IS_VALID_HPP
diff --git a/include/mapnik/image_any.hpp b/include/mapnik/image_any.hpp
index c14d5dd..735ad82 100644
--- a/include/mapnik/image_any.hpp
+++ b/include/mapnik/image_any.hpp
@@ -55,8 +55,8 @@ struct MAPNIK_DECL image_any : image_base
bool painted = false);
template <typename T>
- image_any(T && data) noexcept
- : image_base(std::move(data)) {}
+ image_any(T && _data) noexcept
+ : image_base(std::move(_data)) {}
unsigned char const* bytes() const;
unsigned char* bytes();
diff --git a/include/mapnik/jpeg_io.hpp b/include/mapnik/jpeg_io.hpp
index dcfd446..cc64dac 100644
--- a/include/mapnik/jpeg_io.hpp
+++ b/include/mapnik/jpeg_io.hpp
@@ -27,10 +27,10 @@
#include <new>
#include <ostream>
+#include <cstdio>
extern "C"
{
-#include <stdio.h>
#include <jpeglib.h>
}
@@ -58,10 +58,10 @@ inline boolean empty_output_buffer (j_compress_ptr cinfo)
{
dest_mgr * dest = reinterpret_cast<dest_mgr*>(cinfo->dest);
dest->out->write((char*)dest->buffer, BUFFER_SIZE);
- if (!*(dest->out)) return false;
+ if (!*(dest->out)) return boolean(0);
dest->pub.next_output_byte = dest->buffer;
dest->pub.free_in_buffer = BUFFER_SIZE;
- return true;
+ return boolean(1);
}
inline void term_destination( j_compress_ptr cinfo)
@@ -105,8 +105,8 @@ void save_as_jpeg(T1 & file,int quality, T2 const& image)
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo, quality,1);
- jpeg_start_compress(&cinfo, 1);
+ jpeg_set_quality(&cinfo, quality, boolean(1));
+ jpeg_start_compress(&cinfo, boolean(1));
JSAMPROW row_pointer[1];
JSAMPLE* row=reinterpret_cast<JSAMPLE*>( ::operator new (sizeof(JSAMPLE) * width*3));
while (cinfo.next_scanline < cinfo.image_height)
diff --git a/include/mapnik/json/error_handler.hpp b/include/mapnik/json/error_handler.hpp
index 2f38f62..90d64af 100644
--- a/include/mapnik/json/error_handler.hpp
+++ b/include/mapnik/json/error_handler.hpp
@@ -44,7 +44,7 @@ struct error_handler
auto start = err_pos;
std::advance(err_pos,16);
auto end = err_pos;
- s << what << " expected but got: " << std::string(start, end);
+ s << "Mapnik geojson parsing error:" << what << " expected but got: " << std::string(start, end);
throw std::runtime_error(s.str());
}
};
diff --git a/include/mapnik/json/extract_bounding_box_grammar.hpp b/include/mapnik/json/extract_bounding_box_grammar.hpp
index 2183fe5..bfe9185 100644
--- a/include/mapnik/json/extract_bounding_box_grammar.hpp
+++ b/include/mapnik/json/extract_bounding_box_grammar.hpp
@@ -45,8 +45,8 @@
namespace mapnik { namespace json {
-using position = mapnik::geometry::point<double>;
-using boxes = std::vector<std::pair<box2d<double>, std::pair<std::size_t, std::size_t>>>;
+using position_type = mapnik::geometry::point<double>;
+using boxes_type = std::vector<std::pair<box2d<double>, std::pair<std::size_t, std::size_t>>>;
namespace qi = boost::spirit::qi;
@@ -84,15 +84,15 @@ struct push_box_impl
template <typename Iterator, typename ErrorHandler = error_handler<Iterator> >
struct extract_bounding_box_grammar :
- qi::grammar<Iterator, void(boxes&), space_type>
+ qi::grammar<Iterator, void(boxes_type&), space_type>
{
extract_bounding_box_grammar();
// rules
- qi::rule<Iterator, void(boxes&), space_type> start;
- qi::rule<Iterator, qi::locals<Iterator>, void(boxes&), space_type> features;
- qi::rule<Iterator, qi::locals<int, box2d<double>>, void(boxes&, Iterator const&), space_type> feature;
+ qi::rule<Iterator, void(boxes_type&), space_type> start;
+ qi::rule<Iterator, qi::locals<Iterator>, void(boxes_type&), space_type> features;
+ qi::rule<Iterator, qi::locals<int, box2d<double>>, void(boxes_type&, Iterator const&), space_type> feature;
qi::rule<Iterator, qi::locals<box2d<double>>, box2d<double>(), space_type> coords;
- qi::rule<Iterator, boost::optional<position>(), space_type> pos;
+ qi::rule<Iterator, boost::optional<position_type>(), space_type> pos;
qi::rule<Iterator, void(box2d<double>&), space_type> ring;
qi::rule<Iterator, void(box2d<double>&), space_type> rings;
qi::rule<Iterator, void(box2d<double>&), space_type> rings_array;
diff --git a/include/mapnik/quad_tree.hpp b/include/mapnik/quad_tree.hpp
index d46faa2..092bf4d 100644
--- a/include/mapnik/quad_tree.hpp
+++ b/include/mapnik/quad_tree.hpp
@@ -30,20 +30,23 @@
// stl
#include <algorithm>
#include <vector>
+#include <type_traits>
+
+#include <cstring>
namespace mapnik
{
template <typename T>
class quad_tree : util::noncopyable
{
+ using value_type = T;
struct node
{
- using value_t = T;
- using cont_t = std::vector<T>;
- using iterator = typename cont_t::iterator;
- using const_iterator = typename cont_t::const_iterator;
+ using cont_type = std::vector<T>;
+ using iterator = typename cont_type::iterator;
+ using const_iterator = typename cont_type::const_iterator;
box2d<double> extent_;
- cont_t cont_;
+ cont_type cont_;
node * children_[4];
explicit node(box2d<double> const& ext)
@@ -76,18 +79,28 @@ class quad_tree : util::noncopyable
{
return cont_.end();
}
+
+ int num_subnodes() const
+ {
+ int count = 0;
+ for (int i = 0; i < 4; ++i)
+ {
+ if (children_[i]) ++count;
+ }
+ return count;
+ }
~node () {}
};
- using nodes_t = std::vector<std::unique_ptr<node> >;
- using cont_t = typename node::cont_t;
- using node_data_iterator = typename cont_t::iterator;
+ using nodes_type = std::vector<std::unique_ptr<node> >;
+ using cont_type = typename node::cont_type;
+ using node_data_iterator = typename cont_type::iterator;
public:
- using iterator = typename nodes_t::iterator;
- using const_iterator = typename nodes_t::const_iterator;
- using result_t = typename std::vector<std::reference_wrapper<T> >;
- using query_iterator = typename result_t::iterator;
+ using iterator = typename nodes_type::iterator;
+ using const_iterator = typename nodes_type::const_iterator;
+ using result_type = typename std::vector<std::reference_wrapper<T> >;
+ using query_iterator = typename result_type::iterator;
explicit quad_tree(box2d<double> const& ext,
unsigned int max_depth = 8,
@@ -143,9 +156,41 @@ public:
return root_->extent_;
}
+ int count() const
+ {
+ return count_nodes(root_);
+ }
+
+ int count_items() const
+ {
+ int count = 0;
+ count_items(root_, count);
+ return count;
+ }
+ void trim()
+ {
+ trim_tree(root_);
+ }
+
+ template <typename OutputStream>
+ void write(OutputStream & out)
+ {
+ static_assert(std::is_standard_layout<value_type>::value,
+ "Values stored in quad-tree must be standard layout types to allow serialisation");
+ char header[16];
+ std::memset(header,0,16);
+ header[0]='m';
+ header[1]='a';
+ header[2]='p';
+ header[3]='n';
+ header[4]='i';
+ header[5]='k';
+ out.write(header,16);
+ write_node(out,root_);
+ }
private:
- void query_node(box2d<double> const& box, result_t & result, node * node_) const
+ void query_node(box2d<double> const& box, result_type & result, node * node_) const
{
if (node_)
{
@@ -208,10 +253,107 @@ private:
ext[3]=box2d<double>(hix - width * ratio_,hiy - height*ratio_,hix,hiy);
}
+ void trim_tree(node *& n)
+ {
+ if (n)
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ trim_tree(n->children_[i]);
+ }
+ if (n->num_subnodes() == 1 && n->cont_.size() == 0)
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ if (n->children_[i])
+ {
+ n = n->children_[i];
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ int count_nodes(node const* n) const
+ {
+ if (!n) return 0;
+ else
+ {
+ int count = 1;
+ for (int i = 0; i < 4; ++i)
+ {
+ count += count_nodes(n->children_[i]);
+ }
+ return count;
+ }
+ }
+
+ void count_items(node const* n,int& count) const
+ {
+ if (n)
+ {
+ count += n->cont_.size();
+ for (int i = 0; i < 4; ++i)
+ {
+ count_items(n->children_[i],count);
+ }
+ }
+ }
+
+ int subnode_offset(node const* n) const
+ {
+ int offset = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ if (n->children_[i])
+ {
+ offset +=sizeof(box2d<double>) + (n->children_[i]->cont_.size() * sizeof(value_type)) + 3 * sizeof(int);
+ offset +=subnode_offset(n->children_[i]);
+ }
+ }
+ return offset;
+ }
+
+ template <typename OutputStream>
+ void write_node(OutputStream & out, node const* n) const
+ {
+ if (n)
+ {
+ int offset=subnode_offset(n);
+ int shape_count=n->cont_.size();
+ int recsize=sizeof(box2d<double>) + 3 * sizeof(int) + shape_count * sizeof(value_type);
+ std::unique_ptr<char[]> node_record(new char[recsize]);
+ std::memset(node_record.get(), 0, recsize);
+ std::memcpy(node_record.get(), &offset, 4);
+ std::memcpy(node_record.get() + 4, &n->extent_, sizeof(box2d<double>));
+ std::memcpy(node_record.get() + 36, &shape_count, 4);
+ for (int i=0; i < shape_count; ++i)
+ {
+ memcpy(node_record.get() + 40 + i * sizeof(value_type), &(n->cont_[i]),sizeof(value_type));
+ }
+ int num_subnodes=0;
+ for (int i = 0; i < 4; ++i)
+ {
+ if (n->children_[i])
+ {
+ ++num_subnodes;
+ }
+ }
+ std::memcpy(node_record.get() + 40 + shape_count * sizeof(value_type),&num_subnodes,4);
+ out.write(node_record.get(),recsize);
+ for (int i = 0; i < 4; ++i)
+ {
+ write_node(out, n->children_[i]);
+ }
+ }
+ }
+
const unsigned int max_depth_;
const double ratio_;
- result_t query_result_;
- nodes_t nodes_;
+ result_type query_result_;
+ nodes_type nodes_;
node * root_;
};
diff --git a/include/mapnik/renderer_common/process_group_symbolizer.hpp b/include/mapnik/renderer_common/process_group_symbolizer.hpp
index d593b8e..edec308 100644
--- a/include/mapnik/renderer_common/process_group_symbolizer.hpp
+++ b/include/mapnik/renderer_common/process_group_symbolizer.hpp
@@ -329,7 +329,7 @@ void render_group_symbolizer(group_symbolizer const& sym,
// get the layout for this set of properties
for (auto const& rule : props->get_rules())
{
- if (util::apply_visitor(evaluate<Feature,value_type,attributes>(*sub_feature,common.vars_),
+ if (util::apply_visitor(evaluate<feature_impl,value_type,attributes>(*sub_feature,common.vars_),
*(rule->get_filter())).to_bool())
{
// add matched rule and feature to the list of things to draw
@@ -380,7 +380,7 @@ void render_group_symbolizer(group_symbolizer const& sym,
// evaluate the repeat key with the matched sub feature if we have one
if (rpt_key_expr)
{
- rpt_key_value = util::apply_visitor(evaluate<Feature,value_type,attributes>(*match_feature,common.vars_),
+ rpt_key_value = util::apply_visitor(evaluate<feature_impl,value_type,attributes>(*match_feature,common.vars_),
*rpt_key_expr).to_unicode();
}
helper.add_box_element(layout_manager.offset_box_at(i), rpt_key_value);
diff --git a/include/mapnik/simplify_converter.hpp b/include/mapnik/simplify_converter.hpp
index e217eba..f107a8d 100644
--- a/include/mapnik/simplify_converter.hpp
+++ b/include/mapnik/simplify_converter.hpp
@@ -268,11 +268,11 @@ private:
}
template <typename Iterator>
- bool fit_sleeve(Iterator itr,Iterator end, vertex2d const& v)
+ bool fit_sleeve(Iterator itr, Iterator itr_end, vertex2d const& v)
{
sleeve s(*itr,v,tolerance_);
++itr; // skip first vertex
- for (; itr!=end; ++itr)
+ for (; itr!=itr_end; ++itr)
{
if (!s.inside(*itr))
{
diff --git a/include/mapnik/text/placements/base.hpp b/include/mapnik/text/placements/base.hpp
index f83a547..0b93fb8 100644
--- a/include/mapnik/text/placements/base.hpp
+++ b/include/mapnik/text/placements/base.hpp
@@ -45,7 +45,7 @@ class MAPNIK_DECL text_placement_info : util::noncopyable
public:
// Constructor. Takes the parent text_placements object as a parameter
// to read defaults from it.
- text_placement_info(text_placements const* parent, double scale_factor_);
+ text_placement_info(text_placements const* parent, double _scale_factor);
// Get next placement.
// This function is also called before the first placement is tried.
// Each class has to return at least one position!
@@ -87,7 +87,7 @@ public:
// return text_placement_info_ptr(new text_placement_info_XXX(this));
// }
- virtual text_placement_info_ptr get_placement_info(double scale_factor, feature_impl const& feature, attributes const& vars) const = 0;
+ virtual text_placement_info_ptr get_placement_info(double _scale_factor, feature_impl const& feature, attributes const& vars) const = 0;
// Get a list of all expressions used in any placement.
// This function is used to collect attributes.
diff --git a/include/mapnik/text/placements/dummy.hpp b/include/mapnik/text/placements/dummy.hpp
index 036c5bd..e83808f 100644
--- a/include/mapnik/text/placements/dummy.hpp
+++ b/include/mapnik/text/placements/dummy.hpp
@@ -37,7 +37,7 @@ struct attribute;
class MAPNIK_DECL text_placements_dummy: public text_placements
{
public:
- text_placement_info_ptr get_placement_info(double scale_factor, feature_impl const& feature, attributes const& vars) const;
+ text_placement_info_ptr get_placement_info(double _scale_factor, feature_impl const& feature, attributes const& vars) const;
friend class text_placement_info_dummy;
};
@@ -45,8 +45,8 @@ public:
class MAPNIK_DECL text_placement_info_dummy : public text_placement_info
{
public:
- text_placement_info_dummy(text_placements_dummy const* parent, double scale_factor)
- : text_placement_info(parent, scale_factor),
+ text_placement_info_dummy(text_placements_dummy const* parent, double _scale_factor)
+ : text_placement_info(parent, _scale_factor),
state(0) {}
bool next() const;
private:
diff --git a/include/mapnik/text/placements/simple.hpp b/include/mapnik/text/placements/simple.hpp
index a489bea..ea0d73c 100644
--- a/include/mapnik/text/placements/simple.hpp
+++ b/include/mapnik/text/placements/simple.hpp
@@ -40,7 +40,7 @@ public:
text_placements_simple(symbolizer_base::value_type const& positions,
std::vector<directions_e> && direction,
std::vector<int> && text_sizes);
- text_placement_info_ptr get_placement_info(double scale_factor, feature_impl const& feature, attributes const& vars) const;
+ text_placement_info_ptr get_placement_info(double _scale_factor, feature_impl const& feature, attributes const& vars) const;
std::string get_positions() const;
static text_placements_ptr from_xml(xml_node const& xml, fontset_map const& fontsets, bool is_shield);
void init_positions(std::string const& positions) const;
@@ -58,7 +58,7 @@ class text_placement_info_simple : public text_placement_info
public:
text_placement_info_simple(text_placements_simple const* parent,
std::string const& evaluated_positions,
- double scale_factor);
+ double _scale_factor);
bool next() const;
protected:
bool next_position_only() const;
diff --git a/include/mapnik/util/singleton.hpp b/include/mapnik/util/singleton.hpp
index 94f8bf1..fcb0275 100644
--- a/include/mapnik/util/singleton.hpp
+++ b/include/mapnik/util/singleton.hpp
@@ -31,7 +31,10 @@
#include <new> // operator new
#include <type_traits>
#include <atomic>
+
+#ifdef MAPNIK_THREADSAFE
#include <mutex>
+#endif
namespace mapnik
{
@@ -97,7 +100,9 @@ template <typename T,
}
protected:
+#ifdef MAPNIK_THREADSAFE
static std::mutex mutex_;
+#endif
singleton() {}
public:
@@ -106,7 +111,9 @@ template <typename T,
T * tmp = pInstance_.load(std::memory_order_acquire);
if (tmp == nullptr)
{
+#ifdef MAPNIK_THREADSAFE
std::lock_guard<std::mutex> lock(mutex_);
+#endif
tmp = pInstance_.load(std::memory_order_relaxed);
if (tmp == nullptr)
{
@@ -130,8 +137,10 @@ template <typename T,
}
};
+#ifdef MAPNIK_THREADSAFE
template <typename T,
template <typename U> class CreatePolicy> std::mutex singleton<T,CreatePolicy>::mutex_;
+#endif
template <typename T,
template <typename U> class CreatePolicy> std::atomic<T*> singleton<T,CreatePolicy>::pInstance_;
template <typename T,
diff --git a/include/mapnik/util/spatial_index.hpp b/include/mapnik/util/spatial_index.hpp
new file mode 100644
index 0000000..021bed5
--- /dev/null
+++ b/include/mapnik/util/spatial_index.hpp
@@ -0,0 +1,155 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2015 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
+ *
+ *****************************************************************************/
+
+#ifndef MAPNIK_UTIL_SPATIAL_INDEX_HPP
+#define MAPNIK_UTIL_SPATIAL_INDEX_HPP
+
+//mapnik
+#include <mapnik/coord.hpp>
+#include <mapnik/box2d.hpp>
+#include <mapnik/query.hpp>
+#include <mapnik/geom_util.hpp>
+// stl
+#include <type_traits>
+
+using mapnik::box2d;
+using mapnik::query;
+
+namespace mapnik { namespace util {
+
+template <typename Value, typename Filter, typename InputStream>
+class spatial_index
+{
+public:
+ static void query(Filter const& filter, InputStream& in,std::vector<Value>& pos);
+ static box2d<double> bounding_box( InputStream& in );
+ static void query_first_n(Filter const& filter, InputStream & in, std::vector<Value>& pos, std::size_t count);
+private:
+
+ spatial_index();
+ ~spatial_index();
+ spatial_index(spatial_index const&);
+ spatial_index& operator=(spatial_index const&);
+ static int read_ndr_integer(InputStream& in);
+ static void read_envelope(InputStream& in, box2d<double>& envelope);
+ static void query_node(Filter const& filter, InputStream& in, std::vector<Value> & results);
+ static void query_first_n_impl(Filter const& filter, InputStream& in, std::vector<Value> & results, std::size_t count);
+};
+
+template <typename Value, typename Filter, typename InputStream>
+box2d<double> spatial_index<Value, Filter, InputStream>::bounding_box(InputStream& in)
+{
+ static_assert(std::is_standard_layout<Value>::value, "Values stored in quad-tree must be standard layout type");
+ in.seekg(16 + 4, std::ios::beg);
+ box2d<double> box;
+ read_envelope(in, box);
+ in.seekg(0, std::ios::beg);
+ return box;
+}
+
+template <typename Value, typename Filter, typename InputStream>
+void spatial_index<Value, Filter, InputStream>::query(Filter const& filter, InputStream& in, std::vector<Value>& results)
+{
+ static_assert(std::is_standard_layout<Value>::value, "Values stored in quad-tree must be standard layout types");
+ in.seekg(16, std::ios::beg);
+ query_node(filter, in, results);
+}
+
+template <typename Value, typename Filter, typename InputStream>
+void spatial_index<Value, Filter, InputStream>::query_node(Filter const& filter, InputStream& in, std::vector<Value>& results)
+{
+ int offset = read_ndr_integer(in);
+ box2d<double> node_ext;
+ read_envelope(in, node_ext);
+ int num_shapes = read_ndr_integer(in);
+ if (!filter.pass(node_ext))
+ {
+ in.seekg(offset + num_shapes * sizeof(Value) + 4, std::ios::cur);
+ return;
+ }
+
+ for (int i = 0; i < num_shapes; ++i)
+ {
+ Value item;
+ in.read(reinterpret_cast<char*>(&item), sizeof(Value));
+ results.push_back(std::move(item));
+ }
+
+ int children = read_ndr_integer(in);
+ for (int j = 0; j < children; ++j)
+ {
+ query_node(filter, in, results);
+ }
+}
+
+template <typename Value, typename Filter, typename InputStream>
+void spatial_index<Value, Filter, InputStream>::query_first_n(Filter const& filter, InputStream& in, std::vector<Value>& results, std::size_t count)
+{
+ static_assert(std::is_standard_layout<Value>::value, "Values stored in quad-tree must be standard layout types");
+ in.seekg(16, std::ios::beg);
+ query_first_n_impl(filter, in, results, count);
+}
+
+template <typename Value, typename Filter, typename InputStream>
+void spatial_index<Value, Filter, InputStream>::query_first_n_impl(Filter const& filter, InputStream& in, std::vector<Value>& results, std::size_t count)
+{
+ if (results.size() == count) return;
+ int offset = read_ndr_integer(in);
+ box2d<double> node_ext;
+ read_envelope(in, node_ext);
+ int num_shapes = read_ndr_integer(in);
+ if (!filter.pass(node_ext))
+ {
+ in.seekg(offset + num_shapes * sizeof(Value) + 4, std::ios::cur);
+ return;
+ }
+
+ for (int i = 0; i < num_shapes; ++i)
+ {
+ Value item;
+ in.read(reinterpret_cast<char*>(&item), sizeof(Value));
+ if (results.size() < count) results.push_back(std::move(item));
+ }
+ int children = read_ndr_integer(in);
+ for (int j = 0; j < children; ++j)
+ {
+ query_first_n_impl(filter, in, results, count);
+ }
+}
+
+template <typename Value, typename Filter, typename InputStream>
+int spatial_index<Value, Filter, InputStream>::read_ndr_integer(InputStream& in)
+{
+ char b[4];
+ in.read(b, 4);
+ return (b[0] & 0xff) | (b[1] & 0xff) << 8 | (b[2] & 0xff) << 16 | (b[3] & 0xff) << 24;
+}
+
+template <typename Value, typename Filter, typename InputStream>
+void spatial_index<Value, Filter, InputStream>::read_envelope(InputStream& in, box2d<double>& envelope)
+{
+ in.read(reinterpret_cast<char*>(&envelope), sizeof(envelope));
+}
+
+}} // mapnik/util
+
+#endif // MAPNIK_UTIL_SPATIAL_INDEX_HPP
diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp
index a56d76f..1041d94 100644
--- a/include/mapnik/value.hpp
+++ b/include/mapnik/value.hpp
@@ -72,42 +72,41 @@ using value_base = util::variant<value_null, value_bool, value_integer,value_dou
namespace impl {
struct equals
-
{
bool operator() (value_integer lhs, value_double rhs) const
{
- return lhs == rhs;
+ return static_cast<value_double>(lhs) == rhs;
}
bool operator() (value_bool lhs, value_double rhs) const
{
- return lhs == rhs;
+ return static_cast<value_double>(lhs) == rhs;
}
bool operator() (value_double lhs, value_integer rhs) const
{
- return lhs == rhs;
+ return lhs == static_cast<value_double>(rhs);
}
bool operator() (value_bool lhs, value_integer rhs) const
{
- return lhs == rhs;
+ return static_cast<value_integer>(lhs) == rhs;
}
bool operator() (value_integer lhs, value_bool rhs) const
{
- return lhs == rhs;
+ return lhs == static_cast<value_integer>(rhs);
}
bool operator() (value_double lhs, value_bool rhs) const
{
- return lhs == rhs;
+ return static_cast<value_double>(lhs) == rhs;
}
bool operator() (value_unicode_string const& lhs,
value_unicode_string const& rhs) const
{
- return (lhs == rhs) ? true: false;
+ return (lhs == rhs) ? true: false;
}
template <typename T>
@@ -140,32 +139,32 @@ struct not_equals
bool operator() (value_integer lhs, value_double rhs) const
{
- return lhs != rhs;
+ return static_cast<value_double>(lhs) != rhs;
}
bool operator() (value_bool lhs, value_double rhs) const
{
- return lhs != rhs;
+ return static_cast<value_double>(lhs) != rhs;
}
bool operator() (value_double lhs, value_integer rhs) const
{
- return lhs != rhs;
+ return lhs != static_cast<value_double>(rhs);
}
bool operator() (value_bool lhs, value_integer rhs) const
{
- return lhs != rhs;
+ return static_cast<value_integer>(lhs) != rhs;
}
bool operator() (value_integer lhs, value_bool rhs) const
{
- return lhs != rhs;
+ return lhs != static_cast<value_integer>(rhs);
}
bool operator() (value_double lhs, value_bool rhs) const
{
- return lhs != rhs;
+ return lhs != static_cast<value_double>(rhs);
}
bool operator() (value_unicode_string const& lhs,
@@ -993,8 +992,8 @@ inline bool value::is_null() const
namespace std
{
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmismatched-tags"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmismatched-tags"
template <>
struct hash<mapnik::value>
@@ -1005,7 +1004,7 @@ struct hash<mapnik::value>
}
};
-#pragma clang diagnostic pop
+#pragma GCC diagnostic pop
}
diff --git a/include/mapnik/version.hpp b/include/mapnik/version.hpp
index 161b708..ad784d0 100644
--- a/include/mapnik/version.hpp
+++ b/include/mapnik/version.hpp
@@ -27,7 +27,7 @@
#define MAPNIK_MAJOR_VERSION 3
#define MAPNIK_MINOR_VERSION 0
-#define MAPNIK_PATCH_VERSION 5
+#define MAPNIK_PATCH_VERSION 6
#define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION)
diff --git a/include/mapnik/webp_io.hpp b/include/mapnik/webp_io.hpp
index 978e6cf..b16a891 100644
--- a/include/mapnik/webp_io.hpp
+++ b/include/mapnik/webp_io.hpp
@@ -28,13 +28,13 @@
#include <mapnik/util/conversions.hpp>
// webp
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-function"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
extern "C"
{
#include <webp/encode.h>
}
-#pragma clang diagnostic pop
+#pragma GCC diagnostic pop
// stl
#include <algorithm>
diff --git a/plugins/input/csv/build.py b/plugins/input/csv/build.py
index 2694109..f21c93f 100644
--- a/plugins/input/csv/build.py
+++ b/plugins/input/csv/build.py
@@ -42,18 +42,19 @@ else:
%(PLUGIN_NAME)s_datasource.cpp
%(PLUGIN_NAME)s_featureset.cpp
%(PLUGIN_NAME)s_inline_featureset.cpp
+ %(PLUGIN_NAME)s_index_featureset.cpp
""" % locals()
)
# Link Library to Dependencies
libraries = []
- libraries.append('boost_system%s' % env['BOOST_APPEND'])
- libraries.append(env['ICU_LIB_NAME'])
libraries.append('mapnik-json')
libraries.append('mapnik-wkt')
if env['PLUGIN_LINKING'] == 'shared':
- libraries.append(env['MAPNIK_NAME'])
+ libraries.append('boost_system%s' % env['BOOST_APPEND'])
+ libraries.insert(0,env['MAPNIK_NAME'])
+ libraries.append(env['ICU_LIB_NAME'])
TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME,
SHLIBPREFIX='',
diff --git a/plugins/input/csv/csv_datasource.cpp b/plugins/input/csv/csv_datasource.cpp
index 8b15fc9..8da4691 100644
--- a/plugins/input/csv/csv_datasource.cpp
+++ b/plugins/input/csv/csv_datasource.cpp
@@ -24,6 +24,7 @@
#include "csv_datasource.hpp"
#include "csv_featureset.hpp"
#include "csv_inline_featureset.hpp"
+#include "csv_index_featureset.hpp"
// boost
#include <boost/algorithm/string.hpp>
// mapnik
@@ -37,10 +38,16 @@
#include <mapnik/util/trim.hpp>
#include <mapnik/util/geometry_to_ds_type.hpp>
#include <mapnik/value_types.hpp>
-
+#include <mapnik/util/fs.hpp>
+#include <mapnik/util/spatial_index.hpp>
+#include <mapnik/geom_util.hpp>
#ifdef CSV_MEMORY_MAPPED_FILE
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
+#pragma GCC diagnostic pop
#include <mapnik/mapped_memory_cache.hpp>
#endif
@@ -56,13 +63,6 @@ using mapnik::parameters;
DATASOURCE_PLUGIN(csv_datasource)
-
-namespace {
-
-using cvs_value = mapnik::util::variant<std::string, mapnik::value_integer, mapnik::value_double, mapnik::value_bool>;
-
-}
-
csv_datasource::csv_datasource(parameters const& params)
: datasource(params),
desc_(csv_datasource::name(), *params.get<std::string>("encoding", "utf-8")),
@@ -70,17 +70,31 @@ csv_datasource::csv_datasource(parameters const& params)
filename_(),
row_limit_(*params.get<mapnik::value_integer>("row_limit", 0)),
inline_string_(),
- escape_(*params.get<std::string>("escape", "")),
- separator_(*params.get<std::string>("separator", "")),
- quote_(*params.get<std::string>("quote", "")),
+ separator_(0),
+ quote_(0),
headers_(),
manual_headers_(mapnik::util::trim_copy(*params.get<std::string>("headers", ""))),
strict_(*params.get<mapnik::boolean_type>("strict", false)),
ctx_(std::make_shared<mapnik::context_type>()),
extent_initialized_(false),
tree_(nullptr),
- locator_()
+ locator_(),
+ has_disk_index_(false)
{
+ auto quote_param = params.get<std::string>("quote");
+ if (quote_param)
+ {
+ auto val = mapnik::util::trim_copy(*quote_param);
+ if (!val.empty()) quote_ = val.front(); // we pick pick first non-space char
+ }
+
+ auto separator_param = params.get<std::string>("separator");
+ if (separator_param)
+ {
+ auto val = mapnik::util::trim_copy(*separator_param);
+ if (!val.empty()) separator_ = val.front();
+ }
+
boost::optional<std::string> ext = params.get<std::string>("extent");
if (ext && !ext->empty())
{
@@ -101,11 +115,13 @@ csv_datasource::csv_datasource(parameters const& params)
filename_ = *base + "/" + *file;
else
filename_ = *file;
+
+ has_disk_index_ = mapnik::util::exists(filename_ + ".index");
}
if (!inline_string_.empty())
{
std::istringstream in(inline_string_);
- parse_csv(in, escape_, separator_, quote_);
+ parse_csv(in);
}
else
{
@@ -137,7 +153,18 @@ csv_datasource::csv_datasource(parameters const& params)
throw mapnik::datasource_exception("CSV Plugin: could not open: '" + filename_ + "'");
}
#endif
- parse_csv(in, escape_, separator_, quote_);
+ parse_csv(in);
+
+ if (has_disk_index_ && !extent_initialized_)
+ {
+ // read bounding box from *.index
+ using value_type = std::pair<std::size_t, std::size_t>;
+ std::ifstream index(filename_ + ".index", std::ios::binary);
+ if (!index) throw mapnik::datasource_exception("CSV Plugin: could not open: '" + filename_ + ".index'");
+ extent_ = mapnik::util::spatial_index<value_type,
+ mapnik::filter_in_box,
+ std::ifstream>::bounding_box(index);
+ }
//in.close(); no need to call close, rely on dtor
}
}
@@ -145,60 +172,47 @@ csv_datasource::csv_datasource(parameters const& params)
csv_datasource::~csv_datasource() {}
template <typename T>
-void csv_datasource::parse_csv(T & stream,
- std::string const& escape,
- std::string const& separator,
- std::string const& quote)
+void csv_datasource::parse_csv(T & stream)
{
auto file_length = detail::file_length(stream);
// set back to start
stream.seekg(0, std::ios::beg);
char newline;
bool has_newline;
- std::tie(newline, has_newline) = detail::autodect_newline(stream, file_length);
+ char detected_quote;
+ std::tie(newline, has_newline, detected_quote) = detail::autodect_newline_and_quote(stream, file_length);
+ if (quote_ == 0) quote_ = detected_quote;
// set back to start
stream.seekg(0, std::ios::beg);
- // get first line
std::string csv_line;
- std::getline(stream,csv_line,stream.widen(newline));
- // if user has not passed a separator manually
- // then attempt to detect by reading first line
-
- std::string sep = mapnik::util::trim_copy(separator);
- if (sep.empty()) sep = detail::detect_separator(csv_line);
- separator_ = sep;
+ csv_utils::getline_csv(stream, csv_line, newline, quote_);
+ if (separator_ == 0)
+ {
+ separator_ = detail::detect_separator(csv_line);
+ }
- // set back to start
+ MAPNIK_LOG_DEBUG(csv) << "csv_datasource: separator: '" << separator_
+ << "' quote: '" << quote_ << "'";
stream.seekg(0, std::ios::beg);
- std::string esc = mapnik::util::trim_copy(escape);
- if (esc.empty()) esc = "\\";
-
- std::string quo = mapnik::util::trim_copy(quote);
- if (quo.empty()) quo = "\"";
-
- MAPNIK_LOG_DEBUG(csv) << "csv_datasource: csv grammar: sep: '" << sep
- << "' quo: '" << quo << "' esc: '" << esc << "'";
-
int line_number = 1;
if (!manual_headers_.empty())
{
std::size_t index = 0;
- auto headers = csv_utils::parse_line(manual_headers_, sep);
+ auto headers = csv_utils::parse_line(manual_headers_, separator_, quote_);
for (auto const& header : headers)
{
- std::string val = mapnik::util::trim_copy(header);
- detail::locate_geometry_column(val, index++, locator_);
- headers_.push_back(val);
+ detail::locate_geometry_column(header, index++, locator_);
+ headers_.push_back(header);
}
}
else // parse first line as headers
{
- while (std::getline(stream,csv_line,stream.widen(newline)))
+ while (csv_utils::getline_csv(stream, csv_line, newline, quote_))
{
try
{
- auto headers = csv_utils::parse_line(csv_line, sep);
+ auto headers = csv_utils::parse_line(csv_line, separator_, quote_);
// skip blank lines
std::string val;
if (headers.size() > 0 && headers[0].empty()) ++line_number;
@@ -261,11 +275,12 @@ void csv_datasource::parse_csv(T & stream,
[ & ](std::string const& header){ ctx_->push(header); });
mapnik::transcoder tr(desc_.get_encoding());
- auto pos = stream.tellg();
+ auto pos = stream.tellg();
// handle rare case of a single line of data and user-provided headers
- // where a lack of a newline will mean that std::getline returns false
+ // where a lack of a newline will mean that csv_utils::getline_csv returns false
bool is_first_row = false;
+
if (!has_newline)
{
stream.setstate(std::ios::failbit);
@@ -275,9 +290,11 @@ void csv_datasource::parse_csv(T & stream,
is_first_row = true;
}
}
+
std::vector<item_type> boxes;
- while (is_first_row || std::getline(stream, csv_line, stream.widen(newline)))
+ while (is_first_row || csv_utils::getline_csv(stream, csv_line, newline, quote_))
{
+
if ((row_limit_ > 0) && (line_number++ > row_limit_))
{
MAPNIK_LOG_DEBUG(csv) << "csv_datasource: row limit hit, exiting at feature: " << feature_count;
@@ -287,9 +304,9 @@ void csv_datasource::parse_csv(T & stream,
auto record_size = csv_line.length();
pos = stream.tellg();
is_first_row = false;
+
// skip blank lines
- unsigned line_length = csv_line.length();
- if (line_length <= 10)
+ if (record_size <= 10)
{
std::string trimmed = csv_line;
boost::trim_if(trimmed,boost::algorithm::is_any_of("\",'\r\n "));
@@ -302,9 +319,9 @@ void csv_datasource::parse_csv(T & stream,
try
{
- auto values = csv_utils::parse_line(csv_line, sep);
+ auto values = csv_utils::parse_line(csv_line, separator_, quote_);
unsigned num_fields = values.size();
- if (num_fields > num_headers)
+ if (num_fields > num_headers || num_fields < num_headers)
{
std::ostringstream s;
s << "CSV Plugin: # of columns("
@@ -312,21 +329,6 @@ void csv_datasource::parse_csv(T & stream,
<< num_headers << ") parsed for row " << line_number << "\n";
throw mapnik::datasource_exception(s.str());
}
- else if (num_fields < num_headers)
- {
- std::ostringstream s;
- s << "CSV Plugin: # of headers("
- << num_headers << ") > # of columns("
- << num_fields << ") parsed for row " << line_number << "\n";
- if (strict_)
- {
- throw mapnik::datasource_exception(s.str());
- }
- else
- {
- MAPNIK_LOG_WARN(csv) << s.str();
- }
- }
auto geom = detail::extract_geometry(values, locator_);
if (!geom.is<mapnik::geometry::geometry_empty>())
@@ -430,14 +432,7 @@ void csv_datasource::parse_csv(T & stream,
s << "CSV Plugin: expected geometry column: could not parse row "
<< line_number << " "
<< values[locator_.index] << "'";
- if (strict_)
- {
- throw mapnik::datasource_exception(s.str());
- }
- else
- {
- MAPNIK_LOG_ERROR(csv) << s.str();
- }
+ throw mapnik::datasource_exception(s.str());
}
}
catch (mapnik::datasource_exception const& ex )
@@ -463,6 +458,8 @@ void csv_datasource::parse_csv(T & stream,
MAPNIK_LOG_ERROR(csv) << s.str();
}
}
+ // return early if *.index is present
+ if (has_disk_index_) return;
}
// bulk insert initialise r-tree
tree_ = std::make_unique<spatial_index_type>(boxes);
@@ -492,40 +489,87 @@ template <typename T>
boost::optional<mapnik::datasource_geometry_t> csv_datasource::get_geometry_type_impl(T & stream) const
{
boost::optional<mapnik::datasource_geometry_t> result;
- int multi_type = 0;
- auto itr = tree_->qbegin(boost::geometry::index::intersects(extent_));
- auto end = tree_->qend();
- for (std::size_t count = 0; itr !=end && count < 5; ++itr, ++count)
+ if (tree_)
{
- csv_datasource::item_type const& item = *itr;
- std::size_t file_offset = item.second.first;
- std::size_t size = item.second.second;
- stream.seekg(file_offset);
- std::vector<char> record;
- record.resize(size);
- stream.read(record.data(), size);
- std::string str(record.begin(), record.end());
- try
+ int multi_type = 0;
+ auto itr = tree_->qbegin(boost::geometry::index::intersects(extent_));
+ auto end = tree_->qend();
+ for (std::size_t count = 0; itr !=end && count < 5; ++itr, ++count)
{
- auto values = csv_utils::parse_line(str, separator_);
- auto geom = detail::extract_geometry(values, locator_);
- result = mapnik::util::to_ds_type(geom);
- if (result)
+ csv_datasource::item_type const& item = *itr;
+ std::size_t file_offset = item.second.first;
+ std::size_t size = item.second.second;
+ stream.seekg(file_offset);
+ std::vector<char> record;
+ record.resize(size);
+ stream.read(record.data(), size);
+ std::string str(record.begin(), record.end());
+ try
{
- int type = static_cast<int>(*result);
- if (multi_type > 0 && multi_type != type)
+ auto values = csv_utils::parse_line(str, separator_, quote_);
+ auto geom = detail::extract_geometry(values, locator_);
+ result = mapnik::util::to_ds_type(geom);
+ if (result)
{
- result.reset(mapnik::datasource_geometry_t::Collection);
- return result;
+ int type = static_cast<int>(*result);
+ if (multi_type > 0 && multi_type != type)
+ {
+ result.reset(mapnik::datasource_geometry_t::Collection);
+ return result;
+ }
+ multi_type = type;
}
- multi_type = type;
+ }
+ catch (std::exception const& ex)
+ {
+ if (strict_) throw ex;
+ else MAPNIK_LOG_ERROR(csv) << ex.what();
}
}
- catch (std::exception const& ex)
+ }
+ else
+ {
+ // try reading *.index
+ using value_type = std::pair<std::size_t, std::size_t>;
+ std::ifstream index(filename_ + ".index", std::ios::binary);
+ if (!index) throw mapnik::datasource_exception("CSV Plugin: could not open: '" + filename_ + ".index'");
+
+ mapnik::filter_in_box filter(extent_);
+ std::vector<value_type> positions;
+ mapnik::util::spatial_index<value_type,
+ mapnik::filter_in_box,
+ std::ifstream>::query_first_n(filter, index, positions, 5);
+ int multi_type = 0;
+ for (auto const& val : positions)
{
- if (strict_) throw ex;
- else MAPNIK_LOG_ERROR(csv) << ex.what();
+ stream.seekg(val.first);
+ std::vector<char> record;
+ record.resize(val.second);
+ stream.read(record.data(), val.second);
+ std::string str(record.begin(), record.end());
+ try
+ {
+ auto values = csv_utils::parse_line(str, separator_, quote_);
+ auto geom = detail::extract_geometry(values, locator_);
+ result = mapnik::util::to_ds_type(geom);
+ if (result)
+ {
+ int type = static_cast<int>(*result);
+ if (multi_type > 0 && multi_type != type)
+ {
+ result.reset(mapnik::datasource_geometry_t::Collection);
+ return result;
+ }
+ multi_type = type;
+ }
+ }
+ catch (std::exception const& ex)
+ {
+ if (strict_) throw ex;
+ else MAPNIK_LOG_ERROR(csv) << ex.what();
+ }
}
+
}
return result;
}
@@ -554,7 +598,6 @@ boost::optional<mapnik::datasource_geometry_t> csv_datasource::get_geometry_type
mapnik::featureset_ptr csv_datasource::features(mapnik::query const& q) const
{
-
for (auto const& name : q.property_names())
{
bool found_name = false;
@@ -589,13 +632,18 @@ mapnik::featureset_ptr csv_datasource::features(mapnik::query const& q) const
});
if (inline_string_.empty())
{
- return std::make_shared<csv_featureset>(filename_, locator_, separator_, headers_, ctx_, std::move(index_array));
+ return std::make_shared<csv_featureset>(filename_, locator_, separator_, quote_, headers_, ctx_, std::move(index_array));
}
else
{
- return std::make_shared<csv_inline_featureset>(inline_string_, locator_, separator_, headers_, ctx_, std::move(index_array));
+ return std::make_shared<csv_inline_featureset>(inline_string_, locator_, separator_, quote_, headers_, ctx_, std::move(index_array));
}
}
+ else if (has_disk_index_)
+ {
+ mapnik::filter_in_box filter(q.get_bbox());
+ return std::make_shared<csv_index_featureset>(filename_, filter, locator_, separator_, quote_, headers_, ctx_);
+ }
}
return mapnik::featureset_ptr();
}
diff --git a/plugins/input/csv/csv_datasource.hpp b/plugins/input/csv/csv_datasource.hpp
index 06b5daf..3faf0cf 100644
--- a/plugins/input/csv/csv_datasource.hpp
+++ b/plugins/input/csv/csv_datasource.hpp
@@ -88,14 +88,10 @@ public:
mapnik::box2d<double> envelope() const;
mapnik::layer_descriptor get_descriptor() const;
boost::optional<mapnik::datasource_geometry_t> get_geometry_type() const;
- template <typename T>
- void parse_csv(T & stream,
- std::string const& escape,
- std::string const& separator,
- std::string const& quote);
-
private:
template <typename T>
+ void parse_csv(T & stream);
+ template <typename T>
boost::optional<mapnik::datasource_geometry_t> get_geometry_type_impl(T & stream) const;
mapnik::layer_descriptor desc_;
@@ -103,9 +99,8 @@ private:
std::string filename_;
mapnik::value_integer row_limit_;
std::string inline_string_;
- std::string escape_;
- std::string separator_;
- std::string quote_;
+ char separator_;
+ char quote_;
std::vector<std::string> headers_;
std::string manual_headers_;
bool strict_;
@@ -113,6 +108,7 @@ private:
bool extent_initialized_;
std::unique_ptr<spatial_index_type> tree_;
detail::geometry_column_locator locator_;
+ bool has_disk_index_;
};
#endif // MAPNIK_CSV_DATASOURCE_HPP
diff --git a/plugins/input/csv/csv_featureset.cpp b/plugins/input/csv/csv_featureset.cpp
index acda58e..8a94875 100644
--- a/plugins/input/csv/csv_featureset.cpp
+++ b/plugins/input/csv/csv_featureset.cpp
@@ -31,7 +31,7 @@
#include <vector>
#include <deque>
-csv_featureset::csv_featureset(std::string const& filename, detail::geometry_column_locator const& locator, std::string const& separator,
+csv_featureset::csv_featureset(std::string const& filename, detail::geometry_column_locator const& locator, char separator, char quote,
std::vector<std::string> const& headers, mapnik::context_ptr const& ctx, array_type && index_array)
:
#if defined(CSV_MEMORY_MAPPED_FILE)
@@ -42,6 +42,7 @@ csv_featureset::csv_featureset(std::string const& filename, detail::geometry_col
file_(std::fopen(filename.c_str(),"rb"), std::fclose),
#endif
separator_(separator),
+ quote_(quote),
headers_(headers),
index_array_(std::move(index_array)),
index_itr_(index_array_.begin()),
@@ -70,7 +71,7 @@ csv_featureset::~csv_featureset() {}
mapnik::feature_ptr csv_featureset::parse_feature(char const* beg, char const* end)
{
- auto values = csv_utils::parse_line(beg, end, separator_, headers_.size());
+ auto values = csv_utils::parse_line(beg, end, separator_, quote_, headers_.size());
auto geom = detail::extract_geometry(values, locator_);
if (!geom.is<mapnik::geometry::geometry_empty>())
{
diff --git a/plugins/input/csv/csv_featureset.hpp b/plugins/input/csv/csv_featureset.hpp
index 59afa1d..3f05c08 100644
--- a/plugins/input/csv/csv_featureset.hpp
+++ b/plugins/input/csv/csv_featureset.hpp
@@ -31,20 +31,24 @@
#include <cstdio>
#ifdef CSV_MEMORY_MAPPED_FILE
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
+#pragma GCC diagnostic pop
#include <mapnik/mapped_memory_cache.hpp>
#endif
class csv_featureset : public mapnik::Featureset
{
-
using locator_type = detail::geometry_column_locator;
public:
using array_type = std::deque<csv_datasource::item_type>;
csv_featureset(std::string const& filename,
locator_type const& locator,
- std::string const& separator,
+ char separator,
+ char quote,
std::vector<std::string> const& headers,
mapnik::context_ptr const& ctx,
array_type && index_array);
@@ -59,7 +63,8 @@ private:
using file_ptr = std::unique_ptr<std::FILE, int (*)(std::FILE *)>;
file_ptr file_;
#endif
- std::string const& separator_;
+ char separator_;
+ char quote_;
std::vector<std::string> const& headers_;
const array_type index_array_;
array_type::const_iterator index_itr_;
diff --git a/plugins/input/csv/csv_index_featureset.cpp b/plugins/input/csv/csv_index_featureset.cpp
new file mode 100644
index 0000000..4a13551
--- /dev/null
+++ b/plugins/input/csv/csv_index_featureset.cpp
@@ -0,0 +1,130 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2015 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
+ *
+ *****************************************************************************/
+
+// mapnik
+#include "csv_index_featureset.hpp"
+#include <mapnik/debug.hpp>
+#include <mapnik/feature.hpp>
+#include <mapnik/feature_factory.hpp>
+#include <mapnik/util/utf_conv_win.hpp>
+#include <mapnik/util/trim.hpp>
+#include <mapnik/util/spatial_index.hpp>
+#include <mapnik/geometry.hpp>
+// stl
+#include <string>
+#include <vector>
+#include <deque>
+#include <fstream>
+
+csv_index_featureset::csv_index_featureset(std::string const& filename,
+ mapnik::filter_in_box const& filter,
+ detail::geometry_column_locator const& locator,
+ char separator,
+ char quote,
+ std::vector<std::string> const& headers,
+ mapnik::context_ptr const& ctx)
+ : separator_(separator),
+ quote_(quote),
+ headers_(headers),
+ ctx_(ctx),
+ locator_(locator),
+ tr_("utf8")
+#if defined(CSV_MEMORY_MAPPED_FILE)
+ //
+#elif defined( _WINDOWS)
+ ,file_(_wfopen(mapnik::utf8_to_utf16(filename).c_str(), L"rb"), std::fclose)
+#else
+ ,file_(std::fopen(filename.c_str(),"rb"), std::fclose)
+#endif
+
+{
+#if defined (CSV_MEMORY_MAPPED_FILE)
+ boost::optional<mapnik::mapped_region_ptr> memory =
+ mapnik::mapped_memory_cache::instance().find(filename, true);
+ if (memory)
+ {
+ mapped_region_ = *memory;
+ }
+ else
+ {
+ throw std::runtime_error("could not create file mapping for " + filename);
+ }
+#else
+ if (!file_) throw mapnik::datasource_exception("CSV Plugin: can't open file " + filename);
+#endif
+
+ std::string indexname = filename + ".index";
+ std::ifstream index(indexname.c_str(), std::ios::binary);
+ if (!index) throw mapnik::datasource_exception("CSV Plugin: can't open index file " + indexname);
+ mapnik::util::spatial_index<value_type,
+ mapnik::filter_in_box,
+ std::ifstream>::query(filter, index, positions_);
+
+ std::sort(positions_.begin(), positions_.end(),
+ [](value_type const& lhs, value_type const& rhs) { return lhs.first < rhs.first;});
+ itr_ = positions_.begin();
+}
+
+csv_index_featureset::~csv_index_featureset() {}
+
+mapnik::feature_ptr csv_index_featureset::parse_feature(char const* beg, char const* end)
+{
+ auto values = csv_utils::parse_line(beg, end, separator_, quote_, headers_.size());
+ auto geom = detail::extract_geometry(values, locator_);
+ if (!geom.is<mapnik::geometry::geometry_empty>())
+ {
+ mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_, ++feature_id_));
+ feature->set_geometry(std::move(geom));
+ detail::process_properties(*feature, headers_, values, locator_, tr_);
+ return feature;
+ }
+ return mapnik::feature_ptr();
+}
+
+mapnik::feature_ptr csv_index_featureset::next()
+{
+ /*
+ if (row_limit_ && count_ >= row_limit_)
+ {
+ return feature_ptr();
+ }
+ */
+
+ while( itr_ != positions_.end())
+ {
+ auto pos = *itr_++;
+#if defined(CSV_MEMORY_MAPPED_FILE)
+ char const* start = (char const*)mapped_region_->get_address() + pos.first;
+ char const* end = start + pos.second;
+#else
+ std::fseek(file_.get(), pos.first, SEEK_SET);
+ std::vector<char> record;
+ record.resize(pos.second);
+ std::fread(record.data(), pos.second, 1, file_.get());
+ auto const* start = record.data();
+ auto const* end = start + record.size();
+#endif
+ auto feature = parse_feature(start, end);
+ if (feature) return feature;
+ }
+ return mapnik::feature_ptr();
+}
diff --git a/plugins/input/csv/csv_featureset.hpp b/plugins/input/csv/csv_index_featureset.hpp
similarity index 66%
copy from plugins/input/csv/csv_featureset.hpp
copy to plugins/input/csv/csv_index_featureset.hpp
index 59afa1d..5980afb 100644
--- a/plugins/input/csv/csv_featureset.hpp
+++ b/plugins/input/csv/csv_index_featureset.hpp
@@ -20,38 +20,49 @@
*
*****************************************************************************/
-#ifndef CSV_FEATURESET_HPP
-#define CSV_FEATURESET_HPP
+#ifndef CSV_INDEX_FEATURESET_HPP
+#define CSV_INDEX_FEATURESET_HPP
#include <mapnik/feature.hpp>
#include <mapnik/unicode.hpp>
+#include <mapnik/geom_util.hpp>
#include "csv_utils.hpp"
#include "csv_datasource.hpp"
-#include <deque>
-#include <cstdio>
#ifdef CSV_MEMORY_MAPPED_FILE
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
+#pragma GCC diagnostic pop
#include <mapnik/mapped_memory_cache.hpp>
#endif
-class csv_featureset : public mapnik::Featureset
+class csv_index_featureset : public mapnik::Featureset
{
-
+ using value_type = std::pair<std::size_t, std::size_t>;
using locator_type = detail::geometry_column_locator;
public:
- using array_type = std::deque<csv_datasource::item_type>;
- csv_featureset(std::string const& filename,
- locator_type const& locator,
- std::string const& separator,
- std::vector<std::string> const& headers,
- mapnik::context_ptr const& ctx,
- array_type && index_array);
- ~csv_featureset();
+
+ csv_index_featureset(std::string const& filename,
+ mapnik::filter_in_box const& filter,
+ locator_type const& locator,
+ char separator,
+ char quote,
+ std::vector<std::string> const& headers,
+ mapnik::context_ptr const& ctx);
+ ~csv_index_featureset();
mapnik::feature_ptr next();
private:
mapnik::feature_ptr parse_feature(char const* beg, char const* end);
+ char separator_;
+ char quote_;
+ std::vector<std::string> headers_;
+ mapnik::context_ptr ctx_;
+ mapnik::value_integer feature_id_ = 0;
+ detail::geometry_column_locator const& locator_;
+ mapnik::transcoder tr_;
#if defined (CSV_MEMORY_MAPPED_FILE)
using file_source_type = boost::interprocess::ibufferstream;
mapnik::mapped_region_ptr mapped_region_;
@@ -59,16 +70,9 @@ private:
using file_ptr = std::unique_ptr<std::FILE, int (*)(std::FILE *)>;
file_ptr file_;
#endif
- std::string const& separator_;
- std::vector<std::string> const& headers_;
- const array_type index_array_;
- array_type::const_iterator index_itr_;
- array_type::const_iterator index_end_;
- mapnik::context_ptr ctx_;
- mapnik::value_integer feature_id_ = 0;
- detail::geometry_column_locator const& locator_;
- mapnik::transcoder tr_;
+ std::vector<value_type> positions_;
+ std::vector<value_type>::iterator itr_;
};
-#endif // CSV_FEATURESET_HPP
+#endif // CSV_INDEX_FEATURESET_HPP
diff --git a/plugins/input/csv/csv_inline_featureset.cpp b/plugins/input/csv/csv_inline_featureset.cpp
index 29b2203..b0fe420 100644
--- a/plugins/input/csv/csv_inline_featureset.cpp
+++ b/plugins/input/csv/csv_inline_featureset.cpp
@@ -34,12 +34,14 @@
csv_inline_featureset::csv_inline_featureset(std::string const& inline_string,
detail::geometry_column_locator const& locator,
- std::string const& separator,
+ char separator,
+ char quote,
std::vector<std::string> const& headers,
mapnik::context_ptr const& ctx,
array_type && index_array)
: inline_string_(inline_string),
separator_(separator),
+ quote_(quote),
headers_(headers),
index_array_(std::move(index_array)),
index_itr_(index_array_.begin()),
@@ -52,7 +54,7 @@ csv_inline_featureset::~csv_inline_featureset() {}
mapnik::feature_ptr csv_inline_featureset::parse_feature(std::string const& str)
{
- auto values = csv_utils::parse_line(str, separator_);
+ auto values = csv_utils::parse_line(str, separator_, quote_);
auto geom = detail::extract_geometry(values, locator_);
if (!geom.is<mapnik::geometry::geometry_empty>())
{
diff --git a/plugins/input/csv/csv_inline_featureset.hpp b/plugins/input/csv/csv_inline_featureset.hpp
index 9e06be8..3da9f63 100644
--- a/plugins/input/csv/csv_inline_featureset.hpp
+++ b/plugins/input/csv/csv_inline_featureset.hpp
@@ -36,17 +36,19 @@ class csv_inline_featureset : public mapnik::Featureset
public:
using array_type = std::deque<csv_datasource::item_type>;
csv_inline_featureset(std::string const& inline_string,
- locator_type const& locator,
- std::string const& separator,
- std::vector<std::string> const& headers,
- mapnik::context_ptr const& ctx,
- array_type && index_array);
+ locator_type const& locator,
+ char separator,
+ char quote,
+ std::vector<std::string> const& headers,
+ mapnik::context_ptr const& ctx,
+ array_type && index_array);
~csv_inline_featureset();
mapnik::feature_ptr next();
private:
mapnik::feature_ptr parse_feature(std::string const& str);
std::string const& inline_string_;
- std::string const& separator_;
+ char separator_;
+ char quote_;
std::vector<std::string> headers_;
const array_type index_array_;
array_type::const_iterator index_itr_;
diff --git a/plugins/input/csv/csv_utils.hpp b/plugins/input/csv/csv_utils.hpp
index b84e92d..77a2710 100644
--- a/plugins/input/csv/csv_utils.hpp
+++ b/plugins/input/csv/csv_utils.hpp
@@ -52,30 +52,30 @@ namespace csv_utils
{
static const mapnik::csv_line_grammar<char const*> line_g;
+static const mapnik::csv_white_space_skipper<char const*> skipper;
template <typename Iterator>
-static mapnik::csv_line parse_line(Iterator start, Iterator end, std::string const& separator, std::size_t num_columns)
+static mapnik::csv_line parse_line(Iterator start, Iterator end, char separator, char quote, std::size_t num_columns)
{
mapnik::csv_line values;
if (num_columns > 0) values.reserve(num_columns);
- boost::spirit::standard::blank_type blank;
- if (!boost::spirit::qi::phrase_parse(start, end, (line_g)(boost::phoenix::cref(separator)), blank, values))
+ if (!boost::spirit::qi::phrase_parse(start, end, (line_g)(separator, quote), skipper, values))
{
throw std::runtime_error("Failed to parse CSV line:\n" + std::string(start, end));
}
return values;
}
-static inline mapnik::csv_line parse_line(std::string const& line_str, std::string const& separator)
+static inline mapnik::csv_line parse_line(std::string const& line_str, char separator, char quote)
{
auto start = line_str.c_str();
auto end = start + line_str.length();
- return parse_line(start, end, separator, 0);
+ return parse_line(start, end, separator, quote, 0);
}
static inline bool is_likely_number(std::string const& value)
{
- return( strspn( value.c_str(), "e-.+0123456789" ) == value.size() );
+ return (std::strspn( value.c_str(), "e-.+0123456789" ) == value.size());
}
struct ignore_case_equal_pred
@@ -92,6 +92,43 @@ inline bool ignore_case_equal(std::string const& s0, std::string const& s1)
s1.begin(), ignore_case_equal_pred());
}
+template <class CharT, class Traits, class Allocator>
+std::basic_istream<CharT, Traits>& getline_csv(std::istream& is, std::basic_string<CharT,Traits,Allocator>& s, CharT delim, CharT quote)
+{
+ typename std::basic_string<CharT,Traits,Allocator>::size_type nread = 0;
+ typename std::basic_istream<CharT, Traits>::sentry sentry(is, true);
+ if (sentry)
+ {
+ std::basic_streambuf<CharT, Traits>* buf = is.rdbuf();
+ s.clear();
+ bool has_quote = false;
+ while (nread < s.max_size())
+ {
+ int c1 = buf->sbumpc();
+ if (Traits::eq_int_type(c1, Traits::eof()))
+ {
+ is.setstate(std::ios_base::eofbit);
+ break;
+ }
+ else
+ {
+ ++nread;
+ CharT c = Traits::to_char_type(c1);
+ if (Traits::eq(c, quote))
+ has_quote = !has_quote;
+ if (!Traits::eq(c, delim) || has_quote)
+ s.push_back(c);
+ else
+ break;// Character is extracted but not appended.
+ }
+ }
+ }
+ if (nread == 0 || nread >= s.max_size())
+ is.setstate(std::ios_base::failbit);
+
+ return is;
+}
+
}
@@ -104,9 +141,9 @@ std::size_t file_length(T & stream)
return stream.tellg();
}
-static inline std::string detect_separator(std::string const& str)
+static inline char detect_separator(std::string const& str)
{
- std::string separator = ","; // default
+ char separator = ','; // default
int num_commas = std::count(str.begin(), str.end(), ',');
// detect tabs
int num_tabs = std::count(str.begin(), str.end(), '\t');
@@ -114,7 +151,7 @@ static inline std::string detect_separator(std::string const& str)
{
if (num_tabs > num_commas)
{
- separator = "\t";
+ separator = '\t';
MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected tab separator";
}
}
@@ -123,7 +160,7 @@ static inline std::string detect_separator(std::string const& str)
int num_pipes = std::count(str.begin(), str.end(), '|');
if (num_pipes > num_commas)
{
- separator = "|";
+ separator = '|';
MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected '|' separator";
}
else // semicolons
@@ -131,7 +168,7 @@ static inline std::string detect_separator(std::string const& str)
int num_semicolons = std::count(str.begin(), str.end(), ';');
if (num_semicolons > num_commas)
{
- separator = ";";
+ separator = ';';
MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected ';' separator";
}
}
@@ -140,11 +177,13 @@ static inline std::string detect_separator(std::string const& str)
}
template <typename T>
-std::tuple<char,bool> autodect_newline(T & stream, std::size_t file_length)
+std::tuple<char,bool,char> autodect_newline_and_quote(T & stream, std::size_t file_length)
{
// autodetect newlines
char newline = '\n';
bool has_newline = false;
+ char quote = '"';
+ bool has_quote = false;
static std::size_t const max_size = 4000;
std::size_t size = std::min(file_length, max_size);
for (std::size_t lidx = 0; lidx < size; ++lidx)
@@ -154,15 +193,20 @@ std::tuple<char,bool> autodect_newline(T & stream, std::size_t file_length)
{
newline = '\r';
has_newline = true;
- break;
+ //break;
}
if (c == '\n')
{
has_newline = true;
- break;
+ //break;
+ }
+ else if (!has_quote && c == '\'')
+ {
+ quote = '\'';
+ has_quote = true;
}
}
- return std::make_tuple(newline,has_newline);
+ return std::make_tuple(newline, has_newline, quote);
}
diff --git a/plugins/input/gdal/build.py b/plugins/input/gdal/build.py
index 6c80de2..0db10c2 100644
--- a/plugins/input/gdal/build.py
+++ b/plugins/input/gdal/build.py
@@ -45,9 +45,9 @@ if env['RUNTIME_LINK'] == 'static':
libraries = copy(plugin_env['LIBS'])
if env['PLUGIN_LINKING'] == 'shared':
+ libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.insert(0,env['MAPNIK_NAME'])
libraries.append(env['ICU_LIB_NAME'])
- libraries.append('boost_system%s' % env['BOOST_APPEND'])
TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME,
SHLIBPREFIX='',
diff --git a/plugins/input/geojson/build.py b/plugins/input/geojson/build.py
index 7435be5..9001360 100644
--- a/plugins/input/geojson/build.py
+++ b/plugins/input/geojson/build.py
@@ -48,12 +48,12 @@ else:
# Link Library to Dependencies
libraries = []
- libraries.append(env['ICU_LIB_NAME'])
- libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.append('mapnik-json')
if env['PLUGIN_LINKING'] == 'shared':
- libraries.append(env['MAPNIK_NAME'])
+ libraries.append('boost_system%s' % env['BOOST_APPEND'])
+ libraries.insert(0,env['MAPNIK_NAME'])
+ libraries.append(env['ICU_LIB_NAME'])
TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME,
SHLIBPREFIX='',
diff --git a/plugins/input/geojson/geojson_datasource.cpp b/plugins/input/geojson/geojson_datasource.cpp
index e1ebb47..15a9503 100644
--- a/plugins/input/geojson/geojson_datasource.cpp
+++ b/plugins/input/geojson/geojson_datasource.cpp
@@ -31,6 +31,7 @@
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wsign-conversion"
#include <boost/algorithm/string.hpp>
@@ -198,7 +199,7 @@ const mapnik::json::extract_bounding_box_grammar<base_iterator_type> geojson_dat
template <typename Iterator>
void geojson_datasource::initialise_index(Iterator start, Iterator end)
{
- mapnik::json::boxes boxes;
+ mapnik::json::boxes_type boxes;
boost::spirit::standard::space_type space;
Iterator itr = start;
if (!boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_bbox_grammar)(boost::phoenix::ref(boxes)) , space))
@@ -281,11 +282,10 @@ void geojson_datasource::parse_geojson(Iterator start, Iterator end)
{
extent_.expand_to_include(box);
}
+ values.emplace_back(box, std::make_pair(geometry_index,0));
}
- values.emplace_back(box, std::make_pair(geometry_index,0));
++geometry_index;
}
-
// packing algorithm
tree_ = std::make_unique<spatial_index_type>(values);
diff --git a/plugins/input/ogr/build.py b/plugins/input/ogr/build.py
index 908cf19..143289d 100644
--- a/plugins/input/ogr/build.py
+++ b/plugins/input/ogr/build.py
@@ -51,9 +51,9 @@ libraries = copy(plugin_env['LIBS'])
plugin_env.Append(CXXFLAGS=cxxflags)
if env['PLUGIN_LINKING'] == 'shared':
+ libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.insert(0,env['MAPNIK_NAME'])
libraries.append(env['ICU_LIB_NAME'])
- libraries.append('boost_system%s' % env['BOOST_APPEND'])
TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME,
SHLIBPREFIX='',
diff --git a/plugins/input/pgraster/build.py b/plugins/input/pgraster/build.py
index 9d26665..7b859ee 100644
--- a/plugins/input/pgraster/build.py
+++ b/plugins/input/pgraster/build.py
@@ -51,13 +51,10 @@ else:
# Link Library to Dependencies
libraries = copy(plugin_env['LIBS'])
-if env['THREADING'] == 'multi':
- libraries.append('boost_thread%s' % env['BOOST_APPEND'])
-
if env['PLUGIN_LINKING'] == 'shared':
+ libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.insert(0,env['MAPNIK_NAME'])
libraries.append(env['ICU_LIB_NAME'])
- libraries.append('boost_system%s' % env['BOOST_APPEND'])
TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME,
SHLIBPREFIX='',
diff --git a/plugins/input/postgis/build.py b/plugins/input/postgis/build.py
index 9b8ecd9..157952f 100644
--- a/plugins/input/postgis/build.py
+++ b/plugins/input/postgis/build.py
@@ -51,10 +51,10 @@ else:
libraries = copy(plugin_env['LIBS'])
if env['PLUGIN_LINKING'] == 'shared':
- libraries.insert(0,env['MAPNIK_NAME'])
- libraries.append(env['ICU_LIB_NAME'])
libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.append('boost_regex%s' % env['BOOST_APPEND'])
+ libraries.insert(0,env['MAPNIK_NAME'])
+ libraries.append(env['ICU_LIB_NAME'])
TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME,
SHLIBPREFIX='',
diff --git a/plugins/input/postgis/postgis_datasource.cpp b/plugins/input/postgis/postgis_datasource.cpp
index 9477c04..d1bba46 100644
--- a/plugins/input/postgis/postgis_datasource.cpp
+++ b/plugins/input/postgis/postgis_datasource.cpp
@@ -94,7 +94,8 @@ postgis_datasource::postgis_datasource(parameters const& params)
pattern_(boost::regex("(@\\w+)",boost::regex::normal | boost::regbase::icase)),
// params below are for testing purposes only and may be removed at any time
intersect_min_scale_(*params.get<mapnik::value_integer>("intersect_min_scale", 0)),
- intersect_max_scale_(*params.get<mapnik::value_integer>("intersect_max_scale", 0))
+ intersect_max_scale_(*params.get<mapnik::value_integer>("intersect_max_scale", 0)),
+ key_field_as_attribute_(*params.get<mapnik::value_integer>("key_field_as_attribute", true))
{
#ifdef MAPNIK_STATS
mapnik::progress_timer __stats__(std::clog, "postgis_datasource::init");
@@ -372,7 +373,10 @@ postgis_datasource::postgis_datasource(parameters const& params)
if (type_oid == 20 || type_oid == 21 || type_oid == 23)
{
found_key_field = true;
- desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Integer));
+ if (key_field_as_attribute_)
+ {
+ desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Integer));
+ }
}
else
{
@@ -819,7 +823,10 @@ featureset_ptr postgis_datasource::features_with_context(query const& q,processo
if (! key_field_.empty())
{
mapnik::sql_utils::quote_attr(s, key_field_);
- ctx->push(key_field_);
+ if (key_field_as_attribute_)
+ {
+ ctx->push(key_field_);
+ }
for (; pos != end; ++pos)
{
@@ -849,7 +856,7 @@ featureset_ptr postgis_datasource::features_with_context(query const& q,processo
}
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool, proc_ctx);
- return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty());
+ return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(), key_field_as_attribute_);
}
@@ -902,7 +909,10 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt, double t
if (! key_field_.empty())
{
mapnik::sql_utils::quote_attr(s, key_field_);
- ctx->push(key_field_);
+ if (key_field_as_attribute_)
+ {
+ ctx->push(key_field_);
+ }
for (; itr != end; ++itr)
{
if (itr->get_name() != key_field_)
@@ -932,7 +942,7 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt, double t
}
std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool);
- return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty());
+ return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(), key_field_as_attribute_);
}
}
diff --git a/plugins/input/postgis/postgis_datasource.hpp b/plugins/input/postgis/postgis_datasource.hpp
index 84bcfe5..2f5d24f 100644
--- a/plugins/input/postgis/postgis_datasource.hpp
+++ b/plugins/input/postgis/postgis_datasource.hpp
@@ -122,6 +122,7 @@ private:
boost::regex pattern_;
int intersect_min_scale_;
int intersect_max_scale_;
+ bool key_field_as_attribute_;
};
#endif // POSTGIS_DATASOURCE_HPP
diff --git a/plugins/input/postgis/postgis_featureset.cpp b/plugins/input/postgis/postgis_featureset.cpp
index 9dda45d..9e0db0e 100644
--- a/plugins/input/postgis/postgis_featureset.cpp
+++ b/plugins/input/postgis/postgis_featureset.cpp
@@ -48,13 +48,15 @@ using mapnik::context_ptr;
postgis_featureset::postgis_featureset(std::shared_ptr<IResultSet> const& rs,
context_ptr const& ctx,
std::string const& encoding,
- bool key_field)
+ bool key_field,
+ bool key_field_as_attribute)
: rs_(rs),
ctx_(ctx),
tr_(new transcoder(encoding)),
totalGeomSize_(0),
feature_id_(1),
- key_field_(key_field)
+ key_field_(key_field),
+ key_field_as_attribute_(key_field_as_attribute)
{
}
@@ -97,10 +99,10 @@ feature_ptr postgis_featureset::next()
}
feature = feature_factory::create(ctx_, val);
- // TODO - extend feature class to know
- // that its id is also an attribute to avoid
- // this duplication
- feature->put<mapnik::value_integer>(name,val);
+ if (key_field_as_attribute_)
+ {
+ feature->put<mapnik::value_integer>(name,val);
+ }
++pos;
}
else
diff --git a/plugins/input/postgis/postgis_featureset.hpp b/plugins/input/postgis/postgis_featureset.hpp
index 1dc2b3f..4984ec9 100644
--- a/plugins/input/postgis/postgis_featureset.hpp
+++ b/plugins/input/postgis/postgis_featureset.hpp
@@ -43,7 +43,8 @@ public:
postgis_featureset(std::shared_ptr<IResultSet> const& rs,
context_ptr const& ctx,
std::string const& encoding,
- bool key_field = false);
+ bool key_field,
+ bool key_field_as_attribute);
feature_ptr next();
~postgis_featureset();
@@ -54,6 +55,7 @@ private:
unsigned totalGeomSize_;
mapnik::value_integer feature_id_;
bool key_field_;
+ bool key_field_as_attribute_;
};
#endif // POSTGIS_FEATURESET_HPP
diff --git a/plugins/input/raster/build.py b/plugins/input/raster/build.py
index 324a2a9..2ca3c2e 100644
--- a/plugins/input/raster/build.py
+++ b/plugins/input/raster/build.py
@@ -36,11 +36,11 @@ plugin_sources = Split(
# Link Library to Dependencies
libraries = []
-libraries.append(env['ICU_LIB_NAME'])
-libraries.append('boost_system%s' % env['BOOST_APPEND'])
if env['PLUGIN_LINKING'] == 'shared':
- libraries.append(env['MAPNIK_NAME'])
+ libraries.append('boost_system%s' % env['BOOST_APPEND'])
+ libraries.insert(0,env['MAPNIK_NAME'])
+ libraries.append(env['ICU_LIB_NAME'])
TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME,
SHLIBPREFIX='',
diff --git a/plugins/input/raster/raster_datasource.cpp b/plugins/input/raster/raster_datasource.cpp
index 96f5938..4d8b5f9 100644
--- a/plugins/input/raster/raster_datasource.cpp
+++ b/plugins/input/raster/raster_datasource.cpp
@@ -87,6 +87,7 @@ raster_datasource::raster_datasource(parameters const& params)
else //bounding box from image_reader
{
std::unique_ptr<image_reader> reader(mapnik::get_image_reader(*file));
+ if (!reader) throw datasource_exception("Raster Plugin: failed to create reader for " + *file);
auto bbox = reader->bounding_box();
if (bbox)
{
diff --git a/plugins/input/shape/build.py b/plugins/input/shape/build.py
index 097d602..3f397d0 100644
--- a/plugins/input/shape/build.py
+++ b/plugins/input/shape/build.py
@@ -39,8 +39,6 @@ plugin_sources = Split(
# Link Library to Dependencies
libraries = []
-libraries.append(env['ICU_LIB_NAME'])
-libraries.append('boost_system%s' % env['BOOST_APPEND'])
cppdefines = []
cxxflags = []
@@ -49,7 +47,9 @@ plugin_env.Append(CXXFLAGS=cxxflags)
plugin_env.Append(CPPDEFINES=cppdefines)
if env['PLUGIN_LINKING'] == 'shared':
- libraries.append(env['MAPNIK_NAME'])
+ libraries.append('boost_system%s' % env['BOOST_APPEND'])
+ libraries.insert(0,env['MAPNIK_NAME'])
+ libraries.append(env['ICU_LIB_NAME'])
TARGET = plugin_env.SharedLibrary('../shape',
SHLIBSUFFIX='.input',
diff --git a/plugins/input/shape/shape_index_featureset.cpp b/plugins/input/shape/shape_index_featureset.cpp
index fdd7513..1fa6f0b 100644
--- a/plugins/input/shape/shape_index_featureset.cpp
+++ b/plugins/input/shape/shape_index_featureset.cpp
@@ -36,10 +36,9 @@
#include <boost/interprocess/streams/bufferstream.hpp>
#endif
#pragma GCC diagnostic pop
-
#include "shape_index_featureset.hpp"
#include "shape_utils.hpp"
-#include "shp_index.hpp"
+#include <mapnik/util/spatial_index.hpp>
using mapnik::feature_factory;
@@ -52,11 +51,11 @@ shape_index_featureset<filterT>::shape_index_featureset(filterT const& filter,
int row_limit)
: filter_(filter),
ctx_(std::make_shared<mapnik::context_type>()),
- shape_ptr_(std::move(shape_ptr)),
- tr_(new mapnik::transcoder(encoding)),
- row_limit_(row_limit),
- count_(0),
- feature_bbox_()
+ shape_ptr_(std::move(shape_ptr)),
+ tr_(new mapnik::transcoder(encoding)),
+ row_limit_(row_limit),
+ count_(0),
+ feature_bbox_()
{
shape_ptr_->shp().skip(100);
setup_attributes(ctx_, attribute_names, shape_name, *shape_ptr_,attr_ids_);
@@ -65,17 +64,13 @@ shape_index_featureset<filterT>::shape_index_featureset(filterT const& filter,
if (index)
{
#ifdef SHAPE_MEMORY_MAPPED_FILE
- //shp_index<filterT,stream<mapped_file_source> >::query(filter, index->file(), offsets_);
- shp_index<filterT,boost::interprocess::ibufferstream>::query(filter, index->file(), offsets_);
+ mapnik::util::spatial_index<int, filterT,boost::interprocess::ibufferstream>::query(filter, index->file(), offsets_);
#else
- shp_index<filterT,std::ifstream>::query(filter, index->file(), offsets_);
+ mapnik::util::spatial_index<int, filterT, std::ifstream>::query(filter, index->file(), offsets_);
#endif
}
-
std::sort(offsets_.begin(), offsets_.end());
-
MAPNIK_LOG_DEBUG(shape) << "shape_index_featureset: Query size=" << offsets_.size();
-
itr_ = offsets_.begin();
}
diff --git a/plugins/input/shape/shape_index_featureset.hpp b/plugins/input/shape/shape_index_featureset.hpp
index cf52aa0..80c8fa6 100644
--- a/plugins/input/shape/shape_index_featureset.hpp
+++ b/plugins/input/shape/shape_index_featureset.hpp
@@ -63,8 +63,8 @@ private:
context_ptr ctx_;
std::unique_ptr<shape_io> shape_ptr_;
const std::unique_ptr<mapnik::transcoder> tr_;
- std::vector<std::streampos> offsets_;
- std::vector<std::streampos>::iterator itr_;
+ std::vector<int> offsets_;
+ std::vector<int>::iterator itr_;
std::vector<int> attr_ids_;
mapnik::value_integer row_limit_;
mutable int count_;
diff --git a/plugins/input/shape/shp_index.hpp b/plugins/input/shape/shp_index.hpp
deleted file mode 100644
index 6c32305..0000000
--- a/plugins/input/shape/shp_index.hpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*****************************************************************************
- *
- * This file is part of Mapnik (c++ mapping toolkit)
- *
- * Copyright (C) 2015 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
- *
- *****************************************************************************/
-
-#ifndef SHP_INDEX_HPP
-#define SHP_INDEX_HPP
-
-// stl
-#include <fstream>
-#include <vector>
-
-// mapnik
-#include <mapnik/box2d.hpp>
-#include <mapnik/query.hpp>
-
-using mapnik::box2d;
-using mapnik::query;
-
-template <typename filterT, typename IStream = std::ifstream>
-class shp_index
-{
-public:
- static void query(filterT const& filter, IStream& file,std::vector<std::streampos>& pos);
-private:
- shp_index();
- ~shp_index();
- shp_index(const shp_index&);
- shp_index& operator=(const shp_index&);
- static int read_ndr_integer(IStream& in);
- static void read_envelope(IStream& in, box2d<double>& envelope);
- static void query_node(const filterT& filter, IStream& in, std::vector<std::streampos>& pos);
-};
-
-template <typename filterT, typename IStream>
-void shp_index<filterT, IStream>::query(const filterT& filter, IStream& file, std::vector<std::streampos>& pos)
-{
- file.seekg(16, std::ios::beg);
- query_node(filter, file, pos);
-}
-
-template <typename filterT, typename IStream>
-void shp_index<filterT, IStream>::query_node(const filterT& filter, IStream& file, std::vector<std::streampos>& ids)
-{
- int offset = read_ndr_integer(file);
-
- box2d<double> node_ext;
- read_envelope(file, node_ext);
-
- int num_shapes = read_ndr_integer(file);
-
- if (! filter.pass(node_ext))
- {
- file.seekg(offset + num_shapes * 4 + 4, std::ios::cur);
- return;
- }
-
- for (int i = 0; i < num_shapes; ++i)
- {
- int id = read_ndr_integer(file);
- ids.push_back(id);
- }
-
- int children = read_ndr_integer(file);
-
- for (int j = 0; j < children; ++j)
- {
- query_node(filter, file, ids);
- }
-}
-
-template <typename filterT, typename IStream>
-int shp_index<filterT, IStream>::read_ndr_integer(IStream& file)
-{
- char b[4];
- file.read(b, 4);
- return (b[0] & 0xff) | (b[1] & 0xff) << 8 | (b[2] & 0xff) << 16 | (b[3] & 0xff) << 24;
-}
-
-template <typename filterT, typename IStream>
-void shp_index<filterT, IStream>::read_envelope(IStream& file, box2d<double>& envelope)
-{
- file.read(reinterpret_cast<char*>(&envelope), sizeof(envelope));
-}
-
-#endif // SHP_INDEX_HPP
diff --git a/plugins/input/sqlite/build.py b/plugins/input/sqlite/build.py
index b3a4a3e..53dfd8b 100644
--- a/plugins/input/sqlite/build.py
+++ b/plugins/input/sqlite/build.py
@@ -35,8 +35,6 @@ plugin_sources = Split(
# Link Library to Dependencies
libraries = [ 'sqlite3' ]
-libraries.append(env['ICU_LIB_NAME'])
-libraries.append('boost_system%s' % env['BOOST_APPEND'])
linkflags = []
if env['SQLITE_LINKFLAGS']:
@@ -44,7 +42,9 @@ if env['SQLITE_LINKFLAGS']:
plugin_env.Append(LINKFLAGS=linkflags)
if env['PLUGIN_LINKING'] == 'shared':
- libraries.append(env['MAPNIK_NAME'])
+ libraries.append('boost_system%s' % env['BOOST_APPEND'])
+ libraries.insert(0,env['MAPNIK_NAME'])
+ libraries.append(env['ICU_LIB_NAME'])
TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME,
SHLIBPREFIX='',
diff --git a/plugins/input/topojson/build.py b/plugins/input/topojson/build.py
index 9f7b955..3a49320 100644
--- a/plugins/input/topojson/build.py
+++ b/plugins/input/topojson/build.py
@@ -46,12 +46,12 @@ else:
# Link Library to Dependencies
libraries = []
- libraries.append(env['ICU_LIB_NAME'])
- libraries.append('boost_system%s' % env['BOOST_APPEND'])
libraries.append('mapnik-json')
if env['PLUGIN_LINKING'] == 'shared':
- libraries.append(env['MAPNIK_NAME'])
+ libraries.append('boost_system%s' % env['BOOST_APPEND'])
+ libraries.insert(0,env['MAPNIK_NAME'])
+ libraries.append(env['ICU_LIB_NAME'])
TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME,
SHLIBPREFIX='',
diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat
new file mode 100644
index 0000000..3ed98d9
--- /dev/null
+++ b/scripts/build-appveyor.bat
@@ -0,0 +1,70 @@
+ at ECHO OFF
+SETLOCAL
+SET EL=0
+
+ECHO =========== %~f0 ===========
+
+ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS%
+ECHO RAM [MB]^:
+powershell "get-ciminstance -class 'cim_physicalmemory' | %% { $_.Capacity/1024/1024}"
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+::only build on AppVeyor, if explicitly stated
+ECHO APPVEYOR_REPO_COMMIT_MESSAGE^: %APPVEYOR_REPO_COMMIT_MESSAGE%
+::SET BUILD_ON_APPVEYOR=0
+::for /F "tokens=1 usebackq" %%i in (`powershell .\scripts\parse-commit-message.ps1 '[build appveyor]'`) DO SET BUILD_ON_APPVEYOR=%%i
+::IF %BUILD_ON_APPVEYOR% EQU 0 ECHO not building, commit with [build appveyor] && GOTO DONE
+
+ECHO configuration^: %configuration%
+ECHO platform^: %platform%
+ECHO msvs_toolset^: %msvs_toolset%
+SET BUILD_TYPE=%configuration%
+SET BUILDPLATFORM=%platform%
+SET TOOLS_VERSION=%msvs_toolset%.0
+IF DEFINED APPVEYOR (ECHO on AppVeyor) ELSE (ECHO NOT on AppVeyor)
+ECHO ========
+
+SET PATH=C:\Python27;%PATH%
+SET PATH=C:\Program Files\7-Zip;%PATH%
+:: *nix style find command:
+SET PATH=C:\Program Files (x86)\Git\bin;%PATH%
+
+::cloning mapnik-gyp
+if EXIST mapnik-gyp ECHO mapnik-gyp already cloned && GOTO MAPNIK_GYP_ALREADY_HERE
+CALL git clone https://github.com/mapnik/mapnik-gyp.git
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+:MAPNIK_GYP_ALREADY_HERE
+CD mapnik-gyp
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+git pull
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+
+SET DEPS_URL=https://mapbox.s3.amazonaws.com/windows-builds/windows-build-deps/mapnik-win-sdk-binary-deps-%msvs_toolset%.0-%platform%.7z
+ECHO fetching binary deps^: %DEPS_URL%
+IF EXIST deps.7z (ECHO already downloaded) ELSE (powershell Invoke-WebRequest "${env:DEPS_URL}" -OutFile deps.7z)
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+ECHO extracting binary deps
+IF EXIST mapnik-sdk (ECHO already extracted) ELSE (7z -y x deps.7z | %windir%\system32\FIND "ing archive")
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+SET AV_MAPNIK_GYP_STARTTIME=%TIME%
+ECHO calling build.bat of mapnik-gyp && CALL build.bat
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+ECHO %AV_MAPNIK_GYP_STARTTIME% started mapnik-gyp build.bat
+ECHO %TIME% finished mapnik-gyp build.bat
+
+GOTO DONE
+
+:ERROR
+ECHO =========== ERROR %~f0 ===========
+ECHO ERRORLEVEL^: %ERRORLEVEL%
+SET EL=%ERRORLEVEL%
+
+:DONE
+ECHO =========== DONE %~f0 ===========
+
+EXIT /b %EL%
diff --git a/scripts/build-local.bat b/scripts/build-local.bat
new file mode 100644
index 0000000..240e70f
--- /dev/null
+++ b/scripts/build-local.bat
@@ -0,0 +1,32 @@
+ at ECHO OFF
+SETLOCAL
+SET EL=0
+
+ECHO =========== %~f0 ===========
+
+SET APPVEYOR_REPO_COMMIT_MESSAGE=this is a [build appveyor] test
+SET APPVEYOR=true
+::comment this to get complete AppVeyor behaviour
+SET LOCAL_BUILD_DONT_SKIP_TESTS=true
+
+SET MAPNIK_GIT=3.0.5
+SET BOOST_VERSION=58
+SET FASTBUILD=1
+SET configuration=Release
+SET msvs_toolset=14
+SET platform=x64
+SET APPVEYOR_BUILD_FOLDER=%CD%
+CALL scripts\build-appveyor.bat
+IF %ERRORLEVEL% NEQ 0 GOTO ERROR
+
+GOTO DONE
+
+:ERROR
+ECHO =========== ERROR %~f0 ===========
+ECHO ERRORLEVEL^: %ERRORLEVEL%
+SET EL=%ERRORLEVEL%
+
+:DONE
+ECHO =========== DONE %~f0 ===========
+
+EXIT /b %EL%
diff --git a/scripts/parse-commit-message.ps1 b/scripts/parse-commit-message.ps1
new file mode 100644
index 0000000..a22c10d
--- /dev/null
+++ b/scripts/parse-commit-message.ps1
@@ -0,0 +1,5 @@
+if($env:APPVEYOR_REPO_COMMIT_MESSAGE.ToLower().Contains($args[0].ToLower())) {
+ Write-Host '1';
+} else {
+ Write-Host '0';
+}
diff --git a/src/cairo/process_debug_symbolizer.cpp b/src/cairo/process_debug_symbolizer.cpp
index c60794b..8c78a82 100644
--- a/src/cairo/process_debug_symbolizer.cpp
+++ b/src/cairo/process_debug_symbolizer.cpp
@@ -92,7 +92,6 @@ void cairo_renderer<T>::process(debug_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
- using detector_type = label_collision_detector4;
cairo_save_restore guard(context_);
debug_symbolizer_mode_enum mode = get<debug_symbolizer_mode_enum>(sym, keys::mode, feature, common_.vars_, DEBUG_SYM_MODE_COLLISION);
diff --git a/src/debug.cpp b/src/debug.cpp
index f41f84c..169272f 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -43,22 +43,22 @@
namespace mapnik {
-// mutexes
-
#ifdef MAPNIK_THREADSAFE
+
std::mutex logger::severity_mutex_;
std::mutex logger::format_mutex_;
-#endif
-
-
-// first time checks
std::atomic<bool> logger::severity_env_check_ {true};
std::atomic<bool> logger::format_env_check_ {true};
-// severity
-
std::atomic<logger::severity_type> logger::severity_level_ {
+#else
+
+bool logger::severity_env_check_ {true};
+bool logger::format_env_check_ {true};
+
+logger::severity_type logger::severity_level_ {
+#endif
#if MAPNIK_DEFAULT_LOG_SEVERITY == 0
logger::debug
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 1
diff --git a/src/image_util.cpp b/src/image_util.cpp
index 7f86fdb..79d7e0a 100644
--- a/src/image_util.cpp
+++ b/src/image_util.cpp
@@ -1582,7 +1582,6 @@ struct visitor_get_pixel
template <typename T2>
T1 operator() (T2 const& data) const
{
- using pixel_type = T1;
if (check_bounds(data, x_, y_))
{
return safe_cast<T1>(data(x_, y_));
diff --git a/src/svg/svg_parser.cpp b/src/svg/svg_parser.cpp
index ec1f4d8..af02a71 100644
--- a/src/svg/svg_parser.cpp
+++ b/src/svg/svg_parser.cpp
@@ -157,6 +157,28 @@ double parse_double_optional_percent(T & error_messages, const char* str, bool &
return val;
}
+template <typename T>
+bool parse_double_list(T & error_messages, const char* str, double* list)
+{
+ using namespace boost::spirit::qi;
+ using boost::phoenix::ref;
+ qi::_1_type _1;
+ qi::double_type double_;
+ qi::lit_type lit;
+ using skip_type = boost::spirit::ascii::space_type;
+
+ if (!phrase_parse(str, str + std::strlen(str),
+ double_[ref(list[0])=_1] >> -lit(',') >>
+ double_[ref(list[1])=_1] >> -lit(',') >>
+ double_[ref(list[2])=_1] >> -lit(',') >>
+ double_[ref(list[3])=_1], skip_type()))
+ {
+ error_messages.emplace_back("failed to parse list of doubles from " + std::string(str));
+ return false;
+ }
+ return true;
+}
+
bool parse_style (char const* str, pairs_type & v)
{
using namespace boost::spirit::qi;
@@ -465,16 +487,44 @@ void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
{
double width = 0;
double height = 0;
+ double aspect_ratio = 1;
+ double viewbox[4] = {0,0,0,0};
+ bool has_viewbox = false;
+ bool has_percent_height = true;
+ bool has_percent_width = true;
+
auto const* width_attr = node->first_attribute("width");
if (width_attr)
{
- width = parse_double(parser.error_messages_, width_attr->value());
+ width = parse_double_optional_percent(parser.error_messages_, width_attr->value(), has_percent_width);
}
auto const* height_attr = node->first_attribute("height");
if (height_attr)
{
- height = parse_double(parser.error_messages_, height_attr->value());
+ height = parse_double_optional_percent(parser.error_messages_, height_attr->value(), has_percent_height);
}
+ auto const* viewbox_attr = node->first_attribute("viewBox");
+ if (viewbox_attr)
+ {
+ has_viewbox = parse_double_list(parser.error_messages_, viewbox_attr->value(), viewbox);
+ }
+
+ if (has_percent_width && !has_percent_height && has_viewbox)
+ {
+ aspect_ratio = viewbox[2] / viewbox[3];
+ width = aspect_ratio * height;
+ }
+ else if (!has_percent_width && has_percent_height && has_viewbox)
+ {
+ aspect_ratio = viewbox[2] / viewbox[3];
+ height = height / aspect_ratio;
+ }
+ else if (has_percent_width && has_percent_height && has_viewbox)
+ {
+ width = viewbox[2];
+ height = viewbox[3];
+ }
+
parser.path_.set_dimensions(width, height);
}
diff --git a/src/text/placements/simple.cpp b/src/text/placements/simple.cpp
index 59e4407..493da3f 100644
--- a/src/text/placements/simple.cpp
+++ b/src/text/placements/simple.cpp
@@ -36,6 +36,7 @@
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wsign-conversion"
+#pragma GCC diagnostic ignored "-Wsign-compare"
#pragma GCC diagnostic ignored "-Wconversion"
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
diff --git a/test/standalone/csv_test.cpp b/test/standalone/csv_test.cpp
index 6535e82..7d08bb5 100644
--- a/test/standalone/csv_test.cpp
+++ b/test/standalone/csv_test.cpp
@@ -191,6 +191,7 @@ TEST_CASE("csv") {
for (auto const &path : broken)
{
+ INFO(path);
REQUIRE_THROWS(get_csv_ds(path.native()));
}
}
@@ -555,20 +556,6 @@ TEST_CASE("csv") {
}
} // END SECTION
- SECTION("blank undelimited rows are still parsed") {
- using ustring = mapnik::value_unicode_string;
-
- // TODO: does this mean this CSV file should be in the warnings
- // subdirectory, since it doesn't work in strict mode?
- auto ds = get_csv_ds("test/data/csv/more_headers_than_column_values.csv", false);
- auto fields = ds->get_descriptor().get_descriptors();
- require_field_names(fields, {"x", "y", "one", "two", "three"});
- require_field_types(fields, {mapnik::Integer, mapnik::Integer, mapnik::String, mapnik::String, mapnik::String});
-
- require_attributes(all_features(ds)->next(), {
- attr{"x", 0}, attr{"y", 0}, attr{"one", ustring("")}, attr{"two", ustring("")}, attr{"three", ustring("")} });
- } // END SECTION
-
SECTION("fewer headers than rows throws") {
REQUIRE_THROWS(get_csv_ds("test/data/csv/more_column_values_than_headers.csv"));
} // END SECTION
@@ -670,6 +657,7 @@ TEST_CASE("csv") {
mapnik::parameters params;
params["type"] = std::string("csv");
params["inline"] = csv_string;
+ params["quote"] = "'";
auto ds = mapnik::datasource_cache::instance().create(params);
REQUIRE(bool(ds));
diff --git a/test/standalone/datasource_registration_test.cpp b/test/standalone/datasource_registration_test.cpp
index 2edbcd7..9d6266c 100644
--- a/test/standalone/datasource_registration_test.cpp
+++ b/test/standalone/datasource_registration_test.cpp
@@ -3,6 +3,7 @@
#include <mapnik/datasource_cache.hpp>
#include <mapnik/debug.hpp>
+#include <mapnik/util/fs.hpp>
#include <iostream>
#include <vector>
@@ -22,19 +23,24 @@ SECTION("registration") {
success = cache.register_datasources("test/data/vrt");
CHECK(success == false);
- // registering a directory for the first time should return true
- success = cache.register_datasources("plugins/input");
- REQUIRE(success == true);
-
- // registering the same directory again should now return false
- success = cache.register_datasources("plugins/input");
- CHECK(success == false);
-
- // registering the same directory again, but recursively should
- // still return false - even though there are subdirectories, they
- // do not contain any more plugins.
- success = cache.register_datasources("plugins/input", true);
- CHECK(success == false);
+ // use existence of shape.input as proxy for whether any datasource plugins are available
+ std::string shape_plugin("./plugins/input/shape.input");
+ if (mapnik::util::exists(shape_plugin))
+ {
+ // registering a directory for the first time should return true
+ success = cache.register_datasources("plugins/input");
+ REQUIRE(success == true);
+
+ // registering the same directory again should now return false
+ success = cache.register_datasources("plugins/input");
+ CHECK(success == false);
+
+ // registering the same directory again, but recursively should
+ // still return false - even though there are subdirectories, they
+ // do not contain any more plugins.
+ success = cache.register_datasources("plugins/input", true);
+ CHECK(success == false);
+ }
}
catch (std::exception const & ex)
{
diff --git a/test/unit/color/css_color.cpp b/test/unit/color/css_color.cpp
index 38e1518..7ff6e3f 100644
--- a/test/unit/color/css_color.cpp
+++ b/test/unit/color/css_color.cpp
@@ -1,5 +1,6 @@
#include "catch.hpp"
#include <mapnik/css_color_grammar.hpp>
+#include <mapnik/css_color_grammar_impl.hpp>
#include <mapnik/safe_cast.hpp>
TEST_CASE("css color") {
@@ -35,4 +36,132 @@ TEST_CASE("css color") {
CHECK( c.green() == 0 );
CHECK( c.blue() == 0 );
}
-}
\ No newline at end of file
+
+ SECTION("hex colors")
+ {
+ mapnik::css_color_grammar<std::string::const_iterator> color_grammar;
+ boost::spirit::qi::ascii::space_type space;
+
+ {
+ std::string s("#abcdef");
+ mapnik::color c;
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c) );
+ CHECK( c.alpha() == 0xff );
+ CHECK( c.red() == 0xab );
+ CHECK( c.green() == 0xcd );
+ CHECK( c.blue() == 0xef );
+ }
+
+ {
+ std::string s("#abcdef12");
+ mapnik::color c;
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c) );
+ CHECK( c.alpha() == 0x12 );
+ CHECK( c.red() == 0xab );
+ CHECK( c.green() == 0xcd );
+ CHECK( c.blue() == 0xef );
+ }
+
+ {
+ std::string s(" #abcdef");
+ mapnik::color c;
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c) );
+ CHECK( c.alpha() == 0xff );
+ CHECK( c.red() == 0xab );
+ CHECK( c.green() == 0xcd );
+ CHECK( c.blue() == 0xef );
+ }
+
+ {
+ std::string s(" #abcdef12");
+ mapnik::color c;
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c) );
+ CHECK( c.alpha() == 0x12 );
+ CHECK( c.red() == 0xab );
+ CHECK( c.green() == 0xcd );
+ CHECK( c.blue() == 0xef );
+ }
+
+ {
+ std::string s("# abcdef");
+ CHECK( !boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space) );
+ }
+
+ {
+ std::string s("# abcdef12");
+ CHECK( !boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space) );
+ }
+
+ {
+ std::string s("#ab cdef");
+ CHECK( !boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space) );
+ }
+
+ {
+ std::string s("#ab cdef12");
+ CHECK( !boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space) );
+ }
+
+ // hex_color_small
+
+ {
+ std::string s("#abc");
+ mapnik::color c;
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c) );
+ CHECK( c.alpha() == 0xff );
+ CHECK( c.red() == 0xaa );
+ CHECK( c.green() == 0xbb );
+ CHECK( c.blue() == 0xcc );
+ }
+
+ {
+ std::string s("#abcd");
+ mapnik::color c;
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c) );
+ CHECK( c.alpha() == 0xdd );
+ CHECK( c.red() == 0xaa );
+ CHECK( c.green() == 0xbb );
+ CHECK( c.blue() == 0xcc );
+ }
+
+ {
+ std::string s(" #abc");
+ mapnik::color c;
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c) );
+ CHECK( c.alpha() == 0xff );
+ CHECK( c.red() == 0xaa );
+ CHECK( c.green() == 0xbb );
+ CHECK( c.blue() == 0xcc );
+ }
+
+ {
+ std::string s(" #abcd");
+ mapnik::color c;
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c) );
+ CHECK( c.alpha() == 0xdd );
+ CHECK( c.red() == 0xaa );
+ CHECK( c.green() == 0xbb );
+ CHECK( c.blue() == 0xcc );
+ }
+
+ {
+ std::string s("# abc");
+ CHECK( !boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space) );
+ }
+
+ {
+ std::string s("# abcd");
+ CHECK( !boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space) );
+ }
+
+ {
+ std::string s("#a bc");
+ CHECK( !boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space) );
+ }
+
+ {
+ std::string s("#a bcd");
+ CHECK( !boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), color_grammar, space) );
+ }
+ }
+}
diff --git a/test/unit/core/comparison_test.cpp b/test/unit/core/comparison_test.cpp
new file mode 100644
index 0000000..2cfbc08
--- /dev/null
+++ b/test/unit/core/comparison_test.cpp
@@ -0,0 +1,49 @@
+#include "catch.hpp"
+
+#include <mapnik/value_types.hpp>
+#include <mapnik/value.hpp>
+#include <mapnik/unicode.hpp>
+
+TEST_CASE("comparison")
+{
+ SECTION("operator==()")
+ {
+ mapnik::value v0 = 1; // mapnik::value_integer
+ mapnik::value v1 = 1.001; // mapnik::value_double
+ mapnik::value v2 = true; // mapnik::value_boolean
+
+ REQUIRE(!(v0 == v1));
+ REQUIRE(!(v1 == v0));
+
+ REQUIRE(!(v1 == v2));
+ REQUIRE(!(v2 == v1));
+
+ REQUIRE(v2 == v0);
+ REQUIRE(v0 == v2);
+ }
+
+ SECTION("operator!=()")
+ {
+ mapnik::value v0 = 1; // mapnik::value_integer
+ mapnik::value v1 = 1.001; // mapnik::value_double
+ mapnik::value v2 = true; // mapnik::value_boolean
+ mapnik::value v3 = mapnik::value_null(); //
+
+ REQUIRE(v0 != v1);
+ REQUIRE(v1 != v0);
+
+ REQUIRE(v1 != v2);
+ REQUIRE(v2 != v1);
+
+ REQUIRE(!(v2 != v0));
+ REQUIRE(!(v0 != v2));
+
+ REQUIRE(v3 != v0);
+ REQUIRE(v3 != v1);
+ REQUIRE(v3 != v2);
+ REQUIRE(v0 != v3);
+ REQUIRE(v1 != v3);
+ REQUIRE(v2 != v3);
+
+ }
+}
diff --git a/test/unit/datasource/spatial_index.cpp b/test/unit/datasource/spatial_index.cpp
new file mode 100644
index 0000000..62fde03
--- /dev/null
+++ b/test/unit/datasource/spatial_index.cpp
@@ -0,0 +1,90 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2015 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 <iostream>
+#include <fstream>
+
+#include "catch.hpp"
+
+#include <mapnik/quad_tree.hpp>
+#include <mapnik/util/spatial_index.hpp>
+
+TEST_CASE("spatial_index")
+{
+ SECTION("mapnik::quad_tree<T>")
+ {
+ // value_type must have standard layout (http://en.cppreference.com/w/cpp/types/is_standard_layout)
+ using value_type = std::int32_t;
+ using mapnik::filter_in_box;
+ mapnik::box2d<double> extent(0,0,100,100);
+ mapnik::quad_tree<value_type> tree(extent);
+ REQUIRE(tree.extent() == extent);
+ // insert some items
+ tree.insert(1, mapnik::box2d<double>(10,10,20,20));
+ tree.insert(2, mapnik::box2d<double>(30,30,40,40));
+ tree.insert(3, mapnik::box2d<double>(30,10,40,20));
+ tree.insert(4, mapnik::box2d<double>(1,1,2,2));
+ tree.trim();
+
+ REQUIRE(tree.count() == 5);
+ REQUIRE(tree.count_items() == 4);
+
+ // serialise
+ std::ostringstream out(std::ios::binary);
+ tree.write(out);
+ out.flush();
+
+ REQUIRE(out.str().length() == 252);
+ REQUIRE(out.str().at(0) == 'm');
+
+ // read bounding box
+ std::istringstream in(out.str(), std::ios::binary);
+ auto box = mapnik::util::spatial_index<value_type, filter_in_box, std::istringstream>::bounding_box(in);
+ REQUIRE(box == tree.extent());
+ // bounding box query
+ std::vector<value_type> results;
+ filter_in_box filter(box);
+ mapnik::util::spatial_index<value_type, filter_in_box, std::istringstream>::query(filter, in, results);
+
+ REQUIRE(results[0] == 1);
+ REQUIRE(results[1] == 4);
+ REQUIRE(results[2] == 3);
+ REQUIRE(results[3] == 2);
+ REQUIRE(results.size() == 4);
+
+ // query first N elements interface
+ results.clear();
+ in.seekg(0, std::ios::beg);
+ mapnik::util::spatial_index<value_type, filter_in_box, std::istringstream>::query_first_n(filter, in, results, 2);
+ REQUIRE(results.size() == 2);
+ REQUIRE(results[0] == 1);
+ REQUIRE(results[1] == 4);
+ results.clear();
+ in.seekg(0, std::ios::beg);
+ mapnik::util::spatial_index<value_type, filter_in_box, std::istringstream>::query_first_n(filter, in, results, 5);
+ REQUIRE(results[0] == 1);
+ REQUIRE(results[1] == 4);
+ REQUIRE(results[2] == 3);
+ REQUIRE(results[3] == 2);
+ REQUIRE(results.size() == 4);
+ }
+}
diff --git a/test/unit/geometry/geometry_is_simple.cpp b/test/unit/geometry/geometry_is_simple.cpp
new file mode 100644
index 0000000..a09332f
--- /dev/null
+++ b/test/unit/geometry/geometry_is_simple.cpp
@@ -0,0 +1,320 @@
+#include "catch.hpp"
+
+#include <boost/version.hpp>
+#include <mapnik/geometry.hpp>
+#include <mapnik/geometry_adapters.hpp>
+#include <mapnik/geometry_is_simple.hpp>
+
+TEST_CASE("geometry is_simple") {
+
+// only Boost >= 1.58 has the required is_valid function version
+#if BOOST_VERSION >= 105800
+
+SECTION("point") {
+ mapnik::geometry::geometry_empty empty;
+ CHECK( mapnik::geometry::is_simple(empty) );
+}
+
+SECTION("point") {
+ mapnik::geometry::point<double> pt(0,0);
+ CHECK( mapnik::geometry::is_simple(pt) );
+}
+
+SECTION("point uninitialized") {
+ mapnik::geometry::point<double> pt2;
+ CHECK( mapnik::geometry::is_simple(pt2) );
+}
+
+SECTION("point -- geometry object") {
+ mapnik::geometry::point<double> pt(0,0);
+ mapnik::geometry::geometry<double> geom(pt);
+ CHECK( mapnik::geometry::is_simple(geom) );
+}
+
+// This is funky that boost geometry is_simple does not check for NAN when dealing with a point
+// this test is here in case the logic ever changes
+// Bug report on this: https://svn.boost.org/trac/boost/ticket/11711
+SECTION("point NaN") {
+ mapnik::geometry::point<double> pt(std::numeric_limits<double>::quiet_NaN(),std::numeric_limits<double>::quiet_NaN());
+ CHECK( std::isnan(pt.x) );
+ CHECK( std::isnan(pt.y) );
+ CHECK( mapnik::geometry::is_simple(pt) );
+}
+
+// This is funky that boost geometry is_simple does not check for infinity when dealing with a point
+// this test is here in case the logic ever changes
+// Bug report on this: https://svn.boost.org/trac/boost/ticket/11711
+SECTION("point Infinity") {
+ mapnik::geometry::point<double> pt(std::numeric_limits<double>::infinity(),std::numeric_limits<double>::infinity());
+ CHECK( std::isinf(pt.x) );
+ CHECK( std::isinf(pt.y) );
+ CHECK( mapnik::geometry::is_simple(pt) );
+}
+
+SECTION("multi point") {
+ mapnik::geometry::multi_point<double> mpt;
+ mpt.add_coord(0,0);
+ mpt.add_coord(1,1);
+ CHECK( mapnik::geometry::is_simple(mpt) );
+}
+
+SECTION("multi point empty") {
+ mapnik::geometry::multi_point<double> mpt;
+ CHECK( mapnik::geometry::is_simple(mpt) );
+}
+
+SECTION("line_string") {
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0,0);
+ line.add_coord(1,1);
+ CHECK( mapnik::geometry::is_simple(line) );
+}
+
+// This fails while is_valid will not fail!
+SECTION("line_string repeated points") {
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0,0);
+ line.add_coord(1,1);
+ line.add_coord(1,1);
+ line.add_coord(2,2);
+ CHECK( !mapnik::geometry::is_simple(line) );
+}
+
+SECTION("line_string empty") {
+ mapnik::geometry::line_string<double> line;
+ CHECK( mapnik::geometry::is_simple(line) );
+}
+
+SECTION("multi_line_string") {
+ mapnik::geometry::line_string<double> line1;
+ line1.add_coord(0,0);
+ line1.add_coord(1,1);
+ mapnik::geometry::line_string<double> line2;
+ line2.add_coord(0,1);
+ line2.add_coord(1,2);
+ mapnik::geometry::multi_line_string<double> lines;
+ lines.emplace_back(line1);
+ lines.emplace_back(line2);
+ CHECK( mapnik::geometry::is_simple(lines) );
+}
+
+SECTION("multi_line_string empty") {
+ mapnik::geometry::multi_line_string<double> lines;
+ CHECK( mapnik::geometry::is_simple(lines) );
+}
+
+SECTION("multi_line_string empty") {
+ mapnik::geometry::multi_line_string<double> lines;
+ mapnik::geometry::line_string<double> line;
+ lines.emplace_back(line);
+ CHECK( mapnik::geometry::is_simple(lines) );
+}
+
+SECTION("polygon") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( mapnik::geometry::is_simple(poly) );
+}
+
+SECTION("polygon invalid winding order") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(0,1);
+ ring.add_coord(1,1);
+ ring.add_coord(1,0);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( mapnik::geometry::is_simple(poly) );
+}
+
+// repeated points are not considered invalid in a polygon
+// but they are considered not simple
+SECTION("polygon 2 repeated points") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( !mapnik::geometry::is_simple(poly) );
+}
+// repeated points are not considered invalid in a polygon
+// but they are considered not simple
+SECTION("polygon 3 repeated points") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(1,1);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( !mapnik::geometry::is_simple(poly) );
+}
+
+SECTION("polygon that is empty") {
+ mapnik::geometry::polygon<double> poly;
+ CHECK( mapnik::geometry::is_simple(poly) );
+}
+
+SECTION("polygon that has empty exterior ring") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( mapnik::geometry::is_simple(poly) );
+}
+
+SECTION("polygon that has empty interior ring") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::linear_ring<double> ring2;
+ poly.add_hole(std::move(ring2));
+ CHECK( mapnik::geometry::is_simple(poly) );
+}
+
+// A polygon with a spike can still be simple
+SECTION("polygon with spike") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(2,2);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( mapnik::geometry::is_simple(poly) );
+}
+
+SECTION("polygon with hole") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(3,0);
+ ring.add_coord(3,3);
+ ring.add_coord(0,3);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::linear_ring<double> hole;
+ hole.add_coord(1,1);
+ hole.add_coord(1,2);
+ hole.add_coord(2,2);
+ hole.add_coord(2,1);
+ hole.add_coord(1,1);
+ poly.add_hole(std::move(hole));
+ CHECK( mapnik::geometry::is_simple(poly) );
+}
+
+// Polygons with reversed winding order still can be considered simple
+SECTION("polygon with hole with invalid winding order") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(3,0);
+ ring.add_coord(3,3);
+ ring.add_coord(0,3);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::linear_ring<double> hole;
+ hole.add_coord(1,1);
+ hole.add_coord(2,1);
+ hole.add_coord(2,2);
+ hole.add_coord(1,2);
+ hole.add_coord(1,1);
+ poly.add_hole(std::move(hole));
+ CHECK( mapnik::geometry::is_simple(poly) );
+}
+
+SECTION("multi polygon") {
+ mapnik::geometry::multi_polygon<double> mp;
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::polygon<double> poly2;
+ mapnik::geometry::linear_ring<double> ring2;
+ ring2.add_coord(0,0);
+ ring2.add_coord(-1,0);
+ ring2.add_coord(-1,-1);
+ ring2.add_coord(0,-1);
+ ring2.add_coord(0,0);
+ poly2.set_exterior_ring(std::move(ring2));
+ mp.emplace_back(poly);
+ mp.emplace_back(poly2);
+ CHECK( mapnik::geometry::is_simple(mp) );
+}
+
+SECTION("multi polygon with hole") {
+ mapnik::geometry::multi_polygon<double> mp;
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(3,0);
+ ring.add_coord(3,3);
+ ring.add_coord(0,3);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::linear_ring<double> hole;
+ hole.add_coord(1,1);
+ hole.add_coord(1,2);
+ hole.add_coord(2,2);
+ hole.add_coord(2,1);
+ hole.add_coord(1,1);
+ poly.add_hole(std::move(hole));
+ mapnik::geometry::polygon<double> poly2;
+ mapnik::geometry::linear_ring<double> ring2;
+ ring2.add_coord(0,0);
+ ring2.add_coord(-3,0);
+ ring2.add_coord(-3,-3);
+ ring2.add_coord(0,-3);
+ ring2.add_coord(0,0);
+ poly2.set_exterior_ring(std::move(ring2));
+ mapnik::geometry::linear_ring<double> hole2;
+ hole2.add_coord(-1,-1);
+ hole2.add_coord(-1,-2);
+ hole2.add_coord(-2,-2);
+ hole2.add_coord(-2,-1);
+ hole2.add_coord(-1,-1);
+ poly2.add_hole(std::move(hole2));
+ mp.emplace_back(poly);
+ mp.emplace_back(poly2);
+ CHECK( mapnik::geometry::is_simple(mp) );
+}
+
+SECTION("multi polygon empty") {
+ mapnik::geometry::multi_polygon<double> mp;
+ CHECK( mapnik::geometry::is_simple(mp) );
+}
+
+#else // BOOST_VERSION >= 1.58
+
+SECTION("skipped is_simple tests") {
+ WARN( "geometry simple tests disabled due to boost version older that 1.58 used" );
+}
+
+#endif
+
+}
diff --git a/test/unit/geometry/geometry_is_valid.cpp b/test/unit/geometry/geometry_is_valid.cpp
index 5f4f862..85577ec 100644
--- a/test/unit/geometry/geometry_is_valid.cpp
+++ b/test/unit/geometry/geometry_is_valid.cpp
@@ -6,26 +6,443 @@
TEST_CASE("geometry is_valid") {
-// only Boost >= 1.56 has the is_valid function
-#if BOOST_VERSION >= 105600
+// only Boost >= 1.56 has the is_valid function, but only after 1.58 is there support for returning what is invalid
+#if BOOST_VERSION >= 105800
+
+
+SECTION("empty geometry") {
+ mapnik::geometry::geometry_empty empty;
+ CHECK( mapnik::geometry::is_valid(empty) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(empty, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(empty, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
SECTION("point") {
mapnik::geometry::point<double> pt(0,0);
- REQUIRE( mapnik::geometry::is_valid(pt) );
+ CHECK( mapnik::geometry::is_valid(pt) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(pt, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(pt, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+SECTION("point -- geometry object") {
+ mapnik::geometry::point<double> pt(0,0);
+ mapnik::geometry::geometry<double> geom(pt);
+ CHECK( mapnik::geometry::is_valid(geom) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(geom, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(geom, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
- // uninitialized: should likely not be considered valid
+SECTION("point unitialized") {
mapnik::geometry::point<double> pt2;
- REQUIRE( mapnik::geometry::is_valid(pt2) );
+ CHECK( mapnik::geometry::is_valid(pt2) );
+ std::string message2;
+ CHECK( mapnik::geometry::is_valid(pt2, message2) );
+ CHECK( message2 == "Geometry is valid");
+ boost::geometry::validity_failure_type failure2;
+ CHECK( mapnik::geometry::is_valid(pt2, failure2) );
+ CHECK( failure2 == boost::geometry::no_failure );
+}
+
+// This is funky that boost geometry is_valid does not check for NAN when dealing with a point
+// this test is here in case the logic ever changes
+// Bug report on this: https://svn.boost.org/trac/boost/ticket/11711
+SECTION("point NaN") {
+ mapnik::geometry::point<double> pt(std::numeric_limits<double>::quiet_NaN(),std::numeric_limits<double>::quiet_NaN());
+ CHECK( std::isnan(pt.x) );
+ CHECK( std::isnan(pt.y) );
+ CHECK( mapnik::geometry::is_valid(pt) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(pt, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(pt, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+// This is funky that boost geometry is_valid does not check for infinity when dealing with a point
+// this test is here in case the logic ever changes
+// Bug report on this: https://svn.boost.org/trac/boost/ticket/11711
+SECTION("point Infinity") {
+ mapnik::geometry::point<double> pt(std::numeric_limits<double>::infinity(),std::numeric_limits<double>::infinity());
+ CHECK( std::isinf(pt.x) );
+ CHECK( std::isinf(pt.y) );
+ CHECK( mapnik::geometry::is_valid(pt) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(pt, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(pt, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+SECTION("multi point") {
+ mapnik::geometry::multi_point<double> mpt;
+ mpt.add_coord(0,0);
+ mpt.add_coord(1,1);
+ CHECK( mapnik::geometry::is_valid(mpt) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(mpt, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(mpt, failure) );
+ CHECK( failure == boost::geometry::no_failure );
}
+SECTION("multi point empty") {
+ mapnik::geometry::multi_point<double> mpt;
+ CHECK( mapnik::geometry::is_valid(mpt) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(mpt, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(mpt, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+
SECTION("line_string") {
mapnik::geometry::line_string<double> line;
line.add_coord(0,0);
line.add_coord(1,1);
- REQUIRE( mapnik::geometry::is_valid(line) );
+ CHECK( mapnik::geometry::is_valid(line) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(line, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(line, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+// This shouldn't fail -- test added in case logic ever changes
+SECTION("line_string repeated points") {
+ mapnik::geometry::line_string<double> line;
+ line.add_coord(0,0);
+ line.add_coord(1,1);
+ line.add_coord(1,1);
+ line.add_coord(2,2);
+ CHECK( mapnik::geometry::is_valid(line) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(line, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(line, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+SECTION("line_string empty") {
+ mapnik::geometry::line_string<double> line;
+ CHECK( !mapnik::geometry::is_valid(line) );
+ std::string message;
+ CHECK( !mapnik::geometry::is_valid(line, message) );
+ CHECK( message == "Geometry has too few points");
+ boost::geometry::validity_failure_type failure;
+ CHECK( !mapnik::geometry::is_valid(line, failure) );
+ CHECK( failure == boost::geometry::failure_few_points );
+}
+
+SECTION("multi_line_string") {
+ mapnik::geometry::line_string<double> line1;
+ line1.add_coord(0,0);
+ line1.add_coord(1,1);
+ mapnik::geometry::line_string<double> line2;
+ line2.add_coord(0,1);
+ line2.add_coord(1,2);
+ mapnik::geometry::multi_line_string<double> lines;
+ lines.emplace_back(line1);
+ lines.emplace_back(line2);
+ CHECK( mapnik::geometry::is_valid(lines) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(lines, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(lines, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+SECTION("multi_line_string empty") {
+ mapnik::geometry::multi_line_string<double> lines;
+ CHECK( mapnik::geometry::is_valid(lines) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(lines, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(lines, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+SECTION("polygon") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( mapnik::geometry::is_valid(poly) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(poly, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(poly, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+SECTION("polygon invalid winding order") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(0,1);
+ ring.add_coord(1,1);
+ ring.add_coord(1,0);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( !mapnik::geometry::is_valid(poly) );
+ std::string message;
+ CHECK( !mapnik::geometry::is_valid(poly, message) );
+ CHECK( message == "Geometry has wrong orientation" );
+ boost::geometry::validity_failure_type failure;
+ CHECK( !mapnik::geometry::is_valid(poly, failure) );
+ CHECK( failure == boost::geometry::failure_wrong_orientation );
+}
+
+// repeated points are not considered invalid in a polygon
+SECTION("polygon 2 repeated points") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( mapnik::geometry::is_valid(poly) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(poly, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(poly, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+// repeated points are not considered invalid in a polygon
+SECTION("polygon 3 repeated points") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(1,1);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( mapnik::geometry::is_valid(poly) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(poly, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(poly, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+SECTION("polygon that is empty") {
+ mapnik::geometry::polygon<double> poly;
+ CHECK( !mapnik::geometry::is_valid(poly) );
+ std::string message;
+ CHECK( !mapnik::geometry::is_valid(poly, message) );
+ CHECK( message == "Geometry has too few points");
+ boost::geometry::validity_failure_type failure;
+ CHECK( !mapnik::geometry::is_valid(poly, failure) );
+ CHECK( failure == boost::geometry::failure_few_points );
+}
+
+SECTION("polygon with spike") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(2,2);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ CHECK( !mapnik::geometry::is_valid(poly) );
+ std::string message;
+ CHECK( !mapnik::geometry::is_valid(poly, message) );
+ CHECK( message == "Geometry has spikes. A spike point was found with apex at (2, 2)");
+ boost::geometry::validity_failure_type failure;
+ CHECK( !mapnik::geometry::is_valid(poly, failure) );
+ CHECK( failure == boost::geometry::failure_spikes );
+}
+
+SECTION("polygon with hole") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(3,0);
+ ring.add_coord(3,3);
+ ring.add_coord(0,3);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::linear_ring<double> hole;
+ hole.add_coord(1,1);
+ hole.add_coord(1,2);
+ hole.add_coord(2,2);
+ hole.add_coord(2,1);
+ hole.add_coord(1,1);
+ poly.add_hole(std::move(hole));
+ CHECK( mapnik::geometry::is_valid(poly) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(poly, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(poly, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+SECTION("polygon with empty hole") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(3,0);
+ ring.add_coord(3,3);
+ ring.add_coord(0,3);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::linear_ring<double> hole;
+ poly.add_hole(std::move(hole));
+ CHECK( !mapnik::geometry::is_valid(poly) );
+ std::string message;
+ CHECK( !mapnik::geometry::is_valid(poly, message) );
+ CHECK( message == "Geometry has too few points");
+ boost::geometry::validity_failure_type failure;
+ CHECK( !mapnik::geometry::is_valid(poly, failure) );
+ CHECK( failure == boost::geometry::failure_few_points );
+}
+
+
+SECTION("polygon with hole with invalid winding order") {
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(3,0);
+ ring.add_coord(3,3);
+ ring.add_coord(0,3);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::linear_ring<double> hole;
+ hole.add_coord(1,1);
+ hole.add_coord(2,1);
+ hole.add_coord(2,2);
+ hole.add_coord(1,2);
+ hole.add_coord(1,1);
+ poly.add_hole(std::move(hole));
+ CHECK( !mapnik::geometry::is_valid(poly) );
+ std::string message;
+ CHECK( !mapnik::geometry::is_valid(poly, message) );
+ CHECK( message == "Geometry has wrong orientation" );
+ boost::geometry::validity_failure_type failure;
+ CHECK( !mapnik::geometry::is_valid(poly, failure) );
+ CHECK( failure == boost::geometry::failure_wrong_orientation );
+}
+
+SECTION("multi polygon") {
+ mapnik::geometry::multi_polygon<double> mp;
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(1,0);
+ ring.add_coord(1,1);
+ ring.add_coord(0,1);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::polygon<double> poly2;
+ mapnik::geometry::linear_ring<double> ring2;
+ ring2.add_coord(0,0);
+ ring2.add_coord(-1,0);
+ ring2.add_coord(-1,-1);
+ ring2.add_coord(0,-1);
+ ring2.add_coord(0,0);
+ poly2.set_exterior_ring(std::move(ring2));
+ mp.emplace_back(poly);
+ mp.emplace_back(poly2);
+ CHECK( mapnik::geometry::is_valid(mp) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(mp, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(mp, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+
+SECTION("multi polygon with hole") {
+ mapnik::geometry::multi_polygon<double> mp;
+ mapnik::geometry::polygon<double> poly;
+ mapnik::geometry::linear_ring<double> ring;
+ ring.add_coord(0,0);
+ ring.add_coord(3,0);
+ ring.add_coord(3,3);
+ ring.add_coord(0,3);
+ ring.add_coord(0,0);
+ poly.set_exterior_ring(std::move(ring));
+ mapnik::geometry::linear_ring<double> hole;
+ hole.add_coord(1,1);
+ hole.add_coord(1,2);
+ hole.add_coord(2,2);
+ hole.add_coord(2,1);
+ hole.add_coord(1,1);
+ poly.add_hole(std::move(hole));
+ mapnik::geometry::polygon<double> poly2;
+ mapnik::geometry::linear_ring<double> ring2;
+ ring2.add_coord(0,0);
+ ring2.add_coord(-3,0);
+ ring2.add_coord(-3,-3);
+ ring2.add_coord(0,-3);
+ ring2.add_coord(0,0);
+ poly2.set_exterior_ring(std::move(ring2));
+ mapnik::geometry::linear_ring<double> hole2;
+ hole2.add_coord(-1,-1);
+ hole2.add_coord(-1,-2);
+ hole2.add_coord(-2,-2);
+ hole2.add_coord(-2,-1);
+ hole2.add_coord(-1,-1);
+ poly2.add_hole(std::move(hole2));
+ mp.emplace_back(poly);
+ mp.emplace_back(poly2);
+ CHECK( mapnik::geometry::is_valid(mp) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(mp, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(mp, failure) );
+ CHECK( failure == boost::geometry::no_failure );
+}
+SECTION("multi polygon empty") {
+ mapnik::geometry::multi_polygon<double> mp;
+ CHECK( mapnik::geometry::is_valid(mp) );
+ std::string message;
+ CHECK( mapnik::geometry::is_valid(mp, message) );
+ CHECK( message == "Geometry is valid");
+ boost::geometry::validity_failure_type failure;
+ CHECK( mapnik::geometry::is_valid(mp, failure) );
+ CHECK( failure == boost::geometry::no_failure );
}
-#endif // BOOST_VERSION >= 1.56
+#endif // BOOST_VERSION >= 1.58
}
diff --git a/test/unit/imaging/image_filter.cpp b/test/unit/imaging/image_filter.cpp
index 0386409..8d41ccb 100644
--- a/test/unit/imaging/image_filter.cpp
+++ b/test/unit/imaging/image_filter.cpp
@@ -6,6 +6,9 @@
#include <mapnik/color.hpp>
#include <mapnik/image_filter.hpp>
#include <mapnik/image_util.hpp>
+#include <mapnik/image_filter_grammar.hpp>
+#include <mapnik/image_filter_grammar_impl.hpp>
+#include <mapnik/css_color_grammar_impl.hpp>
TEST_CASE("image filter") {
@@ -388,6 +391,49 @@ SECTION("test colorize-alpha - two color with transparency") {
} // END SECTION
+SECTION("test colorize-alpha - parsing correct input") {
+
+ mapnik::image_filter_grammar<std::string::const_iterator, std::vector<mapnik::filter::filter_type>> filter_grammar;
+ boost::spirit::qi::ascii::space_type space;
+ std::vector<mapnik::filter::filter_type> f;
+ std::string s("colorize-alpha(#0000ff 0%, #00ff00 100%)");
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), filter_grammar, space, f) );
+ mapnik::filter::colorize_alpha const & ca = mapnik::util::get<mapnik::filter::colorize_alpha>(f.front());
+
+ {
+ mapnik::filter::color_stop const & s2 = ca[0];
+ CHECK( s2.color.alpha() == 0xff );
+ CHECK( s2.color.red() == 0x00 );
+ CHECK( s2.color.green() == 0x00 );
+ CHECK( s2.color.blue() == 0xff );
+ CHECK( s2.offset == 0.0 );
+ }
+
+ {
+ mapnik::filter::color_stop const & s2 = ca[1];
+ CHECK( s2.color.alpha() == 0xff );
+ CHECK( s2.color.red() == 0x00 );
+ CHECK( s2.color.green() == 0xff );
+ CHECK( s2.color.blue() == 0x00 );
+ CHECK( s2.offset == 1.0 );
+ }
+
+} // END SECTION
+
+SECTION("test colorize-alpha - parsing incorrect input") {
+
+ mapnik::image_filter_grammar<std::string::const_iterator, std::vector<mapnik::filter::filter_type>> filter_grammar;
+ boost::spirit::qi::ascii::space_type space;
+ std::string s("colorize-alpha(#0000ff 0%, #00ff00 00 100%)");
+ std::string::const_iterator itr = s.cbegin();
+ std::string::const_iterator end = s.cend();
+ std::vector<mapnik::filter::filter_type> f;
+ CHECK( boost::spirit::qi::phrase_parse(s.cbegin(), s.cend(), filter_grammar, space, f) );
+ CHECK( f.empty() );
+ CHECK( itr != end );
+
+} // END SECTION
+
SECTION("test color-blind-protanope") {
mapnik::image_rgba8 im(2,2);
diff --git a/test/unit/serialization/wkb_formats_test.cpp b/test/unit/serialization/wkb_formats_test.cpp
index 9e18b28..ff72a1c 100644
--- a/test/unit/serialization/wkb_formats_test.cpp
+++ b/test/unit/serialization/wkb_formats_test.cpp
@@ -70,7 +70,7 @@ SECTION("wkb") {
mapnik::wkbSpatiaLite);
// winding order is not correct per OGC so we'll fix it
mapnik::geometry::correct(geom);
-#if BOOST_VERSION >= 105600
+#if BOOST_VERSION >= 105800
REQUIRE(mapnik::geometry::is_valid(geom));
REQUIRE(mapnik::geometry::is_simple(geom));
#endif
@@ -79,7 +79,7 @@ SECTION("wkb") {
sizeof(sp_valid_blob) / sizeof(sp_valid_blob[0]),
mapnik::wkbAuto);
mapnik::geometry::correct(geom);
-#if BOOST_VERSION >= 105600
+#if BOOST_VERSION >= 105800
REQUIRE(mapnik::geometry::is_valid(geom));
REQUIRE(mapnik::geometry::is_simple(geom));
#endif
@@ -94,7 +94,7 @@ SECTION("wkb") {
geom = mapnik::geometry_utils::from_wkb((const char*)sq_valid_blob,
sizeof(sq_valid_blob) / sizeof(sq_valid_blob[0]),
mapnik::wkbGeneric);
-#if BOOST_VERSION >= 105600
+#if BOOST_VERSION >= 105800
REQUIRE(mapnik::geometry::is_valid(geom));
REQUIRE(mapnik::geometry::is_simple(geom));
#endif
@@ -103,7 +103,7 @@ SECTION("wkb") {
sizeof(sq_valid_blob) / sizeof(sq_valid_blob[0]),
mapnik::wkbAuto);
-#if BOOST_VERSION >= 105600
+#if BOOST_VERSION >= 105800
REQUIRE(mapnik::geometry::is_valid(geom));
REQUIRE(mapnik::geometry::is_simple(geom));
#endif
@@ -113,7 +113,9 @@ SECTION("wkb") {
mapnik::wkbGeneric);
REQUIRE(geom.is<mapnik::geometry::geometry_empty>()); // returns geometry_empty
- } catch (std::exception const& ex) {
+ }
+ catch (std::exception const& ex)
+ {
REQUIRE(false);
std::clog << "threw: " << ex.what() << "\n";
}
diff --git a/test/unit/svg/svg_parser_test.cpp b/test/unit/svg/svg_parser_test.cpp
index 276e3c5..6dfb0bd 100644
--- a/test/unit/svg/svg_parser_test.cpp
+++ b/test/unit/svg/svg_parser_test.cpp
@@ -333,6 +333,26 @@ TEST_CASE("SVG parser") {
REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),detail::vertex_equal<3>()));
}
+ SECTION("SVG viewbox fallback")
+ {
+ std::string svg_name("./test/data/svg/viewbox-missing-width-and-height.svg");
+ std::ifstream in(svg_name.c_str());
+ std::string svg_str((std::istreambuf_iterator<char>(in)),
+ std::istreambuf_iterator<char>());
+
+ using namespace mapnik::svg;
+ mapnik::svg_storage_type path;
+ vertex_stl_adapter<svg_path_storage> stl_storage(path.source());
+ svg_path_adapter svg_path(stl_storage);
+ svg_converter_type svg(svg_path, path.attributes());
+ svg_parser p(svg);
+ p.parse_from_string(svg_str);
+ auto width = svg.width();
+ auto height = svg.height();
+ REQUIRE(width == 100);
+ REQUIRE(height == 100);
+ }
+
SECTION("SVG rounded <rect>s missing rx or ry")
{
std::string svg_name("./test/data/svg/rounded_rect-missing-one-radius.svg");
diff --git a/test/visual/renderer.hpp b/test/visual/renderer.hpp
index 6ad9791..6b033f9 100644
--- a/test/visual/renderer.hpp
+++ b/test/visual/renderer.hpp
@@ -33,6 +33,7 @@
#include <mapnik/map.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/image_reader.hpp>
+#include <mapnik/util/variant.hpp>
#include <mapnik/agg_renderer.hpp>
#if defined(GRID_RENDERER)
#include <mapnik/grid/grid_renderer.hpp>
@@ -326,11 +327,23 @@ private:
}
const Renderer ren;
- boost::filesystem::path const & output_dir;
- boost::filesystem::path const & reference_dir;
+ const boost::filesystem::path output_dir;
+ const boost::filesystem::path reference_dir;
const bool overwrite;
};
+using renderer_type = mapnik::util::variant<renderer<agg_renderer>
+#if defined(HAVE_CAIRO)
+ ,renderer<cairo_renderer>
+#endif
+#if defined(SVG_RENDERER)
+ ,renderer<svg_renderer>
+#endif
+#if defined(GRID_RENDERER)
+ ,renderer<grid_renderer>
+#endif
+ >;
+
}
#endif
diff --git a/test/visual/report.cpp b/test/visual/report.cpp
index deaf5b9..c4cfc13 100644
--- a/test/visual/report.cpp
+++ b/test/visual/report.cpp
@@ -161,16 +161,18 @@ void html_report::report(result const & r, boost::filesystem::path const & outpu
copy_file(r.reference_image_path, reference);
copy_file(r.actual_image_path, actual);
- s << "<div class=\"expected\">\n"
- " <a href=" << reference.filename() << ">\n"
- " <img src=" << reference.filename() << " width=\"100\%\">\n"
- " </a>\n"
- "</div>\n"
- "<div class=\"text\">" << r.diff << "</div>\n"
- "<div class=\"actual\">\n"
- " <a href=" << actual.filename() << ">\n"
- " <img src=" << actual.filename() << " width=\"100\%\">\n"
- " </a>\n"
+ s << "<p>" << r.diff << "</p>\n"
+ "<div class=\"r\">"
+ " <div class=\"i\">"
+ " <a href=" << reference.filename() << ">\n"
+ " <img src=" << reference.filename() << " width=\"100\%\">\n"
+ " </a>\n"
+ " </div>\n"
+ " <div class=\"i2\">\n"
+ " <a href=" << actual.filename() << ">\n"
+ " <img src=" << actual.filename() << " width=\"100\%\">\n"
+ " </a>\n"
+ " </div>\n"
"</div>\n";
}
}
@@ -179,31 +181,21 @@ constexpr const char * html_header = R"template(<!DOCTYPE html>
<html>
<head>
<style>
- body { margin:10; padding:10; }
- .expected {
- float:left;
- border-width:1px;
- border-style:solid;
- width:45%;
- }
- .actual {
- float:right;
- border-width:1px;
- border-style:solid;
- width:45%;
- }
- .text {
- float:left;
+ .r {
+ width:100%;
+ display: flex;
+ position: relative;
+ border:1px solid black;
+ margin-bottom: 20px;
}
+ .i2 { max-width: 50%; width:50%; }
+ .i { max-width: 50%; width:50%; }
+ .i:hover{ position: absolute; top:0; left:0; }
+ .i img, .i2 img { width: 100%; }
+ .i img:hover { mix-blend-mode: difference; }
</style>
</head>
<body>
-<script>
-</script>
-<div id='results'>
- <div class="expected">expected</div>
- <div class="text">% difference</div>
- <div class="actual">actual</div>
)template";
constexpr const char * html_footer = R"template(</div>
diff --git a/test/visual/report.hpp b/test/visual/report.hpp
index 837ed5e..bb21baf 100644
--- a/test/visual/report.hpp
+++ b/test/visual/report.hpp
@@ -59,7 +59,7 @@ public:
{
}
- console_short_report(std::ostream & s) : console_report(s)
+ console_short_report(std::ostream & _s) : console_report(_s)
{
}
diff --git a/test/visual/run.cpp b/test/visual/run.cpp
index 833f97b..70284bc 100644
--- a/test/visual/run.cpp
+++ b/test/visual/run.cpp
@@ -43,11 +43,50 @@ log_levels_map log_levels
};
#endif
-int main(int argc, char** argv)
+using namespace visual_tests;
+namespace po = boost::program_options;
+
+runner::renderer_container create_renderers(po::variables_map const & args,
+ boost::filesystem::path const & output_dir,
+ bool append_all = false)
{
- using namespace visual_tests;
- namespace po = boost::program_options;
+ boost::filesystem::path reference_dir(args["images-dir"].as<std::string>());
+ bool overwrite = args.count("overwrite");
+ runner::renderer_container renderers;
+ if (append_all || args.count(agg_renderer::name))
+ {
+ renderers.emplace_back(renderer<agg_renderer>(output_dir, reference_dir, overwrite));
+ }
+#if defined(HAVE_CAIRO)
+ if (append_all || args.count(cairo_renderer::name))
+ {
+ renderers.emplace_back(renderer<cairo_renderer>(output_dir, reference_dir, overwrite));
+ }
+#endif
+#if defined(SVG_RENDERER)
+ if (append_all || args.count(svg_renderer::name))
+ {
+ renderers.emplace_back(renderer<svg_renderer>(output_dir, reference_dir, overwrite));
+ }
+#endif
+#if defined(GRID_RENDERER)
+ if (append_all || args.count(grid_renderer::name))
+ {
+ renderers.emplace_back(renderer<grid_renderer>(output_dir, reference_dir, overwrite));
+ }
+#endif
+
+ if (renderers.empty())
+ {
+ return create_renderers(args, output_dir, true);
+ }
+
+ return renderers;
+}
+
+int main(int argc, char** argv)
+{
po::options_description desc("visual test runner");
desc.add_options()
("help,h", "produce usage message")
@@ -69,6 +108,17 @@ int main(int argc, char** argv)
[](log_levels_map::value_type const & level) { return level.second == mapnik::logger::get_severity(); } )->first),
"log level (debug, warn, error, none)")
#endif
+ ("scale-factor,s", po::value<std::vector<double>>()->default_value({ 1.0, 2.0 }, "1.0, 2.0"), "scale factor")
+ (agg_renderer::name, "render with AGG renderer")
+#if defined(HAVE_CAIRO)
+ (cairo_renderer::name, "render with Cairo renderer")
+#endif
+#if defined(SVG_RENDERER)
+ (svg_renderer::name, "render with SVG renderer")
+#endif
+#if defined(GRID_RENDERER)
+ (grid_renderer::name, "render with Grid renderer")
+#endif
;
po::positional_options_description p;
@@ -107,13 +157,15 @@ int main(int argc, char** argv)
output_dir /= boost::filesystem::unique_path();
}
+ config defaults;
+ defaults.scales = vm["scale-factor"].as<std::vector<double>>();
+
runner run(vm["styles-dir"].as<std::string>(),
- output_dir,
- vm["images-dir"].as<std::string>(),
- vm.count("overwrite"),
+ defaults,
vm["iterations"].as<std::size_t>(),
vm["limit"].as<std::size_t>(),
- vm["jobs"].as<std::size_t>());
+ vm["jobs"].as<std::size_t>(),
+ create_renderers(vm, output_dir));
bool show_duration = vm.count("duration");
report_type report(vm.count("verbose") ? report_type((console_report(show_duration))) : report_type((console_short_report(show_duration))));
result_list results;
diff --git a/test/visual/runner.cpp b/test/visual/runner.cpp
index a987d05..06ade77 100644
--- a/test/visual/runner.cpp
+++ b/test/visual/runner.cpp
@@ -126,29 +126,17 @@ private:
};
runner::runner(runner::path_type const & styles_dir,
- runner::path_type const & output_dir,
- runner::path_type const & reference_dir,
- bool overwrite,
+ config const & defaults,
std::size_t iterations,
std::size_t fail_limit,
- std::size_t jobs)
+ std::size_t jobs,
+ runner::renderer_container const & renderers)
: styles_dir_(styles_dir),
- output_dir_(output_dir),
- reference_dir_(reference_dir),
+ defaults_(defaults),
jobs_(jobs),
iterations_(iterations),
fail_limit_(fail_limit),
- renderers_{ renderer<agg_renderer>(output_dir_, reference_dir_, overwrite)
-#if defined(HAVE_CAIRO)
- ,renderer<cairo_renderer>(output_dir_, reference_dir_, overwrite)
-#endif
-#if defined(SVG_RENDERER)
- ,renderer<svg_renderer>(output_dir_, reference_dir_, overwrite)
-#endif
-#if defined(GRID_RENDERER)
- ,renderer<grid_renderer>(output_dir_, reference_dir_, overwrite)
-#endif
- }
+ renderers_(renderers)
{
}
@@ -225,7 +213,6 @@ result_list runner::test_range(files_iterator begin,
std::reference_wrapper<report_type> report,
std::reference_wrapper<std::atomic<std::size_t>> fail_count) const
{
- config defaults;
result_list results;
for (runner::files_iterator i = begin; i != end; i++)
@@ -235,7 +222,7 @@ result_list runner::test_range(files_iterator begin,
{
try
{
- result_list r = test_one(file, defaults, report, fail_count.get());
+ result_list r = test_one(file, report, fail_count.get());
std::move(r.begin(), r.end(), std::back_inserter(results));
}
catch (std::exception const& ex)
@@ -260,10 +247,10 @@ result_list runner::test_range(files_iterator begin,
}
result_list runner::test_one(runner::path_type const& style_path,
- config cfg,
report_type & report,
std::atomic<std::size_t> & fail_count) const
{
+ config cfg(defaults_);
mapnik::Map map(cfg.sizes.front().width, cfg.sizes.front().height);
result_list results;
diff --git a/test/visual/runner.hpp b/test/visual/runner.hpp
index 65b19bb..e38e394 100644
--- a/test/visual/runner.hpp
+++ b/test/visual/runner.hpp
@@ -23,8 +23,6 @@
#ifndef VISUAL_TEST_RUNNER_HPP
#define VISUAL_TEST_RUNNER_HPP
-#include <mapnik/util/variant.hpp>
-
#include "config.hpp"
#include "report.hpp"
#include "renderer.hpp"
@@ -35,28 +33,18 @@ namespace visual_tests
class runner
{
- using renderer_type = mapnik::util::variant<renderer<agg_renderer>
-#if defined(HAVE_CAIRO)
- ,renderer<cairo_renderer>
-#endif
-#if defined(SVG_RENDERER)
- ,renderer<svg_renderer>
-#endif
-#if defined(GRID_RENDERER)
- ,renderer<grid_renderer>
-#endif
- >;
using path_type = boost::filesystem::path;
using files_iterator = std::vector<path_type>::const_iterator;
public:
+ using renderer_container = std::vector<renderer_type>;
+
runner(path_type const & styles_dir,
- path_type const & output_dir,
- path_type const & reference_dir,
- bool overwrite,
+ config const & cfg,
std::size_t iterations,
std::size_t fail_limit,
- std::size_t jobs);
+ std::size_t jobs,
+ renderer_container const & renderers);
result_list test_all(report_type & report) const;
result_list test(std::vector<std::string> const & style_names, report_type & report) const;
@@ -68,18 +56,17 @@ private:
std::reference_wrapper<report_type> report,
std::reference_wrapper<std::atomic<std::size_t>> fail_limit) const;
result_list test_one(path_type const & style_path,
- config cfg, report_type & report,
+ report_type & report,
std::atomic<std::size_t> & fail_limit) const;
void parse_map_sizes(std::string const & str, std::vector<map_size> & sizes) const;
const map_sizes_grammar<std::string::const_iterator> map_sizes_parser_;
const path_type styles_dir_;
- const path_type output_dir_;
- const path_type reference_dir_;
+ const config defaults_;
const std::size_t jobs_;
const std::size_t iterations_;
const std::size_t fail_limit_;
- const renderer_type renderers_[boost::mpl::size<renderer_type::types>::value];
+ const renderer_container renderers_;
};
}
diff --git a/utils/mapnik-index/build.py b/utils/mapnik-index/build.py
new file mode 100644
index 0000000..02258ca
--- /dev/null
+++ b/utils/mapnik-index/build.py
@@ -0,0 +1,59 @@
+#
+# This file is part of Mapnik (c++ mapping toolkit)
+#
+# Copyright (C) 2015 Artem Pavlenko
+#
+# Mapnik 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
+#
+#
+
+import os
+import glob
+from copy import copy
+
+Import ('env')
+
+program_env = env.Clone()
+
+source = Split(
+ """
+ mapnik-index.cpp
+ """
+ )
+
+#headers = ['#plugins/input/shape'] + env['CPPPATH']
+headers = env['CPPPATH']
+
+boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
+boost_system = 'boost_system%s' % env['BOOST_APPEND']
+libraries = [env['MAPNIK_NAME'], boost_program_options, boost_system]
+libraries.append(env['ICU_LIB_NAME'])
+libraries.append('mapnik-json')
+libraries.append('mapnik-wkt')
+
+if env['RUNTIME_LINK'] == 'static':
+ libraries.extend(copy(env['LIBMAPNIK_LIBS']))
+ if env['PLATFORM'] == 'Linux':
+ libraries.append('dl')
+
+mapnik_index = program_env.Program('mapnik-index', source, CPPPATH=headers, LIBS=libraries)
+
+Depends(mapnik_index, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME']))
+
+if 'uninstall' not in COMMAND_LINE_TARGETS:
+ env.Install(os.path.join(env['INSTALL_PREFIX'],'bin'), mapnik_index)
+ env.Alias('install', os.path.join(env['INSTALL_PREFIX'],'bin'))
+
+env['create_uninstall_target'](env, os.path.join(env['INSTALL_PREFIX'],'bin','mapnik-index'))
diff --git a/utils/mapnik-index/mapnik-index.cpp b/utils/mapnik-index/mapnik-index.cpp
new file mode 100644
index 0000000..0f54d4c
--- /dev/null
+++ b/utils/mapnik-index/mapnik-index.cpp
@@ -0,0 +1,353 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2015 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 <iostream>
+#include <vector>
+#include <string>
+#include <fstream>
+
+#include <mapnik/util/fs.hpp>
+#include <mapnik/geometry_envelope.hpp>
+#include <mapnik/quad_tree.hpp>
+#include "../../plugins/input/csv/csv_utils.hpp"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#pragma GCC diagnostic ignored "-Wunused-local-typedef"
+#include <boost/algorithm/string.hpp>
+#include <boost/program_options.hpp>
+#pragma GCC diagnostic pop
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
+#include <boost/interprocess/mapped_region.hpp>
+#include <boost/interprocess/streams/bufferstream.hpp>
+#pragma GCC diagnostic pop
+#include <mapnik/mapped_memory_cache.hpp>
+#include <boost/version.hpp>
+
+const int DEFAULT_DEPTH = 8;
+const double DEFAULT_RATIO = 0.55;
+
+int main (int argc, char** argv)
+{
+ //using namespace mapnik;
+ namespace po = boost::program_options;
+ using std::string;
+ using std::vector;
+ using std::clog;
+ using std::endl;
+
+ bool verbose = false;
+ unsigned int depth = DEFAULT_DEPTH;
+ double ratio = DEFAULT_RATIO;
+ vector<string> csv_files;
+ char separator = 0;
+ char quote = 0;
+ std::string manual_headers;
+ try
+ {
+ po::options_description desc("csvindex utility");
+ desc.add_options()
+ ("help,h", "produce usage message")
+ ("version,V","print version string")
+ ("verbose,v","verbose output")
+ ("depth,d", po::value<unsigned int>(), "max tree depth\n(default 8)")
+ ("ratio,r",po::value<double>(),"split ratio (default 0.55)")
+ ("separator,s", po::value<char>(), "CSV columns separator")
+ ("quote,q", po::value<char>(), "CSV columns quote")
+ ("manual-headers,H", po::value<std::string>(), "CSV manual headers string")
+ ("csv_files",po::value<vector<string> >(),"CSV files to index: file1 file2 ...fileN")
+ ;
+
+ po::positional_options_description p;
+ p.add("csv_files",-1);
+ po::variables_map vm;
+ po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
+ po::notify(vm);
+
+ if (vm.count("version"))
+ {
+ clog << "version 0.3.0" <<std::endl;
+ return 1;
+ }
+
+ if (vm.count("help"))
+ {
+ clog << desc << endl;
+ return 1;
+ }
+ if (vm.count("verbose"))
+ {
+ verbose = true;
+ }
+ if (vm.count("depth"))
+ {
+ depth = vm["depth"].as<unsigned int>();
+ }
+ if (vm.count("ratio"))
+ {
+ ratio = vm["ratio"].as<double>();
+ }
+ if (vm.count("separator"))
+ {
+ separator = vm["separator"].as<char>();
+ }
+ if (vm.count("quote"))
+ {
+ quote = vm["quote"].as<char>();
+ }
+ if (vm.count("manual-headers"))
+ {
+ manual_headers = vm["manual-headers"].as<std::string>();
+ }
+ if (vm.count("csv_files"))
+ {
+ csv_files=vm["csv_files"].as< vector<string> >();
+ }
+ }
+ catch (std::exception const& ex)
+ {
+ clog << "Error: " << ex.what() << endl;
+ return -1;
+ }
+
+ clog << "max tree depth:" << depth << endl;
+ clog << "split ratio:" << ratio << endl;
+
+ if (csv_files.size() == 0)
+ {
+ clog << "no csv files to index" << endl;
+ return 0;
+ }
+
+ for (auto const& filename : csv_files)
+ {
+ clog << "processing " << filename << endl;
+ std::string csvname (filename);
+ if (! mapnik::util::exists (csvname))
+ {
+ clog << "Error : file " << csvname << " does not exist" << endl;
+ continue;
+ }
+ using file_source_type = boost::interprocess::ibufferstream;
+ file_source_type csv_file;
+
+ mapnik::mapped_region_ptr mapped_region;
+ boost::optional<mapnik::mapped_region_ptr> memory =
+ mapnik::mapped_memory_cache::instance().find(csvname, true);
+ if (memory)
+ {
+ mapped_region = *memory;
+ csv_file.buffer(static_cast<char*>(mapped_region->get_address()),mapped_region->get_size());
+ }
+ else
+ {
+ clog << "Error : cannot mmap " << csvname << endl;
+ continue;
+ }
+ auto file_length = detail::file_length(csv_file);
+ // set back to start
+ csv_file.seekg(0, std::ios::beg);
+ char newline;
+ bool has_newline;
+ char detected_quote;
+ std::tie(newline, has_newline, detected_quote) = detail::autodect_newline_and_quote(csv_file, file_length);
+ if (quote == 0) quote = detected_quote;
+ // set back to start
+ csv_file.seekg(0, std::ios::beg);
+ // get first line
+ std::string csv_line;
+ csv_utils::getline_csv(csv_file, csv_line, newline, quote);
+ if (separator == 0) separator = detail::detect_separator(csv_line);
+ csv_file.seekg(0, std::ios::beg);
+ int line_number = 1;
+ detail::geometry_column_locator locator;
+ std::vector<std::string> headers;
+ std::clog << "Parsing CSV using SEPARATOR=" << separator << " QUOTE=" << quote << std::endl;
+ if (!manual_headers.empty())
+ {
+ std::size_t index = 0;
+ headers = csv_utils::parse_line(manual_headers, separator, quote);
+ for (auto const& header : headers)
+ {
+ detail::locate_geometry_column(header, index++, locator);
+ headers.push_back(header);
+ }
+ }
+ else // parse first line as headers
+ {
+ while (csv_utils::getline_csv(csv_file,csv_line,newline, quote))
+ {
+ try
+ {
+ headers = csv_utils::parse_line(csv_line, separator, quote);
+ // skip blank lines
+ if (headers.size() > 0 && headers[0].empty()) ++line_number;
+ else
+ {
+ std::size_t index = 0;
+ for (auto & header : headers)
+ {
+ if (header.empty())
+ {
+ // create a placeholder for the empty header
+ std::ostringstream s;
+ s << "_" << index;
+ header = s.str();
+ }
+ else
+ {
+ detail::locate_geometry_column(header, index, locator);
+ }
+ ++index;
+ }
+ ++line_number;
+ break;
+ }
+ }
+ catch (std::exception const& ex)
+ {
+ std::string s("CSV index: error parsing headers: ");
+ s += ex.what();
+ std::clog << s << std::endl;
+ return 1;
+ }
+ }
+ }
+
+ if (locator.type == detail::geometry_column_locator::UNKNOWN)
+ {
+ std::clog << "CSV index: could not detect column headers with the name of wkt, geojson, x/y, or "
+ << "latitude/longitude - this is required for reading geometry data" << std::endl;
+ return 1;
+ }
+
+ std::size_t num_headers = headers.size();
+ auto pos = csv_file.tellg();
+
+ // handle rare case of a single line of data and user-provided headers
+ // where a lack of a newline will mean that csv_utils::getline_csv returns false
+ bool is_first_row = false;
+ if (!has_newline)
+ {
+ csv_file.setstate(std::ios::failbit);
+ pos = 0;
+ if (!csv_line.empty())
+ {
+ is_first_row = true;
+ }
+ }
+
+ mapnik::box2d<double> extent;
+ using box_type = mapnik::box2d<double>;
+ using item_type = std::pair<box_type, std::pair<unsigned, unsigned>>;
+ std::vector<item_type> boxes;
+
+ while (is_first_row || csv_utils::getline_csv(csv_file, csv_line, newline, quote))
+ {
+ auto record_offset = pos;
+ auto record_size = csv_line.length();
+ pos = csv_file.tellg();
+ is_first_row = false;
+ // skip blank lines
+ if (record_size <= 10)
+ {
+ std::string trimmed = csv_line;
+ boost::trim_if(trimmed, boost::algorithm::is_any_of("\",'\r\n "));
+ if (trimmed.empty())
+ {
+ std::clog << "CSV index: empty row encountered at line: " << line_number << std::endl;
+ continue;
+ }
+ }
+ try
+ {
+ auto values = csv_utils::parse_line(csv_line, separator, quote);
+ unsigned num_fields = values.size();
+ if (num_fields > num_headers || num_fields < num_headers)
+ {
+ std::ostringstream s;
+ s << "CSV Index: # of columns("
+ << num_fields << ") > # of headers("
+ << num_headers << ") parsed for row " << line_number << "\n";
+ std::clog << s.str() << std::endl;
+ return 1;
+ }
+
+ auto geom = detail::extract_geometry(values, locator);
+ if (!geom.is<mapnik::geometry::geometry_empty>())
+ {
+ auto box = mapnik::geometry::envelope(geom);
+ if (!extent.valid()) extent = box;
+ else extent.expand_to_include(box);
+ boxes.emplace_back(std::move(box), make_pair(record_offset, record_size));
+ }
+ else
+ {
+ std::ostringstream s;
+ s << "CSV Index: expected geometry column: could not parse row "
+ << line_number << " "
+ << values[locator.index] << "'";
+ std::clog << s.str() << std::endl;;
+ }
+ }
+ catch (std::exception const& ex)
+ {
+ std::ostringstream s;
+ s << "CSV Index: unexpected error parsing line: " << line_number
+ << " - found " << headers.size() << " with values like: " << csv_line << "\n"
+ << " and got error like: " << ex.what();
+ std::clog << s.str() << std::endl;
+ return 1;
+ }
+ }
+
+ std::clog << extent << std::endl;
+ mapnik::quad_tree<std::pair<std::size_t, std::size_t>> tree(extent, depth, ratio);
+ for (auto const& item : boxes)
+ {
+ tree.insert(std::get<1>(item), std::get<0>(item));
+ }
+
+ std::fstream file((csvname + ".index").c_str(),
+ std::ios::in | std::ios::out | std::ios::trunc | std::ios::binary);
+ if (!file)
+ {
+ clog << "cannot open index file for writing file \""
+ << (csvname + ".index") << "\"" << endl;
+ }
+ else
+ {
+ tree.trim();
+ std::clog << "number nodes=" << tree.count() << std::endl;
+ //tree.print();
+ file.exceptions(std::ios::failbit | std::ios::badbit);
+ tree.write(file);
+ file.flush();
+ file.close();
+ }
+ }
+ clog << "done!" << endl;
+ return 0;
+}
diff --git a/utils/pgsql2sqlite/pgsql2sqlite.hpp b/utils/pgsql2sqlite/pgsql2sqlite.hpp
index 5c5a640..f188e08 100644
--- a/utils/pgsql2sqlite/pgsql2sqlite.hpp
+++ b/utils/pgsql2sqlite/pgsql2sqlite.hpp
@@ -388,7 +388,7 @@ void pgsql2sqlite(Connection conn,
{
if (oid == geometry_oid)
{
- mapnik::Feature feat(ctx,pkid);
+ mapnik::feature_impl feat(ctx,pkid);
mapnik::geometry::geometry<double> geom = geometry_utils::from_wkb(buf, size, wkbGeneric);
if (!mapnik::geometry::is_empty(geom))
{
diff --git a/utils/shapeindex/quadtree.hpp b/utils/shapeindex/quadtree.hpp
deleted file mode 100644
index 440ce50..0000000
--- a/utils/shapeindex/quadtree.hpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*****************************************************************************
- *
- * This file is part of Mapnik (c++ mapping toolkit)
- *
- * Copyright (C) 2015 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
- *
- *****************************************************************************/
-
-#ifndef QUADTREE_HPP
-#define QUADTREE_HPP
-// stl
-#include <cstring>
-#include <vector>
-#include <fstream>
-#include <iostream>
-// mapnik
-#include <mapnik/box2d.hpp>
-
-using mapnik::box2d;
-using mapnik::coord2d;
-
-template <typename T>
-struct quadtree_node
-{
- box2d<double> ext_;
- std::vector<T> data_;
- quadtree_node<T>* children_[4];
- quadtree_node(const box2d<double>& ext)
- : ext_(ext),data_()
- {
- std::memset(children_,0,sizeof(quadtree_node<T>*)*4);
- }
-
- ~quadtree_node()
- {
- for (int i=0;i<4;++i)
- {
- if (children_[i])
- {
- delete children_[i],children_[i]=0;
- }
- }
- }
-
- int num_subnodes() const
- {
- int count=0;
- for (int i=0;i<4;++i)
- {
- if (children_[i])
- {
- ++count;
- }
- }
- return count;
- }
-};
-
-template <typename T>
-class quadtree
-{
-private:
- quadtree_node<T>* root_;
- const int maxdepth_;
- const double ratio_;
-public:
- quadtree(const box2d<double>& extent,int maxdepth,double ratio)
- : root_(new quadtree_node<T>(extent)),
- maxdepth_(maxdepth),
- ratio_(ratio) {}
-
- ~quadtree()
- {
- if (root_) delete root_;
- }
-
- void insert(const T& data,const box2d<double>& item_ext)
- {
- insert(data,item_ext,root_,maxdepth_);
- }
-
- int count() const
- {
- return count_nodes(root_);
- }
-
- int count_items() const
- {
- int count=0;
- count_items(root_,count);
- return count;
- }
-
- void print() const
- {
- print(root_);
- }
-
- void trim()
- {
- trim_tree(root_);
- }
-
- void write(std::ostream& out)
- {
- char header[16];
- std::memset(header,0,16);
- header[0]='m';
- header[1]='a';
- header[2]='p';
- header[3]='n';
- header[4]='i';
- header[5]='k';
- out.write(header,16);
- write_node(out,root_);
- }
-
-private:
-
- void trim_tree(quadtree_node<T>*& node)
- {
- if (node)
- {
- for (int i=0;i<4;++i)
- {
- trim_tree(node->children_[i]);
- }
-
- if (node->num_subnodes()==1 && node->data_.size()==0)
- {
- for (int i=0;i<4;++i)
- {
- if (node->children_[i])
- {
- node=node->children_[i];
- break;
- }
- }
- }
- }
- }
-
- int count_nodes(const quadtree_node<T>* node) const
- {
- if (!node)
- {
- return 0;
- }
- else
- {
- int count = 1;
- for (int i=0;i<4;++i)
- {
- count += count_nodes(node->children_[i]);
- }
- return count;
- }
- }
-
- void count_items(const quadtree_node<T>* node,int& count) const
- {
- if (node)
- {
- count += node->data_.size();
- for (int i=0;i<4;++i)
- {
- count_items(node->children_[i],count);
- }
- }
- }
-
- int subnode_offset(const quadtree_node<T>* node) const
- {
- int offset=0;
- for (int i=0;i<4;i++)
- {
- if (node->children_[i])
- {
- offset +=sizeof(box2d<double>)+(node->children_[i]->data_.size()*sizeof(T))+3*sizeof(int);
- offset +=subnode_offset(node->children_[i]);
- }
- }
- return offset;
- }
-
- void write_node(std::ostream& out,const quadtree_node<T>* node) const
- {
- if (node)
- {
- int offset=subnode_offset(node);
- int shape_count=node->data_.size();
- int recsize=sizeof(box2d<double>) + 3 * sizeof(int) + shape_count * sizeof(T);
- char* node_record=new char[recsize];
- std::memset(node_record,0,recsize);
- std::memcpy(node_record,&offset,4);
- std::memcpy(node_record+4,&node->ext_,sizeof(box2d<double>));
- std::memcpy(node_record+36,&shape_count,4);
- for (int i=0;i<shape_count;++i)
- {
- memcpy(node_record + 40 + i * sizeof(T),&(node->data_[i]),sizeof(T));
- }
- int num_subnodes=0;
- for (int i=0;i<4;++i)
- {
- if (node->children_[i])
- {
- ++num_subnodes;
- }
- }
- std::memcpy(node_record + 40 + shape_count * sizeof(T),&num_subnodes,4);
- out.write(node_record,recsize);
- delete [] node_record;
-
- for (int i=0;i<4;++i)
- {
- write_node(out,node->children_[i]);
- }
- }
- }
-
- void print(const quadtree_node<T>* node,int level=0) const
- {
- if (node)
- {
- typename std::vector<T>::const_iterator itr=node->data_.begin();
- std::string pad;
- for (int i=0;i<level;++i)
- {
- pad+=" ";
- }
- std::clog<<pad<<"node "<<node<<" extent:"<<node->ext_<<std::endl;
- std::clog<<pad;
- while(itr!=node->data_.end())
- {
- std::clog<<*itr<<" ";
- ++itr;
- }
- std::clog<<std::endl;
- for (int i=0;i<4;++i)
- {
- print(node->children_[i],level+4);
- }
- }
- }
-
- void insert(const T& data,const box2d<double>& item_ext,quadtree_node<T>* node,int maxdepth)
- {
- if (node && node->ext_.contains(item_ext))
- {
- double width=node->ext_.width();
- double height=node->ext_.height();
-
- double lox=node->ext_.minx();
- double loy=node->ext_.miny();
- double hix=node->ext_.maxx();
- double hiy=node->ext_.maxy();
-
- box2d<double> ext[4];
- ext[0]=box2d<double>(lox,loy,lox + width * ratio_,loy + height * ratio_);
- ext[1]=box2d<double>(hix - width * ratio_,loy,hix,loy + height * ratio_);
- ext[2]=box2d<double>(lox,hiy - height*ratio_,lox + width * ratio_,hiy);
- ext[3]=box2d<double>(hix - width * ratio_,hiy - height*ratio_,hix,hiy);
-
- if (maxdepth > 1)
- {
- for (int i=0;i<4;++i)
- {
- if (ext[i].contains(item_ext))
- {
- if (!node->children_[i])
- {
- node->children_[i]=new quadtree_node<T>(ext[i]);
- }
- insert(data,item_ext,node->children_[i],maxdepth-1);
- return;
- }
- }
- }
- node->data_.push_back(data);
- }
- }
-};
-#endif //QUADTREE_HPP
diff --git a/utils/shapeindex/shapeindex.cpp b/utils/shapeindex/shapeindex.cpp
index 435daba..6b2324f 100644
--- a/utils/shapeindex/shapeindex.cpp
+++ b/utils/shapeindex/shapeindex.cpp
@@ -25,7 +25,7 @@
#include <vector>
#include <string>
#include <mapnik/util/fs.hpp>
-#include "quadtree.hpp"
+#include <mapnik/quad_tree.hpp>
#include "shapefile.hpp"
#include "shape_io.hpp"
@@ -73,7 +73,7 @@ int main (int argc,char** argv)
if (vm.count("version"))
{
- clog<<"version 0.3.0" <<std::endl;
+ clog << "version 0.3.0" <<std::endl;
return 1;
}
@@ -153,7 +153,7 @@ int main (int argc,char** argv)
int pos=50;
shp.seek(pos*2);
- quadtree<int> tree(extent,depth,ratio);
+ mapnik::quad_tree<int> tree(extent,depth,ratio);
int count=0;
while (true) {
@@ -240,7 +240,7 @@ int main (int argc,char** argv)
<< (shapename+".index") << "\"" << endl;
} else {
tree.trim();
- std::clog<<" number nodes="<<tree.count()<<std::endl;
+ std::clog << " number nodes=" << tree.count() << std::endl;
file.exceptions(std::ios::failbit | std::ios::badbit);
tree.write(file);
file.flush();
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mapnik.git
More information about the Pkg-grass-devel
mailing list