Merge pull request #2776 from mapnik/split-python

Split python
This commit is contained in:
Dane Springmeyer 2015-04-25 06:01:36 +02:00
commit a8b4793642
2531 changed files with 624 additions and 103541 deletions

View file

@ -28,8 +28,6 @@ install:
script: script:
- source bootstrap.sh - source bootstrap.sh
- wget https://gist.githubusercontent.com/springmeyer/0833fa43794838889139/raw/build_pycairo.sh && chmod +x build_pycairo.sh && ./build_pycairo.sh
- export PYTHONPATH=$(pwd)/mason_packages/.link/lib/python2.7/site-packages:${PYTHONPATH}
- if [[ ${COVERAGE} == true ]]; then ./configure CUSTOM_LDFLAGS='--coverage' CUSTOM_CXXFLAGS='--coverage' CUSTOM_CFLAGS='--coverage' DEBUG=True; else ./configure; fi; - if [[ ${COVERAGE} == true ]]; then ./configure CUSTOM_LDFLAGS='--coverage' CUSTOM_CXXFLAGS='--coverage' CUSTOM_CFLAGS='--coverage' DEBUG=True; else ./configure; fi;
- make - make
- git clone --depth=1 https://github.com/mapbox/mapnik-test-data tests/data/mapnik-test-data - git clone --depth=1 https://github.com/mapbox/mapnik-test-data tests/data/mapnik-test-data

View file

@ -46,7 +46,6 @@ clean:
@find ./ -name "*.so" -exec rm {} \; @find ./ -name "*.so" -exec rm {} \;
@find ./ -name "*.o" -exec rm {} \; @find ./ -name "*.o" -exec rm {} \;
@find ./ -name "*.a" -exec rm {} \; @find ./ -name "*.a" -exec rm {} \;
@if test -e "bindings/python/mapnik/paths.py"; then rm "bindings/python/mapnik/paths.py"; fi
distclean: distclean:
if test -e "config.py"; then mv "config.py" "config.py.backup"; fi if test -e "config.py"; then mv "config.py" "config.py.backup"; fi
@ -65,12 +64,6 @@ test:
test-local: test-local:
make test make test
test-visual:
bash -c "source ./localize.sh && python tests/visual_tests/test.py -q"
test-python:
bash -c "source ./localize.sh && python tests/run_tests.py -q"
test-cpp: test-cpp:
./tests/cpp_tests/run ./tests/cpp_tests/run

View file

@ -78,7 +78,6 @@ pretty_dep_names = {
'gdal':'GDAL C++ library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/GDAL', 'gdal':'GDAL C++ library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/GDAL',
'ogr':'OGR-enabled GDAL C++ Library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/OGR', 'ogr':'OGR-enabled GDAL C++ Library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki/OGR',
'cairo':'Cairo C library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option', 'cairo':'Cairo C library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option',
'pycairo':'Python bindings to Cairo library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option',
'proj':'Proj.4 C Projections library | configure with PROJ_LIBS & PROJ_INCLUDES | more info: http://trac.osgeo.org/proj/', 'proj':'Proj.4 C Projections library | configure with PROJ_LIBS & PROJ_INCLUDES | more info: http://trac.osgeo.org/proj/',
'pg':'Postgres C Library required for PostGIS plugin | configure with pg_config program or configure with PG_LIBS & PG_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/PostGIS', 'pg':'Postgres C Library required for PostGIS plugin | configure with pg_config program or configure with PG_LIBS & PG_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/PostGIS',
'sqlite3':'SQLite3 C Library | configure with SQLITE_LIBS & SQLITE_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/SQLite', 'sqlite3':'SQLite3 C Library | configure with SQLITE_LIBS & SQLITE_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/SQLite',
@ -320,7 +319,6 @@ opts.AddVariables(
# Install Variables # Install Variables
('PREFIX', 'The install path "prefix"', '/usr/local'), ('PREFIX', 'The install path "prefix"', '/usr/local'),
('LIBDIR_SCHEMA', 'The library sub-directory appended to the "prefix", sometimes lib64 on 64bit linux systems', LIBDIR_SCHEMA_DEFAULT), ('LIBDIR_SCHEMA', 'The library sub-directory appended to the "prefix", sometimes lib64 on 64bit linux systems', LIBDIR_SCHEMA_DEFAULT),
('PYTHON_PREFIX','Custom install path "prefix" for python bindings (default of no prefix)',''),
('DESTDIR', 'The root directory to install into. Useful mainly for binary package building', '/'), ('DESTDIR', 'The root directory to install into. Useful mainly for binary package building', '/'),
('PATH', 'A custom path (or multiple paths divided by ":") to append to the $PATH env to prioritize usage of command line programs (if multiple are present on the system)', ''), ('PATH', 'A custom path (or multiple paths divided by ":") to append to the $PATH env to prioritize usage of command line programs (if multiple are present on the system)', ''),
('PATH_REMOVE', 'A path prefix to exclude from all known command and compile paths (create multiple excludes separated by :)', ''), ('PATH_REMOVE', 'A path prefix to exclude from all known command and compile paths (create multiple excludes separated by :)', ''),
@ -335,7 +333,6 @@ opts.AddVariables(
('BOOST_TOOLKIT','Specify boost toolkit, e.g., gcc41.','',False), ('BOOST_TOOLKIT','Specify boost toolkit, e.g., gcc41.','',False),
('BOOST_ABI', 'Specify boost ABI, e.g., d.','',False), ('BOOST_ABI', 'Specify boost ABI, e.g., d.','',False),
('BOOST_VERSION','Specify boost version, e.g., 1_35.','',False), ('BOOST_VERSION','Specify boost version, e.g., 1_35.','',False),
('BOOST_PYTHON_LIB','Specify library name to specific Boost Python lib (e.g. "boost_python-py26")','boost_python'),
# Variables for required dependencies # Variables for required dependencies
('FREETYPE_CONFIG', 'The path to the freetype-config executable.', 'freetype-config'), ('FREETYPE_CONFIG', 'The path to the freetype-config executable.', 'freetype-config'),
@ -403,12 +400,8 @@ opts.AddVariables(
('SYSTEM_FONTS','Provide location for python bindings to register fonts (if provided then the bundled DejaVu fonts are not installed)',''), ('SYSTEM_FONTS','Provide location for python bindings to register fonts (if provided then the bundled DejaVu fonts are not installed)',''),
('LIB_DIR_NAME','Name to use for the subfolder beside libmapnik where fonts and plugins are installed','mapnik'), ('LIB_DIR_NAME','Name to use for the subfolder beside libmapnik where fonts and plugins are installed','mapnik'),
PathVariable('PYTHON','Full path to Python executable used to build bindings', sys.executable), PathVariable('PYTHON','Full path to Python executable used to build bindings', sys.executable),
BoolVariable('FRAMEWORK_PYTHON', 'Link against Framework Python on Mac OS X', 'True'),
BoolVariable('PYTHON_DYNAMIC_LOOKUP', 'On OSX, do not directly link python lib, but rather dynamically lookup symbols', 'True'),
('FRAMEWORK_SEARCH_PATH','Custom framework search path on Mac OS X', ''),
BoolVariable('FULL_LIB_PATH', 'Embed the full and absolute path to libmapnik when linking ("install_name" on OS X/rpath on Linux)', 'True'), BoolVariable('FULL_LIB_PATH', 'Embed the full and absolute path to libmapnik when linking ("install_name" on OS X/rpath on Linux)', 'True'),
BoolVariable('ENABLE_SONAME', 'Embed a soname in libmapnik on Linux', 'True'), BoolVariable('ENABLE_SONAME', 'Embed a soname in libmapnik on Linux', 'True'),
ListVariable('BINDINGS','Language bindings to build','all',['python']),
EnumVariable('THREADING','Set threading support','multi', ['multi','single']), EnumVariable('THREADING','Set threading support','multi', ['multi','single']),
EnumVariable('XMLPARSER','Set xml parser','libxml2', ['libxml2','ptree']), EnumVariable('XMLPARSER','Set xml parser','libxml2', ['libxml2','ptree']),
BoolVariable('DEMO', 'Compile demo c++ application', 'True'), BoolVariable('DEMO', 'Compile demo c++ application', 'True'),
@ -452,17 +445,12 @@ pickle_store = [# Scons internal variables
'BOOST_APPEND', 'BOOST_APPEND',
'LIBDIR_SCHEMA', 'LIBDIR_SCHEMA',
'REQUESTED_PLUGINS', 'REQUESTED_PLUGINS',
'PYTHON_VERSION',
'PYTHON_INCLUDES',
'PYTHON_INSTALL_LOCATION',
'PYTHON_SYS_PREFIX',
'COLOR_PRINT', 'COLOR_PRINT',
'HAS_CAIRO', 'HAS_CAIRO',
'MAPNIK_HAS_DLFCN', 'MAPNIK_HAS_DLFCN',
'HAS_PYCAIRO', 'HAS_PYCAIRO',
'PYCAIRO_PATHS', 'PYCAIRO_PATHS',
'HAS_LIBXML2', 'HAS_LIBXML2',
'PYTHON_IS_64BIT',
'SAMPLE_INPUT_PLUGINS', 'SAMPLE_INPUT_PLUGINS',
'PKG_CONFIG_PATH', 'PKG_CONFIG_PATH',
'PATH', 'PATH',
@ -1145,7 +1133,6 @@ if not preconfigured:
env['PLUGINS'] = PLUGINS env['PLUGINS'] = PLUGINS
env['EXTRA_FREETYPE_LIBS'] = [] env['EXTRA_FREETYPE_LIBS'] = []
env['SQLITE_LINKFLAGS'] = [] env['SQLITE_LINKFLAGS'] = []
env['PYTHON_INCLUDES'] = []
# previously a leading / was expected for LIB_DIR_NAME # previously a leading / was expected for LIB_DIR_NAME
# now strip it to ensure expected behavior # now strip it to ensure expected behavior
if env['LIB_DIR_NAME'].startswith(os.path.sep): if env['LIB_DIR_NAME'].startswith(os.path.sep):
@ -1646,94 +1633,6 @@ if not preconfigured:
env['SKIPPED_DEPS'].append('cairo') env['SKIPPED_DEPS'].append('cairo')
env['HAS_CAIRO'] = False env['HAS_CAIRO'] = False
if 'python' in env['BINDINGS']:
if not os.access(env['PYTHON'], os.X_OK):
color_print(1,"Cannot run python interpreter at '%s', make sure that you have the permissions to execute it." % env['PYTHON'])
Exit(1)
py3 = 'True' in os.popen('''%s -c "import sys as s;s.stdout.write(str(s.version_info[0] == 3))"''' % env['PYTHON']).read().strip()
if py3:
sys_prefix = '''%s -c "import sys; print(sys.prefix)"''' % env['PYTHON']
else:
sys_prefix = '''%s -c "import sys; print sys.prefix"''' % env['PYTHON']
env['PYTHON_SYS_PREFIX'] = call(sys_prefix)
if HAS_DISTUTILS:
if py3:
sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print(get_python_version())"''' % env['PYTHON']
else:
sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print get_python_version()"''' % env['PYTHON']
env['PYTHON_VERSION'] = call(sys_version)
if py3:
py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())"''' % env['PYTHON']
else:
py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print get_python_inc()"''' % env['PYTHON']
env['PYTHON_INCLUDES'].append(call(py_includes))
# also append platform specific includes
if py3:
py_plat_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print(get_python_inc(plat_specific=True))"''' % env['PYTHON']
else:
py_plat_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print get_python_inc(plat_specific=True)"''' % env['PYTHON']
env['PYTHON_INCLUDES'].append(call(py_plat_includes))
# Note: we use the plat_specific argument here to make sure to respect the arch-specific site-packages location
if py3:
site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True))"''' % env['PYTHON']
else:
site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print get_python_lib(plat_specific=True)"''' % env['PYTHON']
env['PYTHON_SITE_PACKAGES'] = call(site_packages)
else:
env['PYTHON_SYS_PREFIX'] = os.popen('''%s -c "import sys; print sys.prefix"''' % env['PYTHON']).read().strip()
env['PYTHON_VERSION'] = os.popen('''%s -c "import sys; print sys.version"''' % env['PYTHON']).read()[0:3]
env['PYTHON_INCLUDES'] = [env['PYTHON_SYS_PREFIX'] + '/include/python' + env['PYTHON_VERSION']]
env['PYTHON_SITE_PACKAGES'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SYS_PREFIX'] + os.path.sep + env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/'
# if user-requested custom prefix fall back to manual concatenation for building subdirectories
if env['PYTHON_PREFIX']:
py_relative_install = env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/'
env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_PREFIX'] + os.path.sep + py_relative_install
else:
env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SITE_PACKAGES']
if py3:
is_64_bit = '''%s -c "import sys; print(sys.maxsize == 9223372036854775807)"''' % env['PYTHON']
else:
is_64_bit = '''%s -c "import sys; print sys.maxint == 9223372036854775807"''' % env['PYTHON']
if is_64_bit:
env['PYTHON_IS_64BIT'] = True
else:
env['PYTHON_IS_64BIT'] = False
if has_boost_devel and 'python' in env['BINDINGS']:
if py3 and env['BOOST_PYTHON_LIB'] == 'boost_python':
env['BOOST_PYTHON_LIB'] = 'boost_python3%s' % env['BOOST_APPEND']
elif env['BOOST_PYTHON_LIB'] == 'boost_python':
env['BOOST_PYTHON_LIB'] = 'boost_python%s' % env['BOOST_APPEND']
if not env['HOST']:
if not conf.CheckHeader(header='boost/python/detail/config.hpp',language='C++'):
color_print(1,'Could not find required header files for boost python')
env['MISSING_DEPS'].append('boost python')
if env['CAIRO']:
if CHECK_PKG_CONFIG and conf.CheckPKG('pycairo'):
env['HAS_PYCAIRO'] = True
temp_env = env.Clone()
temp_env['CPPPATH'] = []
temp_env.ParseConfig('pkg-config --cflags pycairo')
if temp_env['CPPPATH']:
env['PYCAIRO_PATHS'] = copy(temp_env['CPPPATH'])
else:
print temp_env['CPPPATH']
else:
env['SKIPPED_DEPS'].extend(['pycairo'])
else:
color_print(4,'Not building with pycairo support, pass CAIRO=True to enable')
#### End Config Stage for Required Dependencies #### #### End Config Stage for Required Dependencies ####
if env['MISSING_DEPS']: if env['MISSING_DEPS']:
@ -1864,29 +1763,6 @@ if not preconfigured:
if env['DEBUG_UNDEFINED']: if env['DEBUG_UNDEFINED']:
env.Append(CXXFLAGS = '-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -ftrapv -fwrapv') env.Append(CXXFLAGS = '-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -ftrapv -fwrapv')
if 'python' in env['BINDINGS']:
majver, minver = env['PYTHON_VERSION'].split('.')
# we don't want the includes it in the main environment...
# as they are later set in the python build.py
# ugly hack needed until we have env specific conf
backup = env.Clone().Dictionary()
for pyinc in env['PYTHON_INCLUDES']:
env.AppendUnique(CPPPATH = fix_path(pyinc))
if not conf.CheckHeader(header='Python.h',language='C'):
color_print(1,'Could not find required header files for the Python language (version %s)' % env['PYTHON_VERSION'])
Exit(1)
if (int(majver), int(minver)) < (2, 2):
color_print(1,"Python version 2.2 or greater required")
Exit(1)
if 'python' in env['BINDINGS']:
color_print(4,'Bindings Python version... %s' % env['PYTHON_VERSION'])
color_print(4,'Python %s prefix... %s' % (env['PYTHON_VERSION'], env['PYTHON_SYS_PREFIX']))
color_print(4,'Python bindings will install in... %s' % os.path.normpath(env['PYTHON_INSTALL_LOCATION']))
env.Replace(**backup)
# if requested, sort LIBPATH and CPPPATH one last time before saving... # if requested, sort LIBPATH and CPPPATH one last time before saving...
if env['PRIORITIZE_LINKING']: if env['PRIORITIZE_LINKING']:
conf.prioritize_paths(silent=True) conf.prioritize_paths(silent=True)
@ -2070,16 +1946,6 @@ if not HELP_REQUESTED:
else : else :
color_print(1,"WARNING: Cannot find boost_program_options. 'shapeindex' and other command line programs will not be available") color_print(1,"WARNING: Cannot find boost_program_options. 'shapeindex' and other command line programs will not be available")
# Build the Python bindings
if 'python' in env['BINDINGS']:
SConscript('bindings/python/build.py')
# Install the python speed testing scripts if python bindings will be available
SConscript('utils/performance/build.py')
# Install the mapnik upgrade script
SConscript('utils/upgrade_map_xml/build.py')
# Configure fonts and if requested install the bundled DejaVu fonts # Configure fonts and if requested install the bundled DejaVu fonts
SConscript('fonts/build.py') SConscript('fonts/build.py')

View file

@ -1,49 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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_PYTHON_BOOST_STD_SHARED_SHIM
#define MAPNIK_PYTHON_BOOST_STD_SHARED_SHIM
// boost
#include <boost/version.hpp>
#include <boost/config.hpp>
#if BOOST_VERSION < 105300 || defined BOOST_NO_CXX11_SMART_PTR
// https://github.com/mapnik/mapnik/issues/2022
#include <memory>
namespace boost {
template<class T> const T* get_pointer(std::shared_ptr<T> const& p)
{
return p.get();
}
template<class T> T* get_pointer(std::shared_ptr<T>& p)
{
return p.get();
}
} // namespace boost
#endif
#endif // MAPNIK_PYTHON_BOOST_STD_SHARED_SHIM

View file

@ -1,212 +0,0 @@
#
# This file is part of Mapnik (c++ mapping toolkit)
#
# Copyright (C) 2014 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 glob
import os
from subprocess import Popen, PIPE
Import('env')
def call(cmd, silent=True):
stdin, stderr = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate()
if not stderr:
return stdin.strip()
elif not silent:
print stderr
def run_2to3(*args,**kwargs):
call('2to3 -w %s' % os.path.dirname(kwargs['target'][0].path))
def is_py3():
return 'True' in os.popen('''%s -c "import sys as s;s.stdout.write(str(s.version_info[0] == 3))"''' % env['PYTHON']).read().strip()
prefix = env['PREFIX']
target_path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + env['MAPNIK_NAME'])
target_path_deprecated = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2')
py_env = env.Clone()
py_env.Append(CPPPATH = env['PYTHON_INCLUDES'])
py_env.Append(CPPDEFINES = env['LIBMAPNIK_DEFINES'])
py_env['LIBS'] = [env['MAPNIK_NAME'],env['BOOST_PYTHON_LIB']]
link_all_libs = env['LINKING'] == 'static' or env['RUNTIME_LINK'] == 'static' or (env['PLATFORM'] == 'Darwin' and not env['PYTHON_DYNAMIC_LOOKUP'])
# even though boost_thread is no longer used in mapnik core
# we need to link in for boost_python to avoid missing symbol: _ZN5boost6detail12get_tss_dataEPKv / boost::detail::get_tss_data
py_env.AppendUnique(LIBS = 'boost_thread%s' % env['BOOST_APPEND'])
if link_all_libs:
py_env.AppendUnique(LIBS=env['LIBMAPNIK_LIBS'])
# note: on linux -lrt must be linked after thread to avoid: undefined symbol: clock_gettime
if env['RUNTIME_LINK'] == 'static' and env['PLATFORM'] == 'Linux':
py_env.AppendUnique(LIBS='rt')
# TODO - do solaris/fedora need direct linking too?
if env['PLATFORM'] == 'Darwin':
##### Python linking on OS X is tricky ###
# Confounding problems are:
# 1) likelyhood of multiple python installs of the same major.minor version
# because apple supplies python built-in and many users may have installed
# further versions using macports
# 2) boost python directly links to a python version
# 3) the below will directly link _mapnik.so to a python version
# 4) _mapnik.so must link to the same python lib as boost_python.dylib otherwise
# python will Abort with a Version Mismatch error.
# See https://github.com/mapnik/mapnik/issues/453 for the seeds of a better approach
# for now we offer control over method of direct linking...
# The default below is to link against the python dylib in the form of
#/path/to/Python.framework/Python instead of -lpython
# http://developer.apple.com/mac/library/DOCUMENTATION/Darwin/Reference/ManPages/man1/ld.1.html
if env['PYTHON_DYNAMIC_LOOKUP']:
python_link_flag = '-undefined dynamic_lookup'
elif env['FRAMEWORK_PYTHON']:
if env['FRAMEWORK_SEARCH_PATH']:
# if the user has supplied a custom root path to search for
# a given Python framework, then use that to direct the linker
python_link_flag = '-F%s -framework Python -Z' % env['FRAMEWORK_SEARCH_PATH']
else:
# otherwise be as explicit as possible for linking to the same Framework
# as the executable we are building with (or is pointed to by the PYTHON variable)
# otherwise we may accidentally link against either:
# /System/Library/Frameworks/Python.framework/Python/Versions/
# or
# /Library/Frameworks/Python.framework/Python/Versions/
# See: https://github.com/mapnik/mapnik/issues/380
link_prefix = env['PYTHON_SYS_PREFIX']
if '.framework' in link_prefix:
python_link_flag = '-F%s -framework Python -Z' % os.path.dirname(link_prefix.split('.')[0])
elif '/System' in link_prefix:
python_link_flag = '-F/System/Library/Frameworks/ -framework Python -Z'
else:
# should we fall back to -lpython here?
python_link_flag = '-F/ -framework Python'
# if we are not linking to a framework then use the *nix standard approach
else:
# TODO - do we need to pass -L/?
python_link_flag = '-lpython%s' % env['PYTHON_VERSION']
elif env['PLATFORM'] == 'SunOS':
# make sure to explicitly link mapnik.so against
# libmapnik in its installed location
python_link_flag = '-R%s' % env['MAPNIK_LIB_BASE']
else:
# all other platforms we don't directly link python
python_link_flag = ''
paths = '''
"""Configuration paths of Mapnik fonts and input plugins (auto-generated by SCons)."""
from os.path import normpath,join,dirname
mapniklibpath = '%s'
mapniklibpath = normpath(join(dirname(__file__),mapniklibpath))
'''
paths += "inputpluginspath = join(mapniklibpath,'input')\n"
if env['SYSTEM_FONTS']:
paths += "fontscollectionpath = normpath('%s')\n" % env['SYSTEM_FONTS']
else:
paths += "fontscollectionpath = join(mapniklibpath,'fonts')\n"
paths += "__all__ = [mapniklibpath,inputpluginspath,fontscollectionpath]\n"
if not os.path.exists(env['MAPNIK_NAME']):
os.mkdir(env['MAPNIK_NAME'])
file('mapnik/paths.py','w').write(paths % (env['MAPNIK_LIB_DIR']))
# force open perms temporarily so that `sudo scons install`
# does not later break simple non-install non-sudo rebuild
try:
os.chmod('mapnik/paths.py',0666)
except: pass
# install the shared object beside the module directory
sources = glob.glob('*.cpp')
if 'install' in COMMAND_LINE_TARGETS:
# install the core mapnik python files, including '__init__.py'
init_files = glob.glob('mapnik/*.py')
if 'mapnik/paths.py' in init_files:
init_files.remove('mapnik/paths.py')
init_module = env.Install(target_path, init_files)
env.Alias(target='install', source=init_module)
# install mapnik2 module which redirects to mapnik and issues DeprecatedWarning
init_mapnik2 = env.Install(target_path_deprecated, 'mapnik2/__init__.py')
env.Alias(target='install', source=init_mapnik2)
# fix perms and install the custom generated 'paths.py'
targetp = os.path.join(target_path,'paths.py')
env.Alias("install", targetp)
# use env.Command rather than env.Install
# to enable setting proper perms on `paths.py`
env.Command( targetp, 'mapnik/paths.py',
[
Copy("$TARGET","$SOURCE"),
Chmod("$TARGET", 0644),
])
if 'uninstall' not in COMMAND_LINE_TARGETS:
if env['HAS_CAIRO']:
py_env.Append(CPPPATH = env['CAIRO_CPPPATHS'])
py_env.Append(CPPDEFINES = '-DHAVE_CAIRO')
if link_all_libs:
py_env.Append(LIBS=env['CAIRO_ALL_LIBS'])
if env['HAS_PYCAIRO']:
py_env.Append(CPPDEFINES = '-DHAVE_PYCAIRO')
py_env.Append(CPPPATH = env['PYCAIRO_PATHS'])
py_env.Append(LINKFLAGS=python_link_flag)
py_env.AppendUnique(LIBS='mapnik-json')
py_env.AppendUnique(LIBS='mapnik-wkt')
_mapnik = py_env.LoadableModule('mapnik/_mapnik', sources, LDMODULEPREFIX='', LDMODULESUFFIX='.so')
Depends(_mapnik, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME']))
Depends(_mapnik, env.subst('../../src/json/libmapnik-json${LIBSUFFIX}'))
Depends(_mapnik, env.subst('../../src/wkt/libmapnik-wkt${LIBSUFFIX}'))
if env['PLATFORM'] == 'SunOS' and env['PYTHON_IS_64BIT']:
# http://mail.python.org/pipermail/python-dev/2006-August/068528.html
cxx_module_path = os.path.join(target_path,'64')
else:
cxx_module_path = target_path
if 'uninstall' not in COMMAND_LINE_TARGETS:
pymapniklib = env.Install(cxx_module_path,_mapnik)
py_env.Alias(target='install',source=pymapniklib)
if 'install' in COMMAND_LINE_TARGETS:
if is_py3():
env.AddPostAction(pymapniklib, run_2to3)
env['create_uninstall_target'](env, target_path)
env['create_uninstall_target'](env, target_path_deprecated)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,27 +0,0 @@
#
# This file is part of Mapnik (C++/Python mapping toolkit)
# Copyright (C) 2014 Artem Pavlenko
#
# Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# mapnik2 module (Deprecated)
import warnings
from mapnik import *
warnings.simplefilter("default")
msg=""" mapnik2 module has been deprecated,
please use 'import mapnik' """
warnings.warn(msg, DeprecationWarning)

View file

@ -1,130 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
#include "boost_std_shared_shim.hpp"
// boost
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
//mapnik
#include <mapnik/color.hpp>
using mapnik::color;
struct color_pickle_suite : boost::python::pickle_suite
{
static boost::python::tuple
getinitargs(const color& c)
{
using namespace boost::python;
return boost::python::make_tuple(c.red(),c.green(),c.blue(),c.alpha());
}
};
void export_color ()
{
using namespace boost::python;
class_<color>("Color", init<int,int,int,int>(
( arg("r"), arg("g"), arg("b"), arg("a") ),
"Creates a new color from its RGB components\n"
"and an alpha value.\n"
"All values between 0 and 255.\n")
)
.def(init<int,int,int,int,bool>(
( arg("r"), arg("g"), arg("b"), arg("a"), arg("premultiplied") ),
"Creates a new color from its RGB components\n"
"and an alpha value.\n"
"All values between 0 and 255.\n")
)
.def(init<int,int,int>(
( arg("r"), arg("g"), arg("b") ),
"Creates a new color from its RGB components.\n"
"All values between 0 and 255.\n")
)
.def(init<uint32_t>(
( arg("val") ),
"Creates a new color from an unsigned integer.\n"
"All values between 0 and 2^32-1\n")
)
.def(init<uint32_t, bool>(
( arg("val"), arg("premultiplied") ),
"Creates a new color from an unsigned integer.\n"
"All values between 0 and 2^32-1\n")
)
.def(init<std::string>(
( arg("color_string") ),
"Creates a new color from its CSS string representation.\n"
"The string may be a CSS color name (e.g. 'blue')\n"
"or a hex color string (e.g. '#0000ff').\n")
)
.def(init<std::string, bool>(
( arg("color_string"), arg("premultiplied") ),
"Creates a new color from its CSS string representation.\n"
"The string may be a CSS color name (e.g. 'blue')\n"
"or a hex color string (e.g. '#0000ff').\n")
)
.add_property("r",
&color::red,
&color::set_red,
"Gets or sets the red component.\n"
"The value is between 0 and 255.\n")
.add_property("g",
&color::green,
&color::set_green,
"Gets or sets the green component.\n"
"The value is between 0 and 255.\n")
.add_property("b",
&color::blue,
&color::set_blue,
"Gets or sets the blue component.\n"
"The value is between 0 and 255.\n")
.add_property("a",
&color::alpha,
&color::set_alpha,
"Gets or sets the alpha component.\n"
"The value is between 0 and 255.\n")
.def(self == self)
.def(self != self)
.def_pickle(color_pickle_suite())
.def("__str__",&color::to_string)
.def("set_premultiplied",&color::set_premultiplied)
.def("get_premultiplied",&color::get_premultiplied)
.def("premultiply",&color::premultiply)
.def("demultiply",&color::demultiply)
.def("packed",&color::rgba)
.def("to_hex_string",&color::to_hex_string,
"Returns the hexadecimal representation of this color.\n"
"\n"
"Example:\n"
">>> c = Color('blue')\n"
">>> c.to_hex_string()\n"
"'#0000ff'\n")
;
}

View file

@ -1,73 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
#include "boost_std_shared_shim.hpp"
// boost
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/coord.hpp>
using mapnik::coord;
struct coord_pickle_suite : boost::python::pickle_suite
{
static boost::python::tuple
getinitargs(const coord<double,2>& c)
{
using namespace boost::python;
return boost::python::make_tuple(c.x,c.y);
}
};
void export_coord()
{
using namespace boost::python;
class_<coord<double,2> >("Coord",init<double, double>(
// class docstring is in mapnik/__init__.py, class _Coord
(arg("x"), arg("y")),
"Constructs a new point with the given coordinates.\n")
)
.def_pickle(coord_pickle_suite())
.def_readwrite("x", &coord<double,2>::x,
"Gets or sets the x/lon coordinate of the point.\n")
.def_readwrite("y", &coord<double,2>::y,
"Gets or sets the y/lat coordinate of the point.\n")
.def(self == self) // __eq__
.def(self + self) // __add__
.def(self + float())
.def(float() + self)
.def(self - self) // __sub__
.def(self - float())
.def(self * float()) //__mult__
.def(float() * self)
.def(self / float()) // __div__
;
}

View file

@ -1,217 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/noncopyable.hpp>
#include <boost/version.hpp>
#pragma GCC diagnostic pop
// stl
#include <vector>
// mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/feature_layer_desc.hpp>
#include <mapnik/memory_datasource.hpp>
using mapnik::datasource;
using mapnik::memory_datasource;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::parameters;
namespace
{
//user-friendly wrapper that uses Python dictionary
using namespace boost::python;
std::shared_ptr<mapnik::datasource> create_datasource(dict const& d)
{
mapnik::parameters params;
boost::python::list keys=d.keys();
for (int i=0; i < len(keys); ++i)
{
std::string key = extract<std::string>(keys[i]);
object obj = d[key];
if (PyUnicode_Check(obj.ptr()))
{
PyObject* temp = PyUnicode_AsUTF8String(obj.ptr());
if (temp)
{
#if PY_VERSION_HEX >= 0x03000000
char* c_str = PyBytes_AsString(temp);
#else
char* c_str = PyString_AsString(temp);
#endif
params[key] = std::string(c_str);
Py_DecRef(temp);
}
continue;
}
extract<std::string> ex0(obj);
extract<mapnik::value_integer> ex1(obj);
extract<double> ex2(obj);
if (ex0.check())
{
params[key] = ex0();
}
else if (ex1.check())
{
params[key] = ex1();
}
else if (ex2.check())
{
params[key] = ex2();
}
}
return mapnik::datasource_cache::instance().create(params);
}
boost::python::dict describe(std::shared_ptr<mapnik::datasource> const& ds)
{
boost::python::dict description;
mapnik::layer_descriptor ld = ds->get_descriptor();
description["type"] = ds->type();
description["name"] = ld.get_name();
description["geometry_type"] = ds->get_geometry_type();
description["encoding"] = ld.get_encoding();
for (auto const& param : ld.get_extra_parameters())
{
description[param.first] = param.second;
}
return description;
}
boost::python::list fields(std::shared_ptr<mapnik::datasource> const& ds)
{
boost::python::list flds;
if (ds)
{
layer_descriptor ld = ds->get_descriptor();
std::vector<attribute_descriptor> const& desc_ar = ld.get_descriptors();
std::vector<attribute_descriptor>::const_iterator it = desc_ar.begin();
std::vector<attribute_descriptor>::const_iterator end = desc_ar.end();
for (; it != end; ++it)
{
flds.append(it->get_name());
}
}
return flds;
}
boost::python::list field_types(std::shared_ptr<mapnik::datasource> const& ds)
{
boost::python::list fld_types;
if (ds)
{
layer_descriptor ld = ds->get_descriptor();
std::vector<attribute_descriptor> const& desc_ar = ld.get_descriptors();
std::vector<attribute_descriptor>::const_iterator it = desc_ar.begin();
std::vector<attribute_descriptor>::const_iterator end = desc_ar.end();
for (; it != end; ++it)
{
unsigned type = it->get_type();
if (type == mapnik::Integer)
// this crashes, so send back strings instead
//fld_types.append(boost::python::object(boost::python::handle<>(&PyInt_Type)));
fld_types.append(boost::python::str("int"));
else if (type == mapnik::Float)
fld_types.append(boost::python::str("float"));
else if (type == mapnik::Double)
fld_types.append(boost::python::str("float"));
else if (type == mapnik::String)
fld_types.append(boost::python::str("str"));
else if (type == mapnik::Boolean)
fld_types.append(boost::python::str("bool"));
else if (type == mapnik::Geometry)
fld_types.append(boost::python::str("geometry"));
else if (type == mapnik::Object)
fld_types.append(boost::python::str("object"));
else
fld_types.append(boost::python::str("unknown"));
}
}
return fld_types;
}}
mapnik::parameters const& (mapnik::datasource::*params_const)() const = &mapnik::datasource::params;
void export_datasource()
{
using namespace boost::python;
enum_<mapnik::datasource::datasource_t>("DataType")
.value("Vector",mapnik::datasource::Vector)
.value("Raster",mapnik::datasource::Raster)
;
enum_<mapnik::datasource_geometry_t>("DataGeometryType")
.value("Point",mapnik::datasource_geometry_t::Point)
.value("LineString",mapnik::datasource_geometry_t::LineString)
.value("Polygon",mapnik::datasource_geometry_t::Polygon)
.value("Collection",mapnik::datasource_geometry_t::Collection)
;
class_<datasource,std::shared_ptr<datasource>,
boost::noncopyable>("Datasource",no_init)
.def("type",&datasource::type)
.def("geometry_type",&datasource::get_geometry_type)
.def("describe",&describe)
.def("envelope",&datasource::envelope)
.def("features",&datasource::features)
.def("fields",&fields)
.def("field_types",&field_types)
.def("features_at_point",&datasource::features_at_point, (arg("coord"),arg("tolerance")=0))
.def("params",make_function(params_const,return_value_policy<copy_const_reference>()),
"The configuration parameters of the data source. "
"These vary depending on the type of data source.")
.def(self == self)
;
def("CreateDatasource",&create_datasource);
class_<memory_datasource,
bases<datasource>, std::shared_ptr<memory_datasource>,
boost::noncopyable>("MemoryDatasourceBase", init<parameters>())
.def("add_feature",&memory_datasource::push,
"Adds a Feature:\n"
">>> ms = MemoryDatasource()\n"
">>> feature = Feature(1)\n"
">>> ms.add_feature(Feature(1))\n")
.def("num_features",&memory_datasource::size)
;
implicitly_convertible<std::shared_ptr<memory_datasource>,std::shared_ptr<datasource> >();
}

View file

@ -1,104 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/noncopyable.hpp>
#pragma GCC diagnostic pop
#include <mapnik/value_types.hpp>
#include <mapnik/params.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
namespace {
using namespace boost::python;
std::shared_ptr<mapnik::datasource> create_datasource(const dict& d)
{
mapnik::parameters params;
boost::python::list keys=d.keys();
for (int i=0; i<len(keys); ++i)
{
std::string key = extract<std::string>(keys[i]);
object obj = d[key];
extract<std::string> ex0(obj);
extract<mapnik::value_integer> ex1(obj);
extract<double> ex2(obj);
if (ex0.check())
{
params[key] = ex0();
}
else if (ex1.check())
{
params[key] = ex1();
}
else if (ex2.check())
{
params[key] = ex2();
}
}
return mapnik::datasource_cache::instance().create(params);
}
void register_datasources(std::string const& path)
{
mapnik::datasource_cache::instance().register_datasources(path);
}
std::vector<std::string> plugin_names()
{
return mapnik::datasource_cache::instance().plugin_names();
}
std::string plugin_directories()
{
return mapnik::datasource_cache::instance().plugin_directories();
}
}
void export_datasource_cache()
{
using mapnik::datasource_cache;
class_<datasource_cache,
boost::noncopyable>("DatasourceCache",no_init)
.def("create",&create_datasource)
.staticmethod("create")
.def("register_datasources",&register_datasources)
.staticmethod("register_datasources")
.def("plugin_names",&plugin_names)
.staticmethod("plugin_names")
.def("plugin_directories",&plugin_directories)
.staticmethod("plugin_directories")
;
}

View file

@ -1,88 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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_PYTHON_BINDING_ENUMERATION_INCLUDED
#define MAPNIK_PYTHON_BINDING_ENUMERATION_INCLUDED
#include <boost/python/converter/registered.hpp> // for registered
#include <boost/python/enum.hpp> // for enum_
#include <boost/python/implicit.hpp> // for implicitly_convertible
#include <boost/python/to_python_converter.hpp>
namespace mapnik {
template <typename EnumWrapper>
class enumeration_ :
public boost::python::enum_<typename EnumWrapper::native_type>
{
// some short cuts
using base_type = boost::python::enum_<typename EnumWrapper::native_type>;
using native_type = typename EnumWrapper::native_type;
public:
enumeration_() :
base_type( EnumWrapper::get_name().c_str() )
{
init();
}
enumeration_(const char * python_alias) :
base_type( python_alias )
{
init();
}
enumeration_(const char * python_alias, const char * doc) :
base_type( python_alias, doc )
{
init();
}
private:
struct converter
{
static PyObject* convert(EnumWrapper const& v)
{
// Redirect conversion to a static method of our base class's
// base class. A free template converter will not work because
// the base_type::base typedef is protected.
// Lets hope MSVC agrees that this is legal C++
using namespace boost::python::converter;
return base_type::base::to_python(
registered<native_type>::converters.m_class_object
, static_cast<long>( v ));
}
};
void init() {
boost::python::implicitly_convertible<native_type, EnumWrapper>();
boost::python::to_python_converter<EnumWrapper, converter >();
for (unsigned i = 0; i < EnumWrapper::MAX; ++i)
{
// Register the strings already defined for this enum.
base_type::value( EnumWrapper::get_string( i ), native_type( i ) );
}
}
};
} // end of namespace mapnik
#endif // MAPNIK_PYTHON_BINDING_ENUMERATION_INCLUDED

View file

@ -1,45 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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_BINDINGS_PYTHON_ENUMERATION_WRAPPPER
#define MAPNIK_BINDINGS_PYTHON_ENUMERATION_WRAPPPER
// mapnik
#include <mapnik/symbolizer.hpp>
// boost
#include <boost/python.hpp>
namespace boost { namespace python {
struct mapnik_enumeration_wrapper_to_python
{
static PyObject* convert(mapnik::enumeration_wrapper const& v)
{
return ::PyLong_FromLongLong(v.value); // FIXME: this is a temp hack!!
}
};
}}
#endif // MAPNIK_BINDINGS_PYTHON_ENUMERATION_WRAPPPER

View file

@ -1,301 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/box2d.hpp>
#include <mapnik/value_error.hpp>
using mapnik::coord;
using mapnik::box2d;
struct envelope_pickle_suite : boost::python::pickle_suite
{
static boost::python::tuple
getinitargs(const box2d<double>& e)
{
using namespace boost::python;
return boost::python::make_tuple(e.minx(),e.miny(),e.maxx(),e.maxy());
}
};
box2d<double> from_string(std::string const& s)
{
box2d<double> bbox;
bool success = bbox.from_string(s);
if (success)
{
return bbox;
}
else
{
std::stringstream ss;
ss << "Could not parse bbox from string: '" << s << "'";
throw mapnik::value_error(ss.str());
}
}
//define overloads here
void (box2d<double>::*width_p1)(double) = &box2d<double>::width;
double (box2d<double>::*width_p2)() const = &box2d<double>::width;
void (box2d<double>::*height_p1)(double) = &box2d<double>::height;
double (box2d<double>::*height_p2)() const = &box2d<double>::height;
void (box2d<double>::*expand_to_include_p1)(double,double) = &box2d<double>::expand_to_include;
void (box2d<double>::*expand_to_include_p2)(coord<double,2> const& ) = &box2d<double>::expand_to_include;
void (box2d<double>::*expand_to_include_p3)(box2d<double> const& ) = &box2d<double>::expand_to_include;
bool (box2d<double>::*contains_p1)(double,double) const = &box2d<double>::contains;
bool (box2d<double>::*contains_p2)(coord<double,2> const&) const = &box2d<double>::contains;
bool (box2d<double>::*contains_p3)(box2d<double> const&) const = &box2d<double>::contains;
//intersects
bool (box2d<double>::*intersects_p1)(double,double) const = &box2d<double>::intersects;
bool (box2d<double>::*intersects_p2)(coord<double,2> const&) const = &box2d<double>::intersects;
bool (box2d<double>::*intersects_p3)(box2d<double> const&) const = &box2d<double>::intersects;
// intersect
box2d<double> (box2d<double>::*intersect)(box2d<double> const&) const = &box2d<double>::intersect;
// re_center
void (box2d<double>::*re_center_p1)(double,double) = &box2d<double>::re_center;
void (box2d<double>::*re_center_p2)(coord<double,2> const& ) = &box2d<double>::re_center;
// clip
void (box2d<double>::*clip)(box2d<double> const&) = &box2d<double>::clip;
// pad
void (box2d<double>::*pad)(double) = &box2d<double>::pad;
// deepcopy
box2d<double> box2d_deepcopy(box2d<double> & obj, boost::python::dict const&)
{
// FIXME::ignore memo for now
box2d<double> result(obj);
return result;
}
void export_envelope()
{
using namespace boost::python;
class_<box2d<double> >("Box2d",
// class docstring is in mapnik/__init__.py, class _Coord
init<double,double,double,double>(
(arg("minx"),arg("miny"),arg("maxx"),arg("maxy")),
"Constructs a new envelope from the coordinates\n"
"of its lower left and upper right corner points.\n"))
.def(init<>("Equivalent to Box2d(0, 0, -1, -1).\n"))
.def(init<const coord<double,2>&, const coord<double,2>&>(
(arg("ll"),arg("ur")),
"Equivalent to Box2d(ll.x, ll.y, ur.x, ur.y).\n"))
.def("from_string",from_string)
.staticmethod("from_string")
.add_property("minx", &box2d<double>::minx,
"X coordinate for the lower left corner")
.add_property("miny", &box2d<double>::miny,
"Y coordinate for the lower left corner")
.add_property("maxx", &box2d<double>::maxx,
"X coordinate for the upper right corner")
.add_property("maxy", &box2d<double>::maxy,
"Y coordinate for the upper right corner")
.def("center", &box2d<double>::center,
"Returns the coordinates of the center of the bounding box.\n"
"\n"
"Example:\n"
">>> e = Box2d(0, 0, 100, 100)\n"
">>> e.center()\n"
"Coord(50, 50)\n")
.def("center", re_center_p1,
(arg("x"), arg("y")),
"Moves the envelope so that the given coordinates become its new center.\n"
"The width and the height are preserved.\n"
"\n "
"Example:\n"
">>> e = Box2d(0, 0, 100, 100)\n"
">>> e.center(60, 60)\n"
">>> e.center()\n"
"Coord(60.0,60.0)\n"
">>> (e.width(), e.height())\n"
"(100.0, 100.0)\n"
">>> e\n"
"Box2d(10.0, 10.0, 110.0, 110.0)\n"
)
.def("center", re_center_p2,
(arg("Coord")),
"Moves the envelope so that the given coordinates become its new center.\n"
"The width and the height are preserved.\n"
"\n "
"Example:\n"
">>> e = Box2d(0, 0, 100, 100)\n"
">>> e.center(Coord60, 60)\n"
">>> e.center()\n"
"Coord(60.0,60.0)\n"
">>> (e.width(), e.height())\n"
"(100.0, 100.0)\n"
">>> e\n"
"Box2d(10.0, 10.0, 110.0, 110.0)\n"
)
.def("clip", clip,
(arg("other")),
"Clip the envelope based on the bounds of another envelope.\n"
"\n "
"Example:\n"
">>> e = Box2d(0, 0, 100, 100)\n"
">>> c = Box2d(-50, -50, 50, 50)\n"
">>> e.clip(c)\n"
">>> e\n"
"Box2d(0.0,0.0,50.0,50.0\n"
)
.def("pad", pad,
(arg("padding")),
"Pad the envelope based on a padding value.\n"
"\n "
"Example:\n"
">>> e = Box2d(0, 0, 100, 100)\n"
">>> e.pad(10)\n"
">>> e\n"
"Box2d(-10.0,-10.0,110.0,110.0\n"
)
.def("width", width_p1,
(arg("new_width")),
"Sets the width to new_width of the envelope preserving its center.\n"
"\n "
"Example:\n"
">>> e = Box2d(0, 0, 100, 100)\n"
">>> e.width(120)\n"
">>> e.center()\n"
"Coord(50.0,50.0)\n"
">>> e\n"
"Box2d(-10.0, 0.0, 110.0, 100.0)\n"
)
.def("width", width_p2,
"Returns the width of this envelope.\n"
)
.def("height", height_p1,
(arg("new_height")),
"Sets the height to new_height of the envelope preserving its center.\n"
"\n "
"Example:\n"
">>> e = Box2d(0, 0, 100, 100)\n"
">>> e.height(120)\n"
">>> e.center()\n"
"Coord(50.0,50.0)\n"
">>> e\n"
"Box2d(0.0, -10.0, 100.0, 110.0)\n"
)
.def("height", height_p2,
"Returns the height of this envelope.\n"
)
.def("expand_to_include",expand_to_include_p1,
(arg("x"),arg("y")),
"Expands this envelope to include the point given by x and y.\n"
"\n"
"Example:\n",
">>> e = Box2d(0, 0, 100, 100)\n"
">>> e.expand_to_include(110, 110)\n"
">>> e\n"
"Box2d(0.0, 00.0, 110.0, 110.0)\n"
)
.def("expand_to_include",expand_to_include_p2,
(arg("p")),
"Equivalent to expand_to_include(p.x, p.y)\n"
)
.def("expand_to_include",expand_to_include_p3,
(arg("other")),
"Equivalent to:\n"
" expand_to_include(other.minx, other.miny)\n"
" expand_to_include(other.maxx, other.maxy)\n"
)
.def("contains",contains_p1,
(arg("x"),arg("y")),
"Returns True iff this envelope contains the point\n"
"given by x and y.\n"
)
.def("contains",contains_p2,
(arg("p")),
"Equivalent to contains(p.x, p.y)\n"
)
.def("contains",contains_p3,
(arg("other")),
"Equivalent to:\n"
" contains(other.minx, other.miny) and contains(other.maxx, other.maxy)\n"
)
.def("intersects",intersects_p1,
(arg("x"),arg("y")),
"Returns True iff this envelope intersects the point\n"
"given by x and y.\n"
"\n"
"Note: For points, intersection is equivalent\n"
"to containment, i.e. the following holds:\n"
" e.contains(x, y) == e.intersects(x, y)\n"
)
.def("intersects",intersects_p2,
(arg("p")),
"Equivalent to contains(p.x, p.y)\n")
.def("intersects",intersects_p3,
(arg("other")),
"Returns True iff this envelope intersects the other envelope,\n"
"This relationship is symmetric."
"\n"
"Example:\n"
">>> e1 = Box2d(0, 0, 100, 100)\n"
">>> e2 = Box2d(50, 50, 150, 150)\n"
">>> e1.intersects(e2)\n"
"True\n"
">>> e1.contains(e2)\n"
"False\n"
)
.def("intersect",intersect,
(arg("other")),
"Returns the overlap of this envelope and the other envelope\n"
"as a new envelope.\n"
"\n"
"Example:\n"
">>> e1 = Box2d(0, 0, 100, 100)\n"
">>> e2 = Box2d(50, 50, 150, 150)\n"
">>> e1.intersect(e2)\n"
"Box2d(50.0, 50.0, 100.0, 100.0)\n"
)
.def(self == self) // __eq__
.def(self != self) // __neq__
.def(self + self) // __add__
.def(self * float()) // __mult__
.def(float() * self)
.def(self / float()) // __div__
.def("__getitem__",&box2d<double>::operator[])
.def("valid",&box2d<double>::valid)
.def_pickle(envelope_pickle_suite())
.def("__deepcopy__", &box2d_deepcopy)
;
}

View file

@ -1,111 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
#include "python_to_value.hpp"
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/noncopyable.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/util/variant.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/expression.hpp>
#include <mapnik/expression_string.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/value.hpp>
using mapnik::expression_ptr;
using mapnik::parse_expression;
using mapnik::to_expression_string;
using mapnik::path_expression_ptr;
// expression
expression_ptr parse_expression_(std::string const& wkt)
{
return parse_expression(wkt);
}
std::string expression_to_string_(mapnik::expr_node const& expr)
{
return mapnik::to_expression_string(expr);
}
mapnik::value expression_evaluate_(mapnik::expr_node const& expr, mapnik::feature_impl const& f, boost::python::dict const& d)
{
// will be auto-converted to proper python type by `mapnik_value_to_python`
return mapnik::util::apply_visitor(mapnik::evaluate<mapnik::feature_impl,mapnik::value,mapnik::attributes>(f,mapnik::dict2attr(d)),expr);
}
bool expression_evaluate_to_bool_(mapnik::expr_node const& expr, mapnik::feature_impl const& f, boost::python::dict const& d)
{
return mapnik::util::apply_visitor(mapnik::evaluate<mapnik::feature_impl,mapnik::value,mapnik::attributes>(f,mapnik::dict2attr(d)),expr).to_bool();
}
// path expression
path_expression_ptr parse_path_(std::string const& path)
{
return mapnik::parse_path(path);
}
std::string path_to_string_(mapnik::path_expression const& expr)
{
return mapnik::path_processor_type::to_string(expr);
}
std::string path_evaluate_(mapnik::path_expression const& expr, mapnik::feature_impl const& f)
{
return mapnik::path_processor_type::evaluate(expr, f);
}
void export_expression()
{
using namespace boost::python;
class_<mapnik::expr_node ,boost::noncopyable>("Expression",
"TODO"
"",no_init)
.def("evaluate", &expression_evaluate_,(arg("feature"),arg("variables")=boost::python::dict()))
.def("to_bool", &expression_evaluate_to_bool_,(arg("feature"),arg("variables")=boost::python::dict()))
.def("__str__",&expression_to_string_);
;
def("Expression",&parse_expression_,(arg("expr")),"Expression string");
class_<mapnik::path_expression ,boost::noncopyable>("PathExpression",
"TODO"
"",no_init)
.def("evaluate", &path_evaluate_) // note: "pass" is a reserved word in Python
.def("__str__",&path_to_string_);
;
def("PathExpression",&parse_path_,(arg("expr")),"PathExpression string");
}

View file

@ -1,237 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/iterator.hpp>
#include <boost/python/call_method.hpp>
#include <boost/python/tuple.hpp>
#include <boost/python/to_python_converter.hpp>
#include <boost/noncopyable.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/value_types.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/feature_factory.hpp>
#include <mapnik/feature_kv_iterator.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/wkb.hpp>
//#include <mapnik/wkt/wkt_factory.hpp>
#include <mapnik/json/feature_parser.hpp>
#include <mapnik/json/feature_generator.hpp>
// stl
#include <stdexcept>
namespace {
using mapnik::geometry_utils;
using mapnik::context_type;
using mapnik::context_ptr;
using mapnik::feature_kv_iterator;
mapnik::feature_ptr from_geojson_impl(std::string const& json, mapnik::context_ptr const& ctx)
{
mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx,1));
if (!mapnik::json::from_geojson(json,*feature))
{
throw std::runtime_error("Failed to parse geojson feature");
}
return feature;
}
std::string feature_to_geojson(mapnik::feature_impl const& feature)
{
std::string json;
if (!mapnik::json::to_geojson(json,feature))
{
throw std::runtime_error("Failed to generate GeoJSON");
}
return json;
}
mapnik::value __getitem__(mapnik::feature_impl const& feature, std::string const& name)
{
return feature.get(name);
}
mapnik::value __getitem2__(mapnik::feature_impl const& feature, std::size_t index)
{
return feature.get(index);
}
void __setitem__(mapnik::feature_impl & feature, std::string const& name, mapnik::value const& val)
{
feature.put_new(name,val);
}
boost::python::dict attributes(mapnik::feature_impl const& f)
{
boost::python::dict attributes;
feature_kv_iterator itr = f.begin();
feature_kv_iterator end = f.end();
for ( ;itr!=end; ++itr)
{
attributes[std::get<0>(*itr)] = std::get<1>(*itr);
}
return attributes;
}
} // end anonymous namespace
struct unicode_string_from_python_str
{
unicode_string_from_python_str()
{
boost::python::converter::registry::push_back(
&convertible,
&construct,
boost::python::type_id<mapnik::value_unicode_string>());
}
static void* convertible(PyObject* obj_ptr)
{
if (!(
#if PY_VERSION_HEX >= 0x03000000
PyBytes_Check(obj_ptr)
#else
PyString_Check(obj_ptr)
#endif
|| PyUnicode_Check(obj_ptr)))
return 0;
return obj_ptr;
}
static void construct(
PyObject* obj_ptr,
boost::python::converter::rvalue_from_python_stage1_data* data)
{
char * value=0;
if (PyUnicode_Check(obj_ptr)) {
PyObject *encoded = PyUnicode_AsEncodedString(obj_ptr, "utf8", "replace");
if (encoded) {
#if PY_VERSION_HEX >= 0x03000000
value = PyBytes_AsString(encoded);
#else
value = PyString_AsString(encoded);
#endif
Py_DecRef(encoded);
}
} else {
#if PY_VERSION_HEX >= 0x03000000
value = PyBytes_AsString(obj_ptr);
#else
value = PyString_AsString(obj_ptr);
#endif
}
if (value == 0) boost::python::throw_error_already_set();
void* storage = (
(boost::python::converter::rvalue_from_python_storage<mapnik::value_unicode_string>*)
data)->storage.bytes;
new (storage) mapnik::value_unicode_string(value);
data->convertible = storage;
}
};
struct value_null_from_python
{
value_null_from_python()
{
boost::python::converter::registry::push_back(
&convertible,
&construct,
boost::python::type_id<mapnik::value_null>());
}
static void* convertible(PyObject* obj_ptr)
{
if (obj_ptr == Py_None) return obj_ptr;
return 0;
}
static void construct(
PyObject* obj_ptr,
boost::python::converter::rvalue_from_python_stage1_data* data)
{
if (obj_ptr != Py_None) boost::python::throw_error_already_set();
void* storage = (
(boost::python::converter::rvalue_from_python_storage<mapnik::value_null>*)
data)->storage.bytes;
new (storage) mapnik::value_null();
data->convertible = storage;
}
};
void export_feature()
{
using namespace boost::python;
// Python to mapnik::value converters
// NOTE: order matters here. For example value_null must be listed before
// bool otherwise Py_None will be interpreted as bool (false)
implicitly_convertible<mapnik::value_unicode_string,mapnik::value>();
implicitly_convertible<mapnik::value_null,mapnik::value>();
implicitly_convertible<mapnik::value_integer,mapnik::value>();
implicitly_convertible<mapnik::value_double,mapnik::value>();
implicitly_convertible<mapnik::value_bool,mapnik::value>();
// http://misspent.wordpress.com/2009/09/27/how-to-write-boost-python-converters/
unicode_string_from_python_str();
value_null_from_python();
class_<context_type,context_ptr,boost::noncopyable>
("Context",init<>("Default ctor."))
.def("push", &context_type::push)
;
class_<mapnik::feature_impl,std::shared_ptr<mapnik::feature_impl>,
boost::noncopyable>("Feature",init<context_ptr,mapnik::value_integer>("Default ctor."))
.def("id",&mapnik::feature_impl::id)
.add_property("geometry",
make_function(&mapnik::feature_impl::get_geometry,return_value_policy<reference_existing_object>()),
&mapnik::feature_impl::set_geometry_copy)
.def("envelope", &mapnik::feature_impl::envelope)
.def("has_key", &mapnik::feature_impl::has_key)
.add_property("attributes",&attributes)
.def("__setitem__",&__setitem__)
.def("__contains__",&__getitem__)
.def("__getitem__",&__getitem__)
.def("__getitem__",&__getitem2__)
.def("__len__", &mapnik::feature_impl::size)
.def("context",&mapnik::feature_impl::context)
.def("to_geojson",&feature_to_geojson)
.def("from_geojson",from_geojson_impl)
.staticmethod("from_geojson")
;
}

View file

@ -1,93 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/noncopyable.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/feature.hpp>
#include <mapnik/datasource.hpp>
namespace {
using namespace boost::python;
inline list features(mapnik::featureset_ptr const& itr)
{
list l;
while (true)
{
mapnik::feature_ptr fp = itr->next();
if (!fp)
{
break;
}
l.append(fp);
}
return l;
}
inline object pass_through(object const& o) { return o; }
inline mapnik::feature_ptr next(mapnik::featureset_ptr const& itr)
{
mapnik::feature_ptr f = itr->next();
if (!f)
{
PyErr_SetString(PyExc_StopIteration, "No more features.");
boost::python::throw_error_already_set();
}
return f;
}
}
void export_featureset()
{
using namespace boost::python;
class_<mapnik::Featureset,std::shared_ptr<mapnik::Featureset>,
boost::noncopyable>("Featureset",no_init)
.def("__iter__",pass_through)
.def("next",next)
.add_property("features",features,
"The list of features.\n"
"\n"
"Usage:\n"
">>> m.query_map_point(0, 10, 10)\n"
"<mapnik._mapnik.Featureset object at 0x1004d2938>\n"
">>> fs = m.query_map_point(0, 10, 10)\n"
">>> for f in fs.features:\n"
">>> print f\n"
"<mapnik.Feature object at 0x105e64140>\n"
)
;
}

View file

@ -1,60 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/noncopyable.hpp>
#pragma GCC diagnostic pop
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/utils.hpp>
void export_font_engine()
{
using mapnik::freetype_engine;
using mapnik::singleton;
using mapnik::CreateStatic;
using namespace boost::python;
class_<singleton<freetype_engine,CreateStatic>,boost::noncopyable>("Singleton",no_init)
.def("instance",&singleton<freetype_engine,CreateStatic>::instance,
return_value_policy<reference_existing_object>())
.staticmethod("instance")
;
class_<freetype_engine,bases<singleton<freetype_engine,CreateStatic> >,
boost::noncopyable>("FontEngine",no_init)
.def("register_font",&freetype_engine::register_font)
.def("register_fonts",&freetype_engine::register_fonts)
.def("face_names",&freetype_engine::face_names)
.staticmethod("register_font")
.staticmethod("register_fonts")
.staticmethod("face_names")
;
}

View file

@ -1,64 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
//mapnik
#include <mapnik/font_set.hpp>
using mapnik::font_set;
void export_fontset ()
{
using namespace boost::python;
class_<font_set>("FontSet", init<std::string const&>("default fontset constructor")
)
.add_property("name",
make_function(&font_set::get_name,return_value_policy<copy_const_reference>()),
&font_set::set_name,
"Get/Set the name of the FontSet.\n"
)
.def("add_face_name",&font_set::add_face_name,
(arg("name")),
"Add a face-name to the fontset.\n"
"\n"
"Example:\n"
">>> fs = Fontset('book-fonts')\n"
">>> fs.add_face_name('DejaVu Sans Book')\n")
.add_property("names",make_function
(&font_set::get_face_names,
return_value_policy<reference_existing_object>()),
"List of face names belonging to a FontSet.\n"
)
;
}

View file

@ -1,49 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
#include <mapnik/symbolizer_enumerations.hpp>
#include "mapnik_enumeration.hpp"
void export_gamma_method()
{
using namespace boost::python;
mapnik::enumeration_<mapnik::gamma_method_e>("gamma_method")
.value("POWER", mapnik::GAMMA_POWER)
.value("LINEAR",mapnik::GAMMA_LINEAR)
.value("NONE", mapnik::GAMMA_NONE)
.value("THRESHOLD", mapnik::GAMMA_THRESHOLD)
.value("MULTIPLY", mapnik::GAMMA_MULTIPLY)
;
}

View file

@ -1,296 +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
*
*****************************************************************************/
#include <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/def.hpp>
#include <boost/python/exception_translator.hpp>
#include <boost/python/manage_new_object.hpp>
#include <boost/python/iterator.hpp>
#include <boost/noncopyable.hpp>
#include <boost/version.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/geometry_envelope.hpp>
#include <mapnik/geometry_is_valid.hpp>
#include <mapnik/geometry_is_simple.hpp>
#include <mapnik/geometry_is_empty.hpp>
#include <mapnik/geometry_correct.hpp>
#include <mapnik/geometry_centroid.hpp>
#include <mapnik/wkt/wkt_factory.hpp> // from_wkt
#include <mapnik/json/geometry_parser.hpp> // from_geojson
#include <mapnik/util/geometry_to_geojson.hpp> // to_geojson
#include <mapnik/util/geometry_to_wkb.hpp> // to_wkb
#include <mapnik/util/geometry_to_wkt.hpp> // to_wkt
//#include <mapnik/util/geometry_to_svg.hpp>
#include <mapnik/wkb.hpp>
// stl
#include <stdexcept>
namespace {
std::shared_ptr<mapnik::geometry::geometry<double> > from_wkb_impl(std::string const& wkb)
{
std::shared_ptr<mapnik::geometry::geometry<double> > geom = std::make_shared<mapnik::geometry::geometry<double> >();
try
{
*geom = std::move(mapnik::geometry_utils::from_wkb(wkb.c_str(), wkb.size()));
}
catch (...)
{
throw std::runtime_error("Failed to parse WKB");
}
return geom;
}
std::shared_ptr<mapnik::geometry::geometry<double> > from_wkt_impl(std::string const& wkt)
{
std::shared_ptr<mapnik::geometry::geometry<double> > geom = std::make_shared<mapnik::geometry::geometry<double> >();
if (!mapnik::from_wkt(wkt, *geom))
throw std::runtime_error("Failed to parse WKT geometry");
return geom;
}
std::shared_ptr<mapnik::geometry::geometry<double> > from_geojson_impl(std::string const& json)
{
std::shared_ptr<mapnik::geometry::geometry<double> > geom = std::make_shared<mapnik::geometry::geometry<double> >();
if (!mapnik::json::from_geojson(json, *geom))
throw std::runtime_error("Failed to parse geojson geometry");
return geom;
}
}
inline std::string boost_version()
{
std::ostringstream s;
s << BOOST_VERSION/100000 << "." << BOOST_VERSION/100 % 1000 << "." << BOOST_VERSION % 100;
return s.str();
}
PyObject* to_wkb_impl(mapnik::geometry::geometry<double> const& geom, mapnik::wkbByteOrder byte_order)
{
mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(geom,byte_order);
if (wkb)
{
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
((const char*)wkb->buffer(),wkb->size());
}
else
{
Py_RETURN_NONE;
}
}
std::string to_geojson_impl(mapnik::geometry::geometry<double> const& geom)
{
std::string wkt;
if (!mapnik::util::to_geojson(wkt, geom))
{
throw std::runtime_error("Generate JSON failed");
}
return wkt;
}
std::string to_wkt_impl(mapnik::geometry::geometry<double> const& geom)
{
std::string wkt;
if (!mapnik::util::to_wkt(wkt,geom))
{
throw std::runtime_error("Generate WKT failed");
}
return wkt;
}
mapnik::geometry::geometry_types geometry_type_impl(mapnik::geometry::geometry<double> const& geom)
{
return mapnik::geometry::geometry_type(geom);
}
mapnik::box2d<double> geometry_envelope_impl(mapnik::geometry::geometry<double> const& geom)
{
return mapnik::geometry::envelope(geom);
}
// only Boost >= 1.56 has is_valid and is_simple
#if BOOST_VERSION >= 105600
bool geometry_is_valid_impl(mapnik::geometry::geometry<double> const& geom)
{
return mapnik::geometry::is_valid(geom);
}
bool geometry_is_simple_impl(mapnik::geometry::geometry<double> const& geom)
{
return mapnik::geometry::is_simple(geom);
}
#endif // BOOST_VERSION >= 1.56
bool geometry_is_empty_impl(mapnik::geometry::geometry<double> const& geom)
{
return mapnik::geometry::is_empty(geom);
}
void geometry_correct_impl(mapnik::geometry::geometry<double> & geom)
{
mapnik::geometry::correct(geom);
}
void polygon_set_exterior_impl(mapnik::geometry::polygon<double> & poly, mapnik::geometry::linear_ring<double> const& ring)
{
poly.exterior_ring = ring; // copy
}
void polygon_add_hole_impl(mapnik::geometry::polygon<double> & poly, mapnik::geometry::linear_ring<double> const& ring)
{
poly.interior_rings.push_back(ring); // copy
}
mapnik::geometry::point<double> geometry_centroid_impl(mapnik::geometry::geometry<double> const& geom)
{
mapnik::geometry::point<double> pt;
mapnik::geometry::centroid(geom, pt);
return pt;
}
void export_geometry()
{
using namespace boost::python;
implicitly_convertible<mapnik::geometry::point<double>, mapnik::geometry::geometry<double> >();
implicitly_convertible<mapnik::geometry::line_string<double>, mapnik::geometry::geometry<double> >();
implicitly_convertible<mapnik::geometry::polygon<double>, mapnik::geometry::geometry<double> >();
enum_<mapnik::geometry::geometry_types>("GeometryType")
.value("Unknown",mapnik::geometry::geometry_types::Unknown)
.value("Point",mapnik::geometry::geometry_types::Point)
.value("LineString",mapnik::geometry::geometry_types::LineString)
.value("Polygon",mapnik::geometry::geometry_types::Polygon)
.value("MultiPoint",mapnik::geometry::geometry_types::MultiPoint)
.value("MultiLineString",mapnik::geometry::geometry_types::MultiLineString)
.value("MultiPolygon",mapnik::geometry::geometry_types::MultiPolygon)
.value("GeometryCollection",mapnik::geometry::geometry_types::GeometryCollection)
;
enum_<mapnik::wkbByteOrder>("wkbByteOrder")
.value("XDR",mapnik::wkbXDR)
.value("NDR",mapnik::wkbNDR)
;
using mapnik::geometry::geometry;
using mapnik::geometry::point;
using mapnik::geometry::line_string;
using mapnik::geometry::linear_ring;
using mapnik::geometry::polygon;
class_<point<double> >("Point", init<double, double>((arg("x"), arg("y")),
"Constructs a new Point object\n"))
.add_property("x", &point<double>::x, "X coordinate")
.add_property("y", &point<double>::y, "Y coordinate")
// only Boost >= 1.56 has is_valid and is_simple
#if BOOST_VERSION >= 105600
.def("is_valid", &geometry_is_valid_impl)
.def("is_simple", &geometry_is_simple_impl)
#endif // BOOST_VERSION >= 1.56
.def("to_geojson",&to_geojson_impl)
.def("to_wkb",&to_wkb_impl)
.def("to_wkt",&to_wkt_impl)
;
class_<line_string<double> >("LineString", init<>(
"Constructs a new LineString object\n"))
.def("add_coord", &line_string<double>::add_coord, "Adds coord")
// only Boost >= 1.56 has is_valid and is_simple
#if BOOST_VERSION >= 105600
.def("is_valid", &geometry_is_valid_impl)
.def("is_simple", &geometry_is_simple_impl)
#endif // BOOST_VERSION >= 1.56
.def("to_geojson",&to_geojson_impl)
.def("to_wkb",&to_wkb_impl)
.def("to_wkt",&to_wkt_impl)
;
class_<linear_ring<double> >("LinearRing", init<>(
"Constructs a new LinearRtring object\n"))
.def("add_coord", &linear_ring<double>::add_coord, "Adds coord")
;
class_<polygon<double> >("Polygon", init<>(
"Constructs a new Polygon object\n"))
.add_property("exterior_ring", &polygon<double>::exterior_ring , "Exterior ring")
.def("add_hole", &polygon_add_hole_impl, "Add interior ring")
.def("num_rings", polygon_set_exterior_impl, "Number of rings (at least 1)")
// only Boost >= 1.56 has is_valid and is_simple
#if BOOST_VERSION >= 105600
.def("is_valid", &geometry_is_valid_impl)
.def("is_simple", &geometry_is_simple_impl)
#endif // BOOST_VERSION >= 1.56
.def("to_geojson",&to_geojson_impl)
.def("to_wkb",&to_wkb_impl)
.def("to_wkt",&to_wkt_impl)
;
class_<geometry<double>, std::shared_ptr<geometry<double> >, boost::noncopyable>("Geometry",no_init)
.def("envelope",&geometry_envelope_impl)
.def("from_geojson", from_geojson_impl)
.def("from_wkt", from_wkt_impl)
.def("from_wkb", from_wkb_impl)
.staticmethod("from_geojson")
.staticmethod("from_wkt")
.staticmethod("from_wkb")
.def("__str__",&to_wkt_impl)
.def("type",&geometry_type_impl)
// only Boost >= 1.56 has is_valid and is_simple
#if BOOST_VERSION >= 105600
.def("is_valid", &geometry_is_valid_impl)
.def("is_simple", &geometry_is_simple_impl)
#endif // BOOST_VERSION >= 1.56
.def("is_empty", &geometry_is_empty_impl)
.def("correct", &geometry_correct_impl)
.def("centroid",&geometry_centroid_impl)
.def("to_wkb",&to_wkb_impl)
.def("to_wkt",&to_wkt_impl)
.def("to_geojson",&to_geojson_impl)
//.def("to_svg",&to_svg)
// TODO add other geometry_type methods
;
}

View file

@ -1,95 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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
*
*****************************************************************************/
#if defined(GRID_RENDERER)
#include <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/grid/grid.hpp>
#include "python_grid_utils.hpp"
using namespace boost::python;
// help compiler see template definitions
static dict (*encode)( mapnik::grid const&, std::string const& , bool, unsigned int) = mapnik::grid_encode;
bool painted(mapnik::grid const& grid)
{
return grid.painted();
}
mapnik::grid::value_type get_pixel(mapnik::grid const& grid, int x, int y)
{
if (x < static_cast<int>(grid.width()) && y < static_cast<int>(grid.height()))
{
mapnik::grid::data_type const & data = grid.data();
return data(x,y);
}
PyErr_SetString(PyExc_IndexError, "invalid x,y for grid dimensions");
boost::python::throw_error_already_set();
return 0;
}
void export_grid()
{
class_<mapnik::grid,std::shared_ptr<mapnik::grid> >(
"Grid",
"This class represents a feature hitgrid.",
init<int,int,std::string>(
( boost::python::arg("width"), boost::python::arg("height"),boost::python::arg("key")="__id__"),
"Create a mapnik.Grid object\n"
))
.def("painted",&painted)
.def("width",&mapnik::grid::width)
.def("height",&mapnik::grid::height)
.def("view",&mapnik::grid::get_view)
.def("get_pixel",&get_pixel)
.def("clear",&mapnik::grid::clear)
.def("encode",encode,
( boost::python::arg("encoding")="utf", boost::python::arg("features")=true,boost::python::arg("resolution")=4 ),
"Encode the grid as as optimized json\n"
)
.add_property("key",
make_function(&mapnik::grid::get_key,return_value_policy<copy_const_reference>()),
&mapnik::grid::set_key,
"Get/Set key to be used as unique indentifier for features\n"
"The value should either be __id__ to refer to the feature.id()\n"
"or some globally unique integer or string attribute field\n"
)
;
}
#endif

View file

@ -1,64 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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
*
*****************************************************************************/
#if defined(GRID_RENDERER)
#include <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <string>
#include <mapnik/grid/grid_view.hpp>
#include <mapnik/grid/grid.hpp>
#include "python_grid_utils.hpp"
using namespace boost::python;
// help compiler see template definitions
static dict (*encode)( mapnik::grid_view const&, std::string const& , bool, unsigned int) = mapnik::grid_encode;
void export_grid_view()
{
class_<mapnik::grid_view,
std::shared_ptr<mapnik::grid_view> >("GridView",
"This class represents a feature hitgrid subset.",no_init)
.def("width",&mapnik::grid_view::width)
.def("height",&mapnik::grid_view::height)
.def("encode",encode,
( boost::python::arg("encoding")="utf",boost::python::arg("add_features")=true,boost::python::arg("resolution")=4 ),
"Encode the grid as as optimized json\n"
)
;
}
#endif

View file

@ -1,471 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/color.hpp>
#include <mapnik/palette.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/image_copy.hpp>
#include <mapnik/image_reader.hpp>
#include <mapnik/image_compositing.hpp>
#include <mapnik/image_view_any.hpp>
// cairo
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <mapnik/cairo/cairo_context.hpp>
#include <mapnik/cairo/cairo_image_util.hpp>
#include <pycairo.h>
#include <cairo.h>
#endif
using mapnik::image_any;
using mapnik::image_reader;
using mapnik::get_image_reader;
using mapnik::type_from_filename;
using mapnik::save_to_file;
using namespace boost::python;
// output 'raw' pixels
PyObject* tostring1( image_any const& im)
{
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
((const char*)im.getBytes(),im.getSize());
}
// encode (png,jpeg)
PyObject* tostring2(image_any const & im, std::string const& format)
{
std::string s = mapnik::save_to_string(im, format);
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
(s.data(),s.size());
}
PyObject* tostring3(image_any const & im, std::string const& format, mapnik::rgba_palette const& pal)
{
std::string s = mapnik::save_to_string(im, format, pal);
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
(s.data(),s.size());
}
void save_to_file1(mapnik::image_any const& im, std::string const& filename)
{
save_to_file(im,filename);
}
void save_to_file2(mapnik::image_any const& im, std::string const& filename, std::string const& type)
{
save_to_file(im,filename,type);
}
void save_to_file3(mapnik::image_any const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal)
{
save_to_file(im,filename,type,pal);
}
mapnik::image_view_any get_view(mapnik::image_any const& data,unsigned x,unsigned y, unsigned w,unsigned h)
{
return mapnik::create_view(data,x,y,w,h);
}
bool is_solid(mapnik::image_any const& im)
{
return mapnik::is_solid(im);
}
void fill_color(mapnik::image_any & im, mapnik::color const& c)
{
mapnik::fill(im, c);
}
void fill_int(mapnik::image_any & im, int val)
{
mapnik::fill(im, val);
}
void fill_double(mapnik::image_any & im, double val)
{
mapnik::fill(im, val);
}
std::shared_ptr<image_any> copy(mapnik::image_any const& im, mapnik::image_dtype type, double offset, double scaling)
{
return std::make_shared<image_any>(std::move(mapnik::image_copy(im, type, offset, scaling)));
}
unsigned compare(mapnik::image_any const& im1, mapnik::image_any const& im2, double threshold, bool alpha)
{
return mapnik::compare(im1, im2, threshold, alpha);
}
struct get_pixel_visitor
{
get_pixel_visitor(unsigned x, unsigned y)
: x_(x), y_(y) {}
object operator() (mapnik::image_null const&)
{
throw std::runtime_error("Can not return a null image from a pixel (shouldn't have reached here)");
}
template <typename T>
object operator() (T const& im)
{
using pixel_type = typename T::pixel_type;
return object(mapnik::get_pixel<pixel_type>(im, x_, y_));
}
private:
unsigned x_;
unsigned y_;
};
object get_pixel(mapnik::image_any const& im, unsigned x, unsigned y, bool get_color)
{
if (x < static_cast<unsigned>(im.width()) && y < static_cast<unsigned>(im.height()))
{
if (get_color)
{
return object(
mapnik::get_pixel<mapnik::color>(im, x, y)
);
}
else
{
return mapnik::util::apply_visitor(get_pixel_visitor(x, y), im);
}
}
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");
boost::python::throw_error_already_set();
return object();
}
void set_pixel_color(mapnik::image_any & im, unsigned x, unsigned y, mapnik::color const& c)
{
if (x >= static_cast<int>(im.width()) && y >= static_cast<int>(im.height()))
{
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");
boost::python::throw_error_already_set();
return;
}
mapnik::set_pixel(im, x, y, c);
}
void set_pixel_double(mapnik::image_any & im, unsigned x, unsigned y, double val)
{
if (x >= static_cast<int>(im.width()) && y >= static_cast<int>(im.height()))
{
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");
boost::python::throw_error_already_set();
return;
}
mapnik::set_pixel(im, x, y, val);
}
void set_pixel_int(mapnik::image_any & im, unsigned x, unsigned y, int val)
{
if (x >= static_cast<int>(im.width()) && y >= static_cast<int>(im.height()))
{
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");
boost::python::throw_error_already_set();
return;
}
mapnik::set_pixel(im, x, y, val);
}
unsigned get_type(mapnik::image_any & im)
{
return im.get_dtype();
}
std::shared_ptr<image_any> open_from_file(std::string const& filename)
{
boost::optional<std::string> type = type_from_filename(filename);
if (type)
{
std::unique_ptr<image_reader> reader(get_image_reader(filename,*type));
if (reader.get())
{
return std::make_shared<image_any>(std::move(reader->read(0,0,reader->width(),reader->height())));
}
throw mapnik::image_reader_exception("Failed to load: " + filename);
}
throw mapnik::image_reader_exception("Unsupported image format:" + filename);
}
std::shared_ptr<image_any> fromstring(std::string const& str)
{
std::unique_ptr<image_reader> reader(get_image_reader(str.c_str(),str.size()));
if (reader.get())
{
return std::make_shared<image_any>(std::move(reader->read(0,0,reader->width(), reader->height())));
}
throw mapnik::image_reader_exception("Failed to load image from buffer" );
}
std::shared_ptr<image_any> frombuffer(PyObject * obj)
{
void const* buffer=0;
Py_ssize_t buffer_len;
if (PyObject_AsReadBuffer(obj, &buffer, &buffer_len) == 0)
{
std::unique_ptr<image_reader> reader(get_image_reader(reinterpret_cast<char const*>(buffer),buffer_len));
if (reader.get())
{
return std::make_shared<image_any>(reader->read(0,0,reader->width(),reader->height()));
}
}
throw mapnik::image_reader_exception("Failed to load image from buffer" );
}
void set_grayscale_to_alpha(image_any & im)
{
mapnik::set_grayscale_to_alpha(im);
}
void set_grayscale_to_alpha_c(image_any & im, mapnik::color const& c)
{
mapnik::set_grayscale_to_alpha(im, c);
}
void set_color_to_alpha(image_any & im, mapnik::color const& c)
{
mapnik::set_color_to_alpha(im, c);
}
void set_alpha(image_any & im, float opacity)
{
mapnik::set_alpha(im, opacity);
}
bool premultiplied(image_any &im)
{
return im.get_premultiplied();
}
bool premultiply(image_any & im)
{
return mapnik::premultiply_alpha(im);
}
bool demultiply(image_any & im)
{
return mapnik::demultiply_alpha(im);
}
void clear(image_any & im)
{
mapnik::fill(im, 0);
}
void composite(image_any & dst, image_any & src, mapnik::composite_mode_e mode, float opacity, int dx, int dy)
{
bool demultiply_dst = mapnik::premultiply_alpha(dst);
bool demultiply_src = mapnik::premultiply_alpha(src);
mapnik::composite(dst,src,mode,opacity,dx,dy);
if (demultiply_dst)
{
mapnik::demultiply_alpha(dst);
}
if (demultiply_src)
{
mapnik::demultiply_alpha(src);
}
}
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
std::shared_ptr<image_any> from_cairo(PycairoSurface* py_surface)
{
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
mapnik::image_rgba8 image = mapnik::image_rgba8(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface));
cairo_image_to_rgba8(image, surface);
return std::make_shared<image_any>(std::move(image));
}
#endif
void export_image()
{
using namespace boost::python;
// NOTE: must match list in include/mapnik/image_compositing.hpp
enum_<mapnik::composite_mode_e>("CompositeOp")
.value("clear", mapnik::clear)
.value("src", mapnik::src)
.value("dst", mapnik::dst)
.value("src_over", mapnik::src_over)
.value("dst_over", mapnik::dst_over)
.value("src_in", mapnik::src_in)
.value("dst_in", mapnik::dst_in)
.value("src_out", mapnik::src_out)
.value("dst_out", mapnik::dst_out)
.value("src_atop", mapnik::src_atop)
.value("dst_atop", mapnik::dst_atop)
.value("xor", mapnik::_xor)
.value("plus", mapnik::plus)
.value("minus", mapnik::minus)
.value("multiply", mapnik::multiply)
.value("screen", mapnik::screen)
.value("overlay", mapnik::overlay)
.value("darken", mapnik::darken)
.value("lighten", mapnik::lighten)
.value("color_dodge", mapnik::color_dodge)
.value("color_burn", mapnik::color_burn)
.value("hard_light", mapnik::hard_light)
.value("soft_light", mapnik::soft_light)
.value("difference", mapnik::difference)
.value("exclusion", mapnik::exclusion)
.value("contrast", mapnik::contrast)
.value("invert", mapnik::invert)
.value("grain_merge", mapnik::grain_merge)
.value("grain_extract", mapnik::grain_extract)
.value("hue", mapnik::hue)
.value("saturation", mapnik::saturation)
.value("color", mapnik::_color)
.value("value", mapnik::_value)
.value("linear_dodge", mapnik::linear_dodge)
.value("linear_burn", mapnik::linear_burn)
.value("divide", mapnik::divide)
;
enum_<mapnik::image_dtype>("ImageType")
.value("rgba8", mapnik::image_dtype_rgba8)
.value("gray8", mapnik::image_dtype_gray8)
.value("gray8s", mapnik::image_dtype_gray8s)
.value("gray16", mapnik::image_dtype_gray16)
.value("gray16s", mapnik::image_dtype_gray16s)
.value("gray32", mapnik::image_dtype_gray32)
.value("gray32s", mapnik::image_dtype_gray32s)
.value("gray32f", mapnik::image_dtype_gray32f)
.value("gray64", mapnik::image_dtype_gray64)
.value("gray64s", mapnik::image_dtype_gray64s)
.value("gray64f", mapnik::image_dtype_gray64f)
;
class_<image_any,std::shared_ptr<image_any>, boost::noncopyable >("Image","This class represents a image.",init<int,int>())
.def(init<int,int,mapnik::image_dtype>())
.def(init<int,int,mapnik::image_dtype,bool>())
.def(init<int,int,mapnik::image_dtype,bool,bool>())
.def(init<int,int,mapnik::image_dtype,bool,bool,bool>())
.def("width",&image_any::width)
.def("height",&image_any::height)
.def("view",&get_view)
.def("painted",&image_any::painted)
.def("is_solid",&is_solid)
.def("fill",&fill_color)
.def("fill",&fill_int)
.def("fill",&fill_double)
.def("set_grayscale_to_alpha",&set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image")
.def("set_grayscale_to_alpha",&set_grayscale_to_alpha_c, "Set the grayscale values to the alpha channel of the Image")
.def("set_color_to_alpha",&set_color_to_alpha, "Set a given color to the alpha channel of the Image")
.def("set_alpha",&set_alpha, "Set the overall alpha channel of the Image")
.def("composite",&composite,
( arg("self"),
arg("image"),
arg("mode")=mapnik::src_over,
arg("opacity")=1.0f,
arg("dx")=0,
arg("dy")=0
))
.def("compare",&compare,
( arg("self"),
arg("image"),
arg("threshold")=0.0,
arg("alpha")=true
))
.def("copy",&copy,
( arg("self"),
arg("type"),
arg("offset")=0.0,
arg("scaling")=1.0
))
.add_property("offset",
&image_any::get_offset,
&image_any::set_offset,
"Gets or sets the offset component.\n")
.add_property("scaling",
&image_any::get_scaling,
&image_any::set_scaling,
"Gets or sets the offset component.\n")
.def("premultiplied",&premultiplied)
.def("premultiply",&premultiply)
.def("demultiply",&demultiply)
.def("set_pixel",&set_pixel_color)
.def("set_pixel",&set_pixel_double)
.def("set_pixel",&set_pixel_int)
.def("get_pixel",&get_pixel,
( arg("self"),
arg("x"),
arg("y"),
arg("get_color")=false
))
.def("get_type",&get_type)
.def("clear",&clear)
//TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3
.def("tostring",&tostring1)
.def("tostring",&tostring2)
.def("tostring",&tostring3)
.def("save", &save_to_file1)
.def("save", &save_to_file2)
.def("save", &save_to_file3)
.def("open",open_from_file)
.staticmethod("open")
.def("frombuffer",&frombuffer)
.staticmethod("frombuffer")
.def("fromstring",&fromstring)
.staticmethod("fromstring")
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
.def("from_cairo",&from_cairo)
.staticmethod("from_cairo")
#endif
;
}

View file

@ -1,128 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/image.hpp>
#include <mapnik/image_view.hpp>
#include <mapnik/image_view_any.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/palette.hpp>
#include <sstream>
using mapnik::image_view_any;
using mapnik::save_to_file;
// output 'raw' pixels
PyObject* view_tostring1(image_view_any const& view)
{
std::ostringstream ss(std::ios::out|std::ios::binary);
mapnik::view_to_string(view, ss);
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
((const char*)ss.str().c_str(),ss.str().size());
}
// encode (png,jpeg)
PyObject* view_tostring2(image_view_any const & view, std::string const& format)
{
std::string s = save_to_string(view, format);
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
(s.data(),s.size());
}
PyObject* view_tostring3(image_view_any const & view, std::string const& format, mapnik::rgba_palette const& pal)
{
std::string s = save_to_string(view, format, pal);
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
(s.data(),s.size());
}
bool is_solid(image_view_any const& view)
{
return mapnik::is_solid(view);
}
void save_view1(image_view_any const& view,
std::string const& filename)
{
save_to_file(view,filename);
}
void save_view2(image_view_any const& view,
std::string const& filename,
std::string const& type)
{
save_to_file(view,filename,type);
}
void save_view3(image_view_any const& view,
std::string const& filename,
std::string const& type,
mapnik::rgba_palette const& pal)
{
save_to_file(view,filename,type,pal);
}
void export_image_view()
{
using namespace boost::python;
class_<image_view_any>("ImageView","A view into an image.",no_init)
.def("width",&image_view_any::width)
.def("height",&image_view_any::height)
.def("is_solid",&is_solid)
.def("tostring",&view_tostring1)
.def("tostring",&view_tostring2)
.def("tostring",&view_tostring3)
.def("save",&save_view1)
.def("save",&save_view2)
.def("save",&save_view3)
;
}

View file

@ -1,131 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#pragma GCC diagnostic pop
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/map.hpp>
#include <list>
using mapnik::label_collision_detector4;
using mapnik::box2d;
using mapnik::Map;
namespace
{
std::shared_ptr<label_collision_detector4>
create_label_collision_detector_from_extent(box2d<double> const &extent)
{
return std::make_shared<label_collision_detector4>(extent);
}
std::shared_ptr<label_collision_detector4>
create_label_collision_detector_from_map(Map const &m)
{
double buffer = m.buffer_size();
box2d<double> extent(-buffer, -buffer, m.width() + buffer, m.height() + buffer);
return std::make_shared<label_collision_detector4>(extent);
}
boost::python::list
make_label_boxes(std::shared_ptr<label_collision_detector4> det)
{
boost::python::list boxes;
for (label_collision_detector4::query_iterator jtr = det->begin();
jtr != det->end(); ++jtr)
{
boxes.append<box2d<double> >(jtr->box);
}
return boxes;
}
}
void export_label_collision_detector()
{
using namespace boost::python;
// for overload resolution
void (label_collision_detector4::*insert_box)(box2d<double> const &) = &label_collision_detector4::insert;
class_<label_collision_detector4, std::shared_ptr<label_collision_detector4>, boost::noncopyable>
("LabelCollisionDetector",
"Object to detect collisions between labels, used in the rendering process.",
no_init)
.def("__init__", make_constructor(create_label_collision_detector_from_extent),
"Creates an empty collision detection object with a given extent. Note "
"that the constructor from Map objects is a sensible default and usually "
"what you want to do.\n"
"\n"
"Example:\n"
">>> m = Map(size_x, size_y)\n"
">>> buf_sz = m.buffer_size\n"
">>> extent = mapnik.Box2d(-buf_sz, -buf_sz, m.width + buf_sz, m.height + buf_sz)\n"
">>> detector = mapnik.LabelCollisionDetector(extent)")
.def("__init__", make_constructor(create_label_collision_detector_from_map),
"Creates an empty collision detection object matching the given Map object. "
"The created detector will have the same size, including the buffer, as the "
"map object. This is usually what you want to do.\n"
"\n"
"Example:\n"
">>> m = Map(size_x, size_y)\n"
">>> detector = mapnik.LabelCollisionDetector(m)")
.def("extent", &label_collision_detector4::extent, return_value_policy<copy_const_reference>(),
"Returns the total extent (bounding box) of all labels inside the detector.\n"
"\n"
"Example:\n"
">>> detector.extent()\n"
"Box2d(573.252589209,494.789179821,584.261023823,496.83610261)")
.def("boxes", &make_label_boxes,
"Returns a list of all the label boxes inside the detector.")
.def("insert", insert_box,
"Insert a 2d box into the collision detector. This can be used to ensure that "
"some space is left clear on the map for later overdrawing, for example by "
"non-Mapnik processes.\n"
"\n"
"Example:\n"
">>> m = Map(size_x, size_y)\n"
">>> detector = mapnik.LabelCollisionDetector(m)"
">>> detector.insert(mapnik.Box2d(196, 254, 291, 389))")
;
}

View file

@ -1,388 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/layer.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
using mapnik::layer;
using mapnik::parameters;
using mapnik::datasource_cache;
struct layer_pickle_suite : boost::python::pickle_suite
{
static boost::python::tuple
getinitargs(const layer& l)
{
return boost::python::make_tuple(l.name(),l.srs());
}
static boost::python::tuple
getstate(const layer& l)
{
boost::python::list s;
std::vector<std::string> const& style_names = l.styles();
for (unsigned i = 0; i < style_names.size(); ++i)
{
s.append(style_names[i]);
}
return boost::python::make_tuple(l.clear_label_cache(),l.min_zoom(),l.max_zoom(),l.queryable(),l.datasource()->params(),l.cache_features(),s);
}
static void
setstate (layer& l, boost::python::tuple state)
{
using namespace boost::python;
if (len(state) != 9)
{
PyErr_SetObject(PyExc_ValueError,
("expected 9-item tuple in call to __setstate__; got %s"
% state).ptr()
);
throw_error_already_set();
}
l.set_clear_label_cache(extract<bool>(state[0]));
l.set_min_zoom(extract<double>(state[1]));
l.set_max_zoom(extract<double>(state[2]));
l.set_queryable(extract<bool>(state[3]));
mapnik::parameters params = extract<parameters>(state[4]);
l.set_datasource(datasource_cache::instance().create(params));
boost::python::list s = extract<boost::python::list>(state[5]);
for (int i=0;i<len(s);++i)
{
l.add_style(extract<std::string>(s[i]));
}
l.set_cache_features(extract<bool>(state[6]));
}
};
std::vector<std::string> & (mapnik::layer::*_styles_)() = &mapnik::layer::styles;
void set_maximum_extent(mapnik::layer & l, boost::optional<mapnik::box2d<double> > const& box)
{
if (box)
{
l.set_maximum_extent(*box);
}
else
{
l.reset_maximum_extent();
}
}
void set_buffer_size(mapnik::layer & l, boost::optional<int> const& buffer_size)
{
if (buffer_size)
{
l.set_buffer_size(*buffer_size);
}
else
{
l.reset_buffer_size();
}
}
PyObject * get_buffer_size(mapnik::layer & l)
{
boost::optional<int> buffer_size = l.buffer_size();
if (buffer_size)
{
#if PY_VERSION_HEX >= 0x03000000
return PyLong_FromLong(*buffer_size);
#else
return PyInt_FromLong(*buffer_size);
#endif
}
else
{
Py_RETURN_NONE;
}
}
void export_layer()
{
using namespace boost::python;
class_<std::vector<std::string> >("Names")
.def(vector_indexing_suite<std::vector<std::string>,true >())
;
class_<layer>("Layer", "A Mapnik map layer.", init<std::string const&,optional<std::string const&> >(
"Create a Layer with a named string and, optionally, an srs string.\n"
"\n"
"The srs can be either a Proj.4 epsg code ('+init=epsg:<code>') or\n"
"of a Proj.4 literal ('+proj=<literal>').\n"
"If no srs is specified it will default to '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n"
"\n"
"Usage:\n"
">>> from mapnik import Layer\n"
">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr\n"
"<mapnik._mapnik.Layer object at 0x6a270>\n"
))
.def_pickle(layer_pickle_suite())
.def("envelope",&layer::envelope,
"Return the geographic envelope/bounding box."
"\n"
"Determined based on the layer datasource.\n"
"\n"
"Usage:\n"
">>> from mapnik import Layer\n"
">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.envelope()\n"
"box2d(-1.0,-1.0,0.0,0.0) # default until a datasource is loaded\n"
)
.def("visible", &layer::visible,
"Return True if this layer's data is active and visible at a given scale.\n"
"\n"
"Otherwise returns False.\n"
"Accepts a scale value as an integer or float input.\n"
"Will return False if:\n"
"\tscale >= minzoom - 1e-6\n"
"\tor:\n"
"\tscale < maxzoom + 1e-6\n"
"\n"
"Usage:\n"
">>> from mapnik import Layer\n"
">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.visible(1.0/1000000)\n"
"True\n"
">>> lyr.active = False\n"
">>> lyr.visible(1.0/1000000)\n"
"False\n"
)
.add_property("active",
&layer::active,
&layer::set_active,
"Get/Set whether this layer is active and will be rendered (same as status property).\n"
"\n"
"Usage:\n"
">>> from mapnik import Layer\n"
">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.active\n"
"True # Active by default\n"
">>> lyr.active = False # set False to disable layer rendering\n"
">>> lyr.active\n"
"False\n"
)
.add_property("status",
&layer::active,
&layer::set_active,
"Get/Set whether this layer is active and will be rendered.\n"
"\n"
"Usage:\n"
">>> from mapnik import Layer\n"
">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.status\n"
"True # Active by default\n"
">>> lyr.status = False # set False to disable layer rendering\n"
">>> lyr.status\n"
"False\n"
)
.add_property("clear_label_cache",
&layer::clear_label_cache,
&layer::set_clear_label_cache,
"Get/Set whether to clear the label collision detector cache for this layer during rendering\n"
"\n"
"Usage:\n"
">>> lyr.clear_label_cache\n"
"False # False by default, meaning label positions from other layers will impact placement \n"
">>> lyr.clear_label_cache = True # set to True to clear the label collision detector cache\n"
)
.add_property("cache_features",
&layer::cache_features,
&layer::set_cache_features,
"Get/Set whether features should be cached during rendering if used between multiple styles\n"
"\n"
"Usage:\n"
">>> lyr.cache_features\n"
"False # False by default\n"
">>> lyr.cache_features = True # set to True to enable feature caching\n"
)
.add_property("datasource",
&layer::datasource,
&layer::set_datasource,
"The datasource attached to this layer.\n"
"\n"
"Usage:\n"
">>> from mapnik import Layer, Datasource\n"
">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.datasource = Datasource(type='shape',file='world_borders')\n"
">>> lyr.datasource\n"
"<mapnik.Datasource object at 0x65470>\n"
)
.add_property("buffer_size",
&get_buffer_size,
&set_buffer_size,
"Get/Set the size of buffer around layer in pixels.\n"
"\n"
"Usage:\n"
">>> print(l.buffer_size)\n"
"None # None by default\n"
">>> l.buffer_size = 2\n"
">>> l.buffer_size\n"
"2\n"
)
.add_property("maximum_extent",make_function
(&layer::maximum_extent,return_value_policy<copy_const_reference>()),
&set_maximum_extent,
"The maximum extent of the map.\n"
"\n"
"Usage:\n"
">>> m.maximum_extent = Box2d(-180,-90,180,90)\n"
)
.add_property("maxzoom",
&layer::max_zoom,
&layer::set_max_zoom,
"Get/Set the maximum zoom lever of the layer.\n"
"\n"
"Usage:\n"
">>> from mapnik import Layer\n"
">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.maxzoom\n"
"1.7976931348623157e+308 # default is the numerical maximum\n"
">>> lyr.maxzoom = 1.0/1000000\n"
">>> lyr.maxzoom\n"
"9.9999999999999995e-07\n"
)
.add_property("minzoom",
&layer::min_zoom,
&layer::set_min_zoom,
"Get/Set the minimum zoom lever of the layer.\n"
"\n"
"Usage:\n"
">>> from mapnik import Layer\n"
">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.minzoom # default is 0\n"
"0.0\n"
">>> lyr.minzoom = 1.0/1000000\n"
">>> lyr.minzoom\n"
"9.9999999999999995e-07\n"
)
.add_property("name",
make_function(&layer::name, return_value_policy<copy_const_reference>()),
&layer::set_name,
"Get/Set the name of the layer.\n"
"\n"
"Usage:\n"
">>> from mapnik import Layer\n"
">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.name\n"
"'My Layer'\n"
">>> lyr.name = 'New Name'\n"
">>> lyr.name\n"
"'New Name'\n"
)
.add_property("queryable",
&layer::queryable,
&layer::set_queryable,
"Get/Set whether this layer is queryable.\n"
"\n"
"Usage:\n"
">>> from mapnik import layer\n"
">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.queryable\n"
"False # Not queryable by default\n"
">>> lyr.queryable = True\n"
">>> lyr.queryable\n"
"True\n"
)
.add_property("srs",
make_function(&layer::srs,return_value_policy<copy_const_reference>()),
&layer::set_srs,
"Get/Set the SRS of the layer.\n"
"\n"
"Usage:\n"
">>> from mapnik import layer\n"
">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.srs\n"
"'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' # The default srs if not initialized with custom srs\n"
">>> # set to google mercator with Proj.4 literal\n"
"... \n"
">>> lyr.srs = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'\n"
)
.add_property("group_by",
make_function(&layer::group_by,return_value_policy<copy_const_reference>()),
&layer::set_group_by,
"Get/Set the optional layer group name.\n"
"\n"
"More details at https://github.com/mapnik/mapnik/wiki/Grouped-rendering:\n"
)
.add_property("styles",
make_function(_styles_,return_value_policy<reference_existing_object>()),
"The styles list attached to this layer.\n"
"\n"
"Usage:\n"
">>> from mapnik import layer\n"
">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
">>> lyr.styles\n"
"<mapnik._mapnik.Names object at 0x6d3e8>\n"
">>> len(lyr.styles)\n"
"0\n # no styles until you append them\n"
"lyr.styles.append('My Style') # mapnik uses named styles for flexibility\n"
">>> len(lyr.styles)\n"
"1\n"
">>> lyr.styles[0]\n"
"'My Style'\n"
)
// comparison
.def(self == self)
;
}

View file

@ -1,83 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/noncopyable.hpp>
#pragma GCC diagnostic pop
#include <mapnik/debug.hpp>
#include <mapnik/utils.hpp>
#include "mapnik_enumeration.hpp"
void export_logger()
{
using mapnik::logger;
using mapnik::singleton;
using mapnik::CreateStatic;
using namespace boost::python;
class_<singleton<logger,CreateStatic>,boost::noncopyable>("Singleton",no_init)
.def("instance",&singleton<logger,CreateStatic>::instance,
return_value_policy<reference_existing_object>())
.staticmethod("instance")
;
enum_<mapnik::logger::severity_type>("severity_type")
.value("Debug", logger::debug)
.value("Warn", logger::warn)
.value("Error", logger::error)
.value("None", logger::none)
;
class_<logger,bases<singleton<logger,CreateStatic> >,
boost::noncopyable>("logger",no_init)
.def("get_severity", &logger::get_severity)
.def("set_severity", &logger::set_severity)
.def("get_object_severity", &logger::get_object_severity)
.def("set_object_severity", &logger::set_object_severity)
.def("clear_object_severity", &logger::clear_object_severity)
.def("get_format", &logger::get_format)
.def("set_format", &logger::set_format)
.def("str", &logger::str)
.def("use_file", &logger::use_file)
.def("use_console", &logger::use_console)
.staticmethod("get_severity")
.staticmethod("set_severity")
.staticmethod("get_object_severity")
.staticmethod("set_object_severity")
.staticmethod("clear_object_severity")
.staticmethod("get_format")
.staticmethod("set_format")
.staticmethod("str")
.staticmethod("use_file")
.staticmethod("use_console")
;
}

View file

@ -1,543 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/noncopyable.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include <boost/python/iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/rule.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/map.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/view_transform.hpp>
#include <mapnik/feature_type_style.hpp>
#include "mapnik_enumeration.hpp"
using mapnik::color;
using mapnik::coord;
using mapnik::box2d;
using mapnik::layer;
using mapnik::Map;
std::vector<layer>& (Map::*layers_nonconst)() = &Map::layers;
std::vector<layer> const& (Map::*layers_const)() const = &Map::layers;
mapnik::parameters& (Map::*params_nonconst)() = &Map::get_extra_parameters;
void insert_style(mapnik::Map & m, std::string const& name, mapnik::feature_type_style const& style)
{
m.insert_style(name,style);
}
void insert_fontset(mapnik::Map & m, std::string const& name, mapnik::font_set const& fontset)
{
m.insert_fontset(name,fontset);
}
mapnik::feature_type_style find_style(mapnik::Map const& m, std::string const& name)
{
boost::optional<mapnik::feature_type_style const&> style = m.find_style(name);
if (!style)
{
PyErr_SetString(PyExc_KeyError, "Invalid style name");
boost::python::throw_error_already_set();
}
return *style;
}
mapnik::font_set find_fontset(mapnik::Map const& m, std::string const& name)
{
boost::optional<mapnik::font_set const&> fontset = m.find_fontset(name);
if (!fontset)
{
PyErr_SetString(PyExc_KeyError, "Invalid font_set name");
boost::python::throw_error_already_set();
}
return *fontset;
}
// TODO - we likely should allow indexing by negative number from python
// for now, protect against negative values and kindly throw
mapnik::featureset_ptr query_point(mapnik::Map const& m, int index, double x, double y)
{
if (index < 0){
PyErr_SetString(PyExc_IndexError, "Please provide a layer index >= 0");
boost::python::throw_error_already_set();
}
unsigned idx = index;
return m.query_point(idx, x, y);
}
mapnik::featureset_ptr query_map_point(mapnik::Map const& m, int index, double x, double y)
{
if (index < 0){
PyErr_SetString(PyExc_IndexError, "Please provide a layer index >= 0");
boost::python::throw_error_already_set();
}
unsigned idx = index;
return m.query_map_point(idx, x, y);
}
void set_maximum_extent(mapnik::Map & m, boost::optional<mapnik::box2d<double> > const& box)
{
if (box)
{
m.set_maximum_extent(*box);
}
else
{
m.reset_maximum_extent();
}
}
struct extract_style
{
using result_type = boost::python::tuple;
result_type operator() (std::map<std::string, mapnik::feature_type_style>::value_type const& val) const
{
return boost::python::make_tuple(val.first,val.second);
}
};
using style_extract_iterator = boost::transform_iterator<extract_style, Map::const_style_iterator>;
using style_range = std::pair<style_extract_iterator,style_extract_iterator>;
style_range _styles_ (mapnik::Map const& m)
{
return style_range(
boost::make_transform_iterator<extract_style>(m.begin_styles(), extract_style()),
boost::make_transform_iterator<extract_style>(m.end_styles(), extract_style()));
}
void export_map()
{
using namespace boost::python;
// aspect ratio fix modes
mapnik::enumeration_<mapnik::aspect_fix_mode_e>("aspect_fix_mode")
.value("GROW_BBOX", mapnik::Map::GROW_BBOX)
.value("GROW_CANVAS",mapnik::Map::GROW_CANVAS)
.value("SHRINK_BBOX",mapnik::Map::SHRINK_BBOX)
.value("SHRINK_CANVAS",mapnik::Map::SHRINK_CANVAS)
.value("ADJUST_BBOX_WIDTH",mapnik::Map::ADJUST_BBOX_WIDTH)
.value("ADJUST_BBOX_HEIGHT",mapnik::Map::ADJUST_BBOX_HEIGHT)
.value("ADJUST_CANVAS_WIDTH",mapnik::Map::ADJUST_CANVAS_WIDTH)
.value("ADJUST_CANVAS_HEIGHT", mapnik::Map::ADJUST_CANVAS_HEIGHT)
.value("RESPECT", mapnik::Map::RESPECT)
;
class_<std::vector<layer> >("Layers")
.def(vector_indexing_suite<std::vector<layer> >())
;
class_<style_range>("StyleRange")
.def("__iter__",
boost::python::range(&style_range::first, &style_range::second))
;
class_<Map>("Map","The map object.",init<int,int,optional<std::string const&> >(
( arg("width"),arg("height"),arg("srs") ),
"Create a Map with a width and height as integers and, optionally,\n"
"an srs string either with a Proj.4 epsg code ('+init=epsg:<code>')\n"
"or with a Proj.4 literal ('+proj=<literal>').\n"
"If no srs is specified the map will default to '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n"
"\n"
"Usage:\n"
">>> from mapnik import Map\n"
">>> m = Map(600,400)\n"
">>> m\n"
"<mapnik._mapnik.Map object at 0x6a240>\n"
">>> m.srs\n"
"'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n"
))
.def("append_style",insert_style,
(arg("style_name"),arg("style_object")),
"Insert a Mapnik Style onto the map by appending it.\n"
"\n"
"Usage:\n"
">>> sty\n"
"<mapnik._mapnik.Style object at 0x6a330>\n"
">>> m.append_style('Style Name', sty)\n"
"True # style object added to map by name\n"
">>> m.append_style('Style Name', sty)\n"
"False # you can only append styles with unique names\n"
)
.def("append_fontset",insert_fontset,
(arg("fontset")),
"Add a FontSet to the map."
)
.def("buffered_envelope",
&Map::get_buffered_extent,
"Get the Box2d() of the Map given\n"
"the Map.buffer_size.\n"
"\n"
"Usage:\n"
">>> m = Map(600,400)\n"
">>> m.envelope()\n"
"Box2d(-1.0,-1.0,0.0,0.0)\n"
">>> m.buffered_envelope()\n"
"Box2d(-1.0,-1.0,0.0,0.0)\n"
">>> m.buffer_size = 1\n"
">>> m.buffered_envelope()\n"
"Box2d(-1.02222222222,-1.02222222222,0.0222222222222,0.0222222222222)\n"
)
.def("envelope",
make_function(&Map::get_current_extent,
return_value_policy<copy_const_reference>()),
"Return the Map Box2d object\n"
"and print the string representation\n"
"of the current extent of the map.\n"
"\n"
"Usage:\n"
">>> m.envelope()\n"
"Box2d(-0.185833333333,-0.96,0.189166666667,-0.71)\n"
">>> dir(m.envelope())\n"
"...'center', 'contains', 'expand_to_include', 'forward',\n"
"...'height', 'intersect', 'intersects', 'inverse', 'maxx',\n"
"...'maxy', 'minx', 'miny', 'width'\n"
)
.def("find_fontset",find_fontset,
(arg("name")),
"Find a fontset by name."
)
.def("find_style",
find_style,
(arg("name")),
"Query the Map for a style by name and return\n"
"a style object if found or raise KeyError\n"
"style if not found.\n"
"\n"
"Usage:\n"
">>> m.find_style('Style Name')\n"
"<mapnik._mapnik.Style object at 0x654f0>\n"
)
.add_property("styles", _styles_)
.def("pan",&Map::pan,
(arg("x"),arg("y")),
"Set the Map center at a given x,y location\n"
"as integers in the coordinates of the pixmap or map surface.\n"
"\n"
"Usage:\n"
">>> m = Map(600,400)\n"
">>> m.envelope().center()\n"
"Coord(-0.5,-0.5) # default Map center\n"
">>> m.pan(-1,-1)\n"
">>> m.envelope().center()\n"
"Coord(0.00166666666667,-0.835)\n"
)
.def("pan_and_zoom",&Map::pan_and_zoom,
(arg("x"),arg("y"),arg("factor")),
"Set the Map center at a given x,y location\n"
"and zoom factor as a float.\n"
"\n"
"Usage:\n"
">>> m = Map(600,400)\n"
">>> m.envelope().center()\n"
"Coord(-0.5,-0.5) # default Map center\n"
">>> m.scale()\n"
"-0.0016666666666666668\n"
">>> m.pan_and_zoom(-1,-1,0.25)\n"
">>> m.scale()\n"
"0.00062500000000000001\n"
)
.def("query_map_point",query_map_point,
(arg("layer_idx"),arg("pixel_x"),arg("pixel_y")),
"Query a Map Layer (by layer index) for features \n"
"intersecting the given x,y location in the pixel\n"
"coordinates of the rendered map image.\n"
"Layer index starts at 0 (first layer in map).\n"
"Will return a Mapnik Featureset if successful\n"
"otherwise will return None.\n"
"\n"
"Usage:\n"
">>> featureset = m.query_map_point(0,200,200)\n"
">>> featureset\n"
"<mapnik._mapnik.Featureset object at 0x23b0b0>\n"
">>> featureset.features\n"
">>> [<mapnik.Feature object at 0x3995630>]\n"
)
.def("query_point",query_point,
(arg("layer idx"),arg("x"),arg("y")),
"Query a Map Layer (by layer index) for features \n"
"intersecting the given x,y location in the coordinates\n"
"of map projection.\n"
"Layer index starts at 0 (first layer in map).\n"
"Will return a Mapnik Featureset if successful\n"
"otherwise will return None.\n"
"\n"
"Usage:\n"
">>> featureset = m.query_point(0,-122,48)\n"
">>> featureset\n"
"<mapnik._mapnik.Featureset object at 0x23b0b0>\n"
">>> featureset.features\n"
">>> [<mapnik.Feature object at 0x3995630>]\n"
)
.def("remove_all",&Map::remove_all,
"Remove all Mapnik Styles and layers from the Map.\n"
"\n"
"Usage:\n"
">>> m.remove_all()\n"
)
.def("remove_style",&Map::remove_style,
(arg("style_name")),
"Remove a Mapnik Style from the map.\n"
"\n"
"Usage:\n"
">>> m.remove_style('Style Name')\n"
)
.def("resize",&Map::resize,
(arg("width"),arg("height")),
"Resize a Mapnik Map.\n"
"\n"
"Usage:\n"
">>> m.resize(64,64)\n"
)
.def("scale", &Map::scale,
"Return the Map Scale.\n"
"Usage:\n"
"\n"
">>> m.scale()\n"
)
.def("scale_denominator", &Map::scale_denominator,
"Return the Map Scale Denominator.\n"
"Usage:\n"
"\n"
">>> m.scale_denominator()\n"
)
.def("view_transform",&Map::transform,
"Return the map ViewTransform object\n"
"which is used internally to convert between\n"
"geographic coordinates and screen coordinates.\n"
"\n"
"Usage:\n"
">>> m.view_transform()\n"
)
.def("zoom",&Map::zoom,
(arg("factor")),
"Zoom in or out by a given factor.\n"
"positive number larger than 1, zooms out\n"
"positive number smaller than 1, zooms in\n"
"\n"
"Usage:\n"
"\n"
">>> m.zoom(0.25)\n"
)
.def("zoom_all",&Map::zoom_all,
"Set the geographical extent of the map\n"
"to the combined extents of all active layers.\n"
"\n"
"Usage:\n"
">>> m.zoom_all()\n"
)
.def("zoom_to_box",&Map::zoom_to_box,
(arg("Boxd2")),
"Set the geographical extent of the map\n"
"by specifying a Mapnik Box2d.\n"
"\n"
"Usage:\n"
">>> extext = Box2d(-180.0, -90.0, 180.0, 90.0)\n"
">>> m.zoom_to_box(extent)\n"
)
.add_property("parameters",make_function(params_nonconst,return_value_policy<reference_existing_object>()),"TODO")
.add_property("aspect_fix_mode",
&Map::get_aspect_fix_mode,
&Map::set_aspect_fix_mode,
// TODO - how to add arg info to properties?
//(arg("aspect_fix_mode")),
"Get/Set aspect fix mode.\n"
"Usage:\n"
"\n"
">>> m.aspect_fix_mode = aspect_fix_mode.GROW_BBOX\n"
)
.add_property("background",make_function
(&Map::background,return_value_policy<copy_const_reference>()),
&Map::set_background,
"The background color of the map (same as background_color property).\n"
"\n"
"Usage:\n"
">>> m.background = Color('steelblue')\n"
)
.add_property("background_color",make_function
(&Map::background,return_value_policy<copy_const_reference>()),
&Map::set_background,
"The background color of the map.\n"
"\n"
"Usage:\n"
">>> m.background_color = Color('steelblue')\n"
)
.add_property("background_image",make_function
(&Map::background_image,return_value_policy<copy_const_reference>()),
&Map::set_background_image,
"The optional background image of the map.\n"
"\n"
"Usage:\n"
">>> m.background_image = '/path/to/image.png'\n"
)
.add_property("background_image_comp_op",&Map::background_image_comp_op,
&Map::set_background_image_comp_op,
"The background image compositing operation.\n"
"\n"
"Usage:\n"
">>> m.background_image_comp_op = mapnik.CompositeOp.src_over\n"
)
.add_property("background_image_opacity",&Map::background_image_opacity,
&Map::set_background_image_opacity,
"The background image opacity.\n"
"\n"
"Usage:\n"
">>> m.background_image_opacity = 1.0\n"
)
.add_property("base",
make_function(&Map::base_path,return_value_policy<copy_const_reference>()),
&Map::set_base_path,
"The base path of the map where any files using relative \n"
"paths will be interpreted as relative to.\n"
"\n"
"Usage:\n"
">>> m.base_path = '.'\n"
)
.add_property("buffer_size",
&Map::buffer_size,
&Map::set_buffer_size,
"Get/Set the size of buffer around map in pixels.\n"
"\n"
"Usage:\n"
">>> m.buffer_size\n"
"0 # zero by default\n"
">>> m.buffer_size = 2\n"
">>> m.buffer_size\n"
"2\n"
)
.add_property("height",
&Map::height,
&Map::set_height,
"Get/Set the height of the map in pixels.\n"
"Minimum settable size is 16 pixels.\n"
"\n"
"Usage:\n"
">>> m.height\n"
"400\n"
">>> m.height = 600\n"
">>> m.height\n"
"600\n"
)
.add_property("layers",make_function
(layers_nonconst,return_value_policy<reference_existing_object>()),
"The list of map layers.\n"
"\n"
"Usage:\n"
">>> m.layers\n"
"<mapnik._mapnik.layers object at 0x6d458>"
">>> m.layers[0]\n"
"<mapnik._mapnik.layer object at 0x5fe130>\n"
)
.add_property("maximum_extent",make_function
(&Map::maximum_extent,return_value_policy<copy_const_reference>()),
&set_maximum_extent,
"The maximum extent of the map.\n"
"\n"
"Usage:\n"
">>> m.maximum_extent = Box2d(-180,-90,180,90)\n"
)
.add_property("srs",
make_function(&Map::srs,return_value_policy<copy_const_reference>()),
&Map::set_srs,
"Spatial reference in Proj.4 format.\n"
"Either an epsg code or proj literal.\n"
"For example, a proj literal:\n"
"\t'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n"
"and a proj epsg code:\n"
"\t'+init=epsg:4326'\n"
"\n"
"Note: using epsg codes requires the installation of\n"
"the Proj.4 'epsg' data file normally found in '/usr/local/share/proj'\n"
"\n"
"Usage:\n"
">>> m.srs\n"
"'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' # The default srs if not initialized with custom srs\n"
">>> # set to google mercator with Proj.4 literal\n"
"... \n"
">>> m.srs = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'\n"
)
.add_property("width",
&Map::width,
&Map::set_width,
"Get/Set the width of the map in pixels.\n"
"Minimum settable size is 16 pixels.\n"
"\n"
"Usage:\n"
">>> m.width\n"
"600\n"
">>> m.width = 800\n"
">>> m.width\n"
"800\n"
)
// comparison
.def(self == self)
;
}

View file

@ -1,70 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/noncopyable.hpp>
#pragma GCC diagnostic pop
//mapnik
#include <mapnik/palette.hpp>
// stl
#include <stdexcept>
static std::shared_ptr<mapnik::rgba_palette> make_palette( std::string const& palette, std::string const& format )
{
mapnik::rgba_palette::palette_type type = mapnik::rgba_palette::PALETTE_RGBA;
if (format == "rgb")
type = mapnik::rgba_palette::PALETTE_RGB;
else if (format == "act")
type = mapnik::rgba_palette::PALETTE_ACT;
else
throw std::runtime_error("invalid type passed for mapnik.Palette: must be either rgba, rgb, or act");
return std::make_shared<mapnik::rgba_palette>(palette, type);
}
void export_palette ()
{
using namespace boost::python;
class_<mapnik::rgba_palette,
std::shared_ptr<mapnik::rgba_palette>,
boost::noncopyable >("Palette",no_init)
//, init<std::string,std::string>(
// ( arg("palette"), arg("type")),
// "Creates a new color palette from a file\n"
// )
.def( "__init__", boost::python::make_constructor(make_palette))
.def("to_string", &mapnik::rgba_palette::to_string,
"Returns the palette as a string.\n"
)
;
}

View file

@ -1,246 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/params.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/value_types.hpp>
#include <mapnik/value.hpp>
// stl
#include <iterator>
using mapnik::parameter;
using mapnik::parameters;
struct parameter_pickle_suite : boost::python::pickle_suite
{
static boost::python::tuple
getinitargs(const parameter& p)
{
using namespace boost::python;
return boost::python::make_tuple(p.first,p.second);
}
};
struct parameters_pickle_suite : boost::python::pickle_suite
{
static boost::python::tuple
getstate(const parameters& p)
{
using namespace boost::python;
dict d;
parameters::const_iterator pos=p.begin();
while(pos!=p.end())
{
d[pos->first] = pos->second;
++pos;
}
return boost::python::make_tuple(d);
}
static void setstate(parameters& p, boost::python::tuple state)
{
using namespace boost::python;
if (len(state) != 1)
{
PyErr_SetObject(PyExc_ValueError,
("expected 1-item tuple in call to __setstate__; got %s"
% state).ptr()
);
throw_error_already_set();
}
dict d = extract<dict>(state[0]);
boost::python::list keys = d.keys();
for (int i=0; i<len(keys); ++i)
{
std::string key = extract<std::string>(keys[i]);
object obj = d[key];
extract<std::string> ex0(obj);
extract<mapnik::value_integer> ex1(obj);
extract<double> ex2(obj);
extract<mapnik::value_unicode_string> ex3(obj);
// TODO - this is never hit - we need proper python string -> std::string to get invoked here
if (ex0.check())
{
p[key] = ex0();
}
else if (ex1.check())
{
p[key] = ex1();
}
else if (ex2.check())
{
p[key] = ex2();
}
else if (ex3.check())
{
std::string buffer;
mapnik::to_utf8(ex3(),buffer);
p[key] = buffer;
}
else
{
MAPNIK_LOG_DEBUG(bindings) << "parameters_pickle_suite: Could not unpickle key=" << key;
}
}
}
};
mapnik::value_holder get_params_by_key1(mapnik::parameters const& p, std::string const& key)
{
parameters::const_iterator pos = p.find(key);
if (pos != p.end())
{
// will be auto-converted to proper python type by `mapnik_params_to_python`
return pos->second;
}
return mapnik::value_null();
}
mapnik::value_holder get_params_by_key2(mapnik::parameters const& p, std::string const& key)
{
parameters::const_iterator pos = p.find(key);
if (pos == p.end())
{
PyErr_SetString(PyExc_KeyError, key.c_str());
boost::python::throw_error_already_set();
}
// will be auto-converted to proper python type by `mapnik_params_to_python`
return pos->second;
}
mapnik::parameter get_params_by_index(mapnik::parameters const& p, int index)
{
if (index < 0 || static_cast<unsigned>(index) > p.size())
{
PyErr_SetString(PyExc_IndexError, "Index is out of range");
throw boost::python::error_already_set();
}
parameters::const_iterator itr = p.begin();
std::advance(itr, index);
if (itr != p.end())
{
return *itr;
}
PyErr_SetString(PyExc_IndexError, "Index is out of range");
throw boost::python::error_already_set();
}
unsigned get_params_size(mapnik::parameters const& p)
{
return p.size();
}
void add_parameter(mapnik::parameters & p, mapnik::parameter const& param)
{
p[param.first] = param.second;
}
mapnik::value_holder get_param(mapnik::parameter const& p, int index)
{
if (index == 0)
{
return p.first;
}
else if (index == 1)
{
return p.second;
}
else
{
PyErr_SetString(PyExc_IndexError, "Index is out of range");
throw boost::python::error_already_set();
}
}
std::shared_ptr<mapnik::parameter> create_parameter(mapnik::value_unicode_string const& key, mapnik::value_holder const& value)
{
std::string key_utf8;
mapnik::to_utf8(key, key_utf8);
return std::make_shared<mapnik::parameter>(key_utf8,value);
}
bool contains(mapnik::parameters const& p, std::string const& key)
{
parameters::const_iterator pos = p.find(key);
return pos != p.end();
}
// needed for Python_Unicode to std::string (utf8) conversion
std::shared_ptr<mapnik::parameter> create_parameter_from_string(mapnik::value_unicode_string const& key, mapnik::value_unicode_string const& ustr)
{
std::string key_utf8;
std::string ustr_utf8;
mapnik::to_utf8(key, key_utf8);
mapnik::to_utf8(ustr,ustr_utf8);
return std::make_shared<mapnik::parameter>(key_utf8, ustr_utf8);
}
void export_parameters()
{
using namespace boost::python;
implicitly_convertible<std::string,mapnik::value_holder>();
implicitly_convertible<mapnik::value_null,mapnik::value_holder>();
implicitly_convertible<mapnik::value_integer,mapnik::value_holder>();
implicitly_convertible<mapnik::value_double,mapnik::value_holder>();
class_<parameter,std::shared_ptr<parameter> >("Parameter",no_init)
.def("__init__", make_constructor(create_parameter),
"Create a mapnik.Parameter from a pair of values, the first being a string\n"
"and the second being either a string, and integer, or a float")
.def("__init__", make_constructor(create_parameter_from_string),
"Create a mapnik.Parameter from a pair of values, the first being a string\n"
"and the second being either a string, and integer, or a float")
.def_pickle(parameter_pickle_suite())
.def("__getitem__",get_param)
;
class_<parameters>("Parameters",init<>())
.def_pickle(parameters_pickle_suite())
.def("get",get_params_by_key1)
.def("__getitem__",get_params_by_key2)
.def("__getitem__",get_params_by_index)
.def("__len__",get_params_size)
.def("__contains__",contains)
.def("append",add_parameter)
.def("iteritems",iterator<parameters>())
;
}

View file

@ -1,154 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/noncopyable.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/proj_transform.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/coord.hpp>
#include <mapnik/box2d.hpp>
// stl
#include <stdexcept>
using mapnik::proj_transform;
using mapnik::projection;
struct proj_transform_pickle_suite : boost::python::pickle_suite
{
static boost::python::tuple
getinitargs(const proj_transform& p)
{
using namespace boost::python;
return boost::python::make_tuple(p.source(),p.dest());
}
};
namespace {
mapnik::coord2d forward_transform_c(mapnik::proj_transform& t, mapnik::coord2d const& c)
{
double x = c.x;
double y = c.y;
double z = 0.0;
if (!t.forward(x,y,z)) {
std::ostringstream s;
s << "Failed to forward project "
<< "from " << t.source().params() << " to: " << t.dest().params();
throw std::runtime_error(s.str());
}
return mapnik::coord2d(x,y);
}
mapnik::coord2d backward_transform_c(mapnik::proj_transform& t, mapnik::coord2d const& c)
{
double x = c.x;
double y = c.y;
double z = 0.0;
if (!t.backward(x,y,z)) {
std::ostringstream s;
s << "Failed to back project "
<< "from " << t.dest().params() << " to: " << t.source().params();
throw std::runtime_error(s.str());
}
return mapnik::coord2d(x,y);
}
mapnik::box2d<double> forward_transform_env(mapnik::proj_transform& t, mapnik::box2d<double> const & box)
{
mapnik::box2d<double> new_box = box;
if (!t.forward(new_box)) {
std::ostringstream s;
s << "Failed to forward project "
<< "from " << t.source().params() << " to: " << t.dest().params();
throw std::runtime_error(s.str());
}
return new_box;
}
mapnik::box2d<double> backward_transform_env(mapnik::proj_transform& t, mapnik::box2d<double> const & box)
{
mapnik::box2d<double> new_box = box;
if (!t.backward(new_box)){
std::ostringstream s;
s << "Failed to back project "
<< "from " << t.dest().params() << " to: " << t.source().params();
throw std::runtime_error(s.str());
}
return new_box;
}
mapnik::box2d<double> forward_transform_env_p(mapnik::proj_transform& t, mapnik::box2d<double> const & box, unsigned int points)
{
mapnik::box2d<double> new_box = box;
if (!t.forward(new_box,points)) {
std::ostringstream s;
s << "Failed to forward project "
<< "from " << t.source().params() << " to: " << t.dest().params();
throw std::runtime_error(s.str());
}
return new_box;
}
mapnik::box2d<double> backward_transform_env_p(mapnik::proj_transform& t, mapnik::box2d<double> const & box, unsigned int points)
{
mapnik::box2d<double> new_box = box;
if (!t.backward(new_box,points)){
std::ostringstream s;
s << "Failed to back project "
<< "from " << t.dest().params() << " to: " << t.source().params();
throw std::runtime_error(s.str());
}
return new_box;
}
}
void export_proj_transform ()
{
using namespace boost::python;
class_<proj_transform, boost::noncopyable>("ProjTransform", init< projection const&, projection const& >())
.def_pickle(proj_transform_pickle_suite())
.def("forward", forward_transform_c)
.def("backward",backward_transform_c)
.def("forward", forward_transform_env)
.def("backward",backward_transform_env)
.def("forward", forward_transform_env_p)
.def("backward",backward_transform_env_p)
;
}

View file

@ -1,125 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/coord.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/projection.hpp>
using mapnik::projection;
struct projection_pickle_suite : boost::python::pickle_suite
{
static boost::python::tuple
getinitargs(const projection& p)
{
using namespace boost::python;
return boost::python::make_tuple(p.params());
}
};
namespace {
mapnik::coord2d forward_pt(mapnik::coord2d const& pt,
mapnik::projection const& prj)
{
double x = pt.x;
double y = pt.y;
prj.forward(x,y);
return mapnik::coord2d(x,y);
}
mapnik::coord2d inverse_pt(mapnik::coord2d const& pt,
mapnik::projection const& prj)
{
double x = pt.x;
double y = pt.y;
prj.inverse(x,y);
return mapnik::coord2d(x,y);
}
mapnik::box2d<double> forward_env(mapnik::box2d<double> const & box,
mapnik::projection const& prj)
{
double minx = box.minx();
double miny = box.miny();
double maxx = box.maxx();
double maxy = box.maxy();
prj.forward(minx,miny);
prj.forward(maxx,maxy);
return mapnik::box2d<double>(minx,miny,maxx,maxy);
}
mapnik::box2d<double> inverse_env(mapnik::box2d<double> const & box,
mapnik::projection const& prj)
{
double minx = box.minx();
double miny = box.miny();
double maxx = box.maxx();
double maxy = box.maxy();
prj.inverse(minx,miny);
prj.inverse(maxx,maxy);
return mapnik::box2d<double>(minx,miny,maxx,maxy);
}
}
void export_projection ()
{
using namespace boost::python;
class_<projection>("Projection", "Represents a map projection.",init<std::string const&>(
(arg("proj4_string")),
"Constructs a new projection from its PROJ.4 string representation.\n"
"\n"
"The constructor will throw a RuntimeError in case the projection\n"
"cannot be initialized.\n"
)
)
.def_pickle(projection_pickle_suite())
.def ("params", make_function(&projection::params,
return_value_policy<copy_const_reference>()),
"Returns the PROJ.4 string for this projection.\n")
.def ("expanded",&projection::expanded,
"normalize PROJ.4 definition by expanding +init= syntax\n")
.add_property ("geographic", &projection::is_geographic,
"This property is True if the projection is a geographic projection\n"
"(i.e. it uses lon/lat coordinates)\n")
;
def("forward_",&forward_pt);
def("inverse_",&inverse_pt);
def("forward_",&forward_env);
def("inverse_",&inverse_env);
}

File diff suppressed because it is too large Load diff

View file

@ -1,107 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include "python_to_value.hpp"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/query.hpp>
#include <mapnik/box2d.hpp>
#include <string>
#include <set>
using mapnik::query;
using mapnik::box2d;
namespace python = boost::python;
struct resolution_to_tuple
{
static PyObject* convert(query::resolution_type const& x)
{
python::object tuple(python::make_tuple(std::get<0>(x), std::get<1>(x)));
return python::incref(tuple.ptr());
}
static PyTypeObject const* get_pytype()
{
return &PyTuple_Type;
}
};
struct names_to_list
{
static PyObject* convert(std::set<std::string> const& names)
{
boost::python::list l;
for ( std::string const& name : names )
{
l.append(name);
}
return python::incref(l.ptr());
}
static PyTypeObject const* get_pytype()
{
return &PyList_Type;
}
};
namespace {
void set_variables(mapnik::query & q, boost::python::dict const& d)
{
mapnik::attributes vars = mapnik::dict2attr(d);
q.set_variables(vars);
}
}
void export_query()
{
using namespace boost::python;
to_python_converter<query::resolution_type, resolution_to_tuple> ();
to_python_converter<std::set<std::string>, names_to_list> ();
class_<query>("Query", "a spatial query data object",
init<box2d<double>,query::resolution_type const&,double>() )
.def(init<box2d<double> >())
.add_property("resolution",make_function(&query::resolution,
return_value_policy<copy_const_reference>()))
.add_property("bbox", make_function(&query::get_bbox,
return_value_policy<copy_const_reference>()) )
.add_property("property_names", make_function(&query::property_names,
return_value_policy<copy_const_reference>()) )
.def("add_property_name", &query::add_property_name)
.def("set_variables",&set_variables);
}

View file

@ -1,241 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/raster_colorizer.hpp>
#include <mapnik/symbolizer.hpp>
using mapnik::raster_colorizer;
using mapnik::raster_colorizer_ptr;
using mapnik::symbolizer_base;
using mapnik::colorizer_stop;
using mapnik::colorizer_stops;
using mapnik::colorizer_mode_enum;
using mapnik::color;
using mapnik::COLORIZER_INHERIT;
using mapnik::COLORIZER_LINEAR;
using mapnik::COLORIZER_DISCRETE;
using mapnik::COLORIZER_EXACT;
namespace {
void add_stop(raster_colorizer_ptr & rc, colorizer_stop & stop)
{
rc->add_stop(stop);
}
void add_stop2(raster_colorizer_ptr & rc, float v)
{
colorizer_stop stop(v, rc->get_default_mode(), rc->get_default_color());
rc->add_stop(stop);
}
void add_stop3(raster_colorizer_ptr &rc, float v, color c)
{
colorizer_stop stop(v, rc->get_default_mode(), c);
rc->add_stop(stop);
}
void add_stop4(raster_colorizer_ptr &rc, float v, colorizer_mode_enum m)
{
colorizer_stop stop(v, m, rc->get_default_color());
rc->add_stop(stop);
}
void add_stop5(raster_colorizer_ptr &rc, float v, colorizer_mode_enum m, color c)
{
colorizer_stop stop(v, m, c);
rc->add_stop(stop);
}
mapnik::color get_color(raster_colorizer_ptr &rc, float value)
{
unsigned rgba = rc->get_color(value);
unsigned r = (rgba & 0xff);
unsigned g = (rgba >> 8 ) & 0xff;
unsigned b = (rgba >> 16) & 0xff;
unsigned a = (rgba >> 24) & 0xff;
return mapnik::color(r,g,b,a);
}
colorizer_stops const& get_stops(raster_colorizer_ptr & rc)
{
return rc->get_stops();
}
}
void export_raster_colorizer()
{
using namespace boost::python;
implicitly_convertible<raster_colorizer_ptr, mapnik::symbolizer_base::value_type>();
class_<raster_colorizer,raster_colorizer_ptr>("RasterColorizer",
"A Raster Colorizer object.",
init<colorizer_mode_enum, color>(args("default_mode","default_color"))
)
.def(init<>())
.add_property("default_color",
make_function(&raster_colorizer::get_default_color, return_value_policy<reference_existing_object>()),
&raster_colorizer::set_default_color,
"The default color for stops added without a color (mapnik.Color).\n")
.add_property("default_mode",
&raster_colorizer::get_default_mode_enum,
&raster_colorizer::set_default_mode_enum,
"The default mode (mapnik.ColorizerMode).\n"
"\n"
"If a stop is added without a mode, then it will inherit this default mode\n")
.add_property("stops",
make_function(get_stops,return_value_policy<reference_existing_object>()),
"The list of stops this RasterColorizer contains\n")
.add_property("epsilon",
&raster_colorizer::get_epsilon,
&raster_colorizer::set_epsilon,
"Comparison epsilon value for exact mode\n"
"\n"
"When comparing values in exact mode, values need only be within epsilon to match.\n")
.def("add_stop", add_stop,
(arg("ColorizerStop")),
"Add a colorizer stop to the raster colorizer.\n"
"\n"
"Usage:\n"
">>> colorizer = mapnik.RasterColorizer()\n"
">>> color = mapnik.Color(\"#0044cc\")\n"
">>> stop = mapnik.ColorizerStop(3, mapnik.COLORIZER_INHERIT, color)\n"
">>> colorizer.add_stop(stop)\n"
)
.def("add_stop", add_stop2,
(arg("value")),
"Add a colorizer stop to the raster colorizer, using the default mode and color.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100)\n"
)
.def("add_stop", add_stop3,
(arg("value")),
"Add a colorizer stop to the raster colorizer, using the default mode.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100, mapnik.Color(\"#123456\"))\n"
)
.def("add_stop", add_stop4,
(arg("value")),
"Add a colorizer stop to the raster colorizer, using the default color.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100, mapnik.COLORIZER_EXACT)\n"
)
.def("add_stop", add_stop5,
(arg("value")),
"Add a colorizer stop to the raster colorizer.\n"
"\n"
"Usage:\n"
">>> default_color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer = mapnik.RasterColorizer(mapnik.COLORIZER_LINEAR, default_color)\n"
">>> colorizer.add_stop(100, mapnik.COLORIZER_DISCRETE, mapnik.Color(\"#112233\"))\n"
)
.def("get_color", get_color,
"Get the color assigned to a certain value in raster data.\n"
"\n"
"Usage:\n"
">>> colorizer = mapnik.RasterColorizer()\n"
">>> color = mapnik.Color(\"#0044cc\")\n"
">>> colorizer.add_stop(0, mapnik.COLORIZER_DISCRETE, mapnik.Color(\"#000000\"))\n"
">>> colorizer.add_stop(100, mapnik.COLORIZER_DISCRETE, mapnik.Color(\"#0E0A06\"))\n"
">>> colorizer.get_color(50)\n"
"Color('#070503')\n"
)
;
class_<colorizer_stops>("ColorizerStops",
"A RasterColorizer's collection of ordered color stops.\n"
"This class is not meant to be instantiated from python. However, "
"it can be accessed at a RasterColorizer's \"stops\" attribute for "
"introspection purposes",
no_init)
.def(vector_indexing_suite<colorizer_stops>())
;
enum_<colorizer_mode_enum>("ColorizerMode")
.value("COLORIZER_INHERIT", COLORIZER_INHERIT)
.value("COLORIZER_LINEAR", COLORIZER_LINEAR)
.value("COLORIZER_DISCRETE", COLORIZER_DISCRETE)
.value("COLORIZER_EXACT", COLORIZER_EXACT)
.export_values()
;
class_<colorizer_stop>("ColorizerStop",init<float, colorizer_mode_enum, color const&>(
"A Colorizer Stop object.\n"
"Create with a value, ColorizerMode, and Color\n"
"\n"
"Usage:"
">>> color = mapnik.Color(\"#fff000\")\n"
">>> stop= mapnik.ColorizerStop(42.42, mapnik.COLORIZER_LINEAR, color)\n"
))
.add_property("color",
make_function(&colorizer_stop::get_color, return_value_policy<reference_existing_object>()),
&colorizer_stop::set_color,
"The stop color (mapnik.Color).\n")
.add_property("value",
&colorizer_stop::get_value,
&colorizer_stop::set_value,
"The stop value.\n")
.add_property("label",
make_function(&colorizer_stop::get_label, return_value_policy<copy_const_reference>()),
&colorizer_stop::set_label,
"The stop label.\n")
.add_property("mode",
&colorizer_stop::get_mode_enum,
&colorizer_stop::set_mode_enum,
"The stop mode (mapnik.ColorizerMode).\n"
"\n"
"If this is COLORIZER_INHERIT then it will inherit the default mode\n"
" from the RasterColorizer it is added to.\n")
.def(self == self)
.def("__str__",&colorizer_stop::to_string)
;
}

View file

@ -1,100 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/implicit.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/rule.hpp>
#include <mapnik/expression.hpp>
#include <mapnik/expression_string.hpp>
using mapnik::rule;
using mapnik::expr_node;
using mapnik::expression_ptr;
using mapnik::point_symbolizer;
using mapnik::line_symbolizer;
using mapnik::line_pattern_symbolizer;
using mapnik::polygon_symbolizer;
using mapnik::polygon_pattern_symbolizer;
using mapnik::raster_symbolizer;
using mapnik::shield_symbolizer;
using mapnik::text_symbolizer;
using mapnik::building_symbolizer;
using mapnik::markers_symbolizer;
using mapnik::group_symbolizer;
using mapnik::symbolizer;
using mapnik::to_expression_string;
void export_rule()
{
using namespace boost::python;
implicitly_convertible<point_symbolizer,symbolizer>();
implicitly_convertible<line_symbolizer,symbolizer>();
implicitly_convertible<line_pattern_symbolizer,symbolizer>();
implicitly_convertible<polygon_symbolizer,symbolizer>();
implicitly_convertible<building_symbolizer,symbolizer>();
implicitly_convertible<polygon_pattern_symbolizer,symbolizer>();
implicitly_convertible<raster_symbolizer,symbolizer>();
implicitly_convertible<shield_symbolizer,symbolizer>();
implicitly_convertible<text_symbolizer,symbolizer>();
implicitly_convertible<markers_symbolizer,symbolizer>();
implicitly_convertible<group_symbolizer,symbolizer>();
class_<rule::symbolizers>("Symbolizers",init<>("TODO"))
.def(vector_indexing_suite<rule::symbolizers>())
;
class_<rule>("Rule",init<>("default constructor"))
.def(init<std::string const&,
boost::python::optional<double,double> >())
.add_property("name",make_function
(&rule::get_name,
return_value_policy<copy_const_reference>()),
&rule::set_name)
.add_property("filter",make_function
(&rule::get_filter,return_value_policy<copy_const_reference>()),
&rule::set_filter)
.add_property("min_scale",&rule::get_min_scale,&rule::set_min_scale)
.add_property("max_scale",&rule::get_max_scale,&rule::set_max_scale)
.def("set_else",&rule::set_else)
.def("has_else",&rule::has_else_filter)
.def("set_also",&rule::set_also)
.def("has_also",&rule::has_also_filter)
.def("active",&rule::active)
.add_property("symbols",make_function
(&rule::get_symbolizers,return_value_policy<reference_existing_object>()))
.add_property("copy_symbols",make_function
(&rule::get_symbolizers,return_value_policy<copy_const_reference>()))
;
}

View file

@ -1,58 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/image_scaling.hpp>
// boost
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
void export_scaling_method()
{
using namespace boost::python;
enum_<mapnik::scaling_method_e>("scaling_method")
.value("NEAR", mapnik::SCALING_NEAR)
.value("BILINEAR", mapnik::SCALING_BILINEAR)
.value("BICUBIC", mapnik::SCALING_BICUBIC)
.value("SPLINE16", mapnik::SCALING_SPLINE16)
.value("SPLINE36", mapnik::SCALING_SPLINE36)
.value("HANNING", mapnik::SCALING_HANNING)
.value("HAMMING", mapnik::SCALING_HAMMING)
.value("HERMITE", mapnik::SCALING_HERMITE)
.value("KAISER", mapnik::SCALING_KAISER)
.value("QUADRIC", mapnik::SCALING_QUADRIC)
.value("CATROM", mapnik::SCALING_CATROM)
.value("GAUSSIAN", mapnik::SCALING_GAUSSIAN)
.value("BESSEL", mapnik::SCALING_BESSEL)
.value("MITCHELL", mapnik::SCALING_MITCHELL)
.value("SINC", mapnik::SCALING_SINC)
.value("LANCZOS", mapnik::SCALING_LANCZOS)
.value("BLACKMAN", mapnik::SCALING_BLACKMAN)
;
}

View file

@ -1,118 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/value_error.hpp>
#include <mapnik/rule.hpp>
#include "mapnik_enumeration.hpp"
#include <mapnik/feature_type_style.hpp>
#include <mapnik/image_filter_types.hpp> // generate_image_filters
using mapnik::feature_type_style;
using mapnik::rules;
using mapnik::rule;
std::string get_image_filters(feature_type_style & style)
{
std::string filters_str;
std::back_insert_iterator<std::string> sink(filters_str);
generate_image_filters(sink, style.image_filters());
return filters_str;
}
void set_image_filters(feature_type_style & style, std::string const& filters)
{
std::vector<mapnik::filter::filter_type> new_filters;
bool result = parse_image_filters(filters, new_filters);
if (!result)
{
throw mapnik::value_error("failed to parse image-filters: '" + filters + "'");
}
#ifdef _WINDOWS
style.image_filters() = new_filters;
// FIXME : https://svn.boost.org/trac/boost/ticket/2839
#else
style.image_filters() = std::move(new_filters);
#endif
}
void export_style()
{
using namespace boost::python;
mapnik::enumeration_<mapnik::filter_mode_e>("filter_mode")
.value("ALL",mapnik::FILTER_ALL)
.value("FIRST",mapnik::FILTER_FIRST)
;
class_<rules>("Rules",init<>("default ctor"))
.def(vector_indexing_suite<rules>())
;
class_<feature_type_style>("Style",init<>("default style constructor"))
.add_property("rules",make_function
(&feature_type_style::get_rules,
return_value_policy<reference_existing_object>()),
"List of rules belonging to a style as rule objects.\n"
"\n"
"Usage:\n"
">>> for r in m.find_style('style 1').rules:\n"
">>> print r\n"
"<mapnik._mapnik.Rule object at 0x100549910>\n"
"<mapnik._mapnik.Rule object at 0x100549980>\n"
)
.add_property("filter_mode",
&feature_type_style::get_filter_mode,
&feature_type_style::set_filter_mode,
"Set/get the filter mode of the style")
.add_property("opacity",
&feature_type_style::get_opacity,
&feature_type_style::set_opacity,
"Set/get the opacity of the style")
.add_property("comp_op",
&feature_type_style::comp_op,
&feature_type_style::set_comp_op,
"Set/get the comp-op (composite operation) of the style")
.add_property("image_filters_inflate",
&feature_type_style::image_filters_inflate,
&feature_type_style::image_filters_inflate,
"Set/get the image_filters_inflate property of the style")
.add_property("image_filters",
get_image_filters,
set_image_filters,
"Set/get the comp-op (composite operation) of the style")
;
}

View file

@ -1,56 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2010 Robert Coup
*
* 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_PYTHON_BINDING_SVG_INCLUDED
#define MAPNIK_PYTHON_BINDING_SVG_INCLUDED
// mapnik
#include <mapnik/parse_transform.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/value_error.hpp>
namespace mapnik {
using namespace boost::python;
template <class T>
std::string get_svg_transform(T& symbolizer)
{
return symbolizer.get_image_transform_string();
}
template <class T>
void set_svg_transform(T& symbolizer, std::string const& transform_wkt)
{
transform_list_ptr trans_expr = mapnik::parse_transform(transform_wkt);
if (!trans_expr)
{
std::stringstream ss;
ss << "Could not parse transform from '"
<< transform_wkt
<< "', expected SVG transform attribute";
throw mapnik::value_error(ss.str());
}
symbolizer.set_image_transform(trans_expr);
}
} // end of namespace mapnik
#endif // MAPNIK_PYTHON_BINDING_SVG_INCLUDED

View file

@ -1,27 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/svg/geometry_svg_generator_impl.hpp>
#include <string>
using sink_type = std::back_insert_iterator<std::string>;
template struct mapnik::svg::svg_path_generator<sink_type, mapnik::vertex_adapter>;

View file

@ -1,422 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/suite/indexing/map_indexing_suite.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/symbolizer.hpp>
#include <mapnik/symbolizer_hash.hpp>
#include <mapnik/symbolizer_utils.hpp>
#include <mapnik/symbolizer_keys.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/parse_path.hpp>
#include <mapnik/path_expression.hpp>
#include "mapnik_enumeration.hpp"
#include "mapnik_svg.hpp"
#include <mapnik/expression_node.hpp>
#include <mapnik/value_error.hpp>
#include <mapnik/marker_cache.hpp> // for known_svg_prefix_
#include <mapnik/group/group_layout.hpp>
#include <mapnik/group/group_rule.hpp>
#include <mapnik/group/group_symbolizer_properties.hpp>
#include <mapnik/util/variant.hpp>
// stl
#include <sstream>
using mapnik::symbolizer;
using mapnik::point_symbolizer;
using mapnik::line_symbolizer;
using mapnik::line_pattern_symbolizer;
using mapnik::polygon_symbolizer;
using mapnik::polygon_pattern_symbolizer;
using mapnik::raster_symbolizer;
using mapnik::shield_symbolizer;
using mapnik::text_symbolizer;
using mapnik::building_symbolizer;
using mapnik::markers_symbolizer;
using mapnik::debug_symbolizer;
using mapnik::group_symbolizer;
using mapnik::symbolizer_base;
using mapnik::color;
using mapnik::path_processor_type;
using mapnik::path_expression_ptr;
using mapnik::guess_type;
using mapnik::expression_ptr;
using mapnik::parse_path;
namespace {
using namespace boost::python;
void __setitem__(mapnik::symbolizer_base & sym, std::string const& name, mapnik::symbolizer_base::value_type const& val)
{
put(sym, mapnik::get_key(name), val);
}
std::shared_ptr<mapnik::symbolizer_base::value_type> numeric_wrapper(const object& arg)
{
std::shared_ptr<mapnik::symbolizer_base::value_type> result;
if (PyBool_Check(arg.ptr()))
{
mapnik::value_bool val = extract<mapnik::value_bool>(arg);
result.reset(new mapnik::symbolizer_base::value_type(val));
}
else if (PyFloat_Check(arg.ptr()))
{
mapnik::value_double val = extract<mapnik::value_double>(arg);
result.reset(new mapnik::symbolizer_base::value_type(val));
}
else
{
mapnik::value_integer val = extract<mapnik::value_integer>(arg);
result.reset(new mapnik::symbolizer_base::value_type(val));
}
return result;
}
struct extract_python_object
{
using result_type = boost::python::object;
template <typename T>
auto operator() (T const& val) const -> result_type
{
return result_type(val); // wrap into python object
}
};
boost::python::object __getitem__(mapnik::symbolizer_base const& sym, std::string const& name)
{
using const_iterator = symbolizer_base::cont_type::const_iterator;
mapnik::keys key = mapnik::get_key(name);
const_iterator itr = sym.properties.find(key);
if (itr != sym.properties.end())
{
return mapnik::util::apply_visitor(extract_python_object(), itr->second);
}
//mapnik::property_meta_type const& meta = mapnik::get_meta(key);
//return mapnik::util::apply_visitor(extract_python_object(), std::get<1>(meta));
return boost::python::object();
}
/*
std::string __str__(mapnik::symbolizer const& sym)
{
return mapnik::util::apply_visitor(mapnik::symbolizer_to_json(), sym);
}
*/
std::string get_symbolizer_type(symbolizer const& sym)
{
return mapnik::symbolizer_name(sym); // FIXME - do we need this ?
}
std::size_t hash_impl(symbolizer const& sym)
{
return mapnik::util::apply_visitor(mapnik::symbolizer_hash_visitor(), sym);
}
template <typename T>
std::size_t hash_impl_2(T const& sym)
{
return mapnik::symbolizer_hash::value<T>(sym);
}
struct extract_underlying_type_visitor
{
template <typename T>
boost::python::object operator() (T const& sym) const
{
return boost::python::object(sym);
}
};
boost::python::object extract_underlying_type(symbolizer const& sym)
{
return mapnik::util::apply_visitor(extract_underlying_type_visitor(), sym);
}
}
void export_symbolizer()
{
using namespace boost::python;
//implicitly_convertible<mapnik::value_bool, mapnik::symbolizer_base::value_type>();
implicitly_convertible<mapnik::value_integer, mapnik::symbolizer_base::value_type>();
implicitly_convertible<mapnik::value_double, mapnik::symbolizer_base::value_type>();
implicitly_convertible<std::string, mapnik::symbolizer_base::value_type>();
implicitly_convertible<mapnik::color, mapnik::symbolizer_base::value_type>();
implicitly_convertible<mapnik::expression_ptr, mapnik::symbolizer_base::value_type>();
implicitly_convertible<mapnik::enumeration_wrapper, mapnik::symbolizer_base::value_type>();
implicitly_convertible<std::shared_ptr<mapnik::group_symbolizer_properties>, mapnik::symbolizer_base::value_type>();
enum_<mapnik::keys>("keys")
.value("gamma", mapnik::keys::gamma)
.value("gamma_method",mapnik::keys::gamma_method)
;
class_<symbolizer>("Symbolizer",no_init)
.def("type",get_symbolizer_type)
.def("__hash__",hash_impl)
.def("extract", extract_underlying_type)
;
class_<symbolizer_base::value_type>("NumericWrapper")
.def("__init__", make_constructor(numeric_wrapper))
;
class_<symbolizer_base>("SymbolizerBase",no_init)
.def("__setitem__",&__setitem__)
.def("__setattr__",&__setitem__)
.def("__getitem__",&__getitem__)
.def("__getattr__",&__getitem__)
//.def("__str__", &__str__)
.def(self == self) // __eq__
;
}
void export_shield_symbolizer()
{
using namespace boost::python;
class_< shield_symbolizer, bases<text_symbolizer> >("ShieldSymbolizer",
init<>("Default ctor"))
.def("__hash__",hash_impl_2<shield_symbolizer>)
;
}
void export_polygon_symbolizer()
{
using namespace boost::python;
class_<polygon_symbolizer, bases<symbolizer_base> >("PolygonSymbolizer",
init<>("Default ctor"))
.def("__hash__",hash_impl_2<polygon_symbolizer>)
;
}
void export_polygon_pattern_symbolizer()
{
using namespace boost::python;
mapnik::enumeration_<mapnik::pattern_alignment_e>("pattern_alignment")
.value("LOCAL",mapnik::LOCAL_ALIGNMENT)
.value("GLOBAL",mapnik::GLOBAL_ALIGNMENT)
;
class_<polygon_pattern_symbolizer>("PolygonPatternSymbolizer",
init<>("Default ctor"))
.def("__hash__",hash_impl_2<polygon_pattern_symbolizer>)
;
}
void export_raster_symbolizer()
{
using namespace boost::python;
class_<raster_symbolizer, bases<symbolizer_base> >("RasterSymbolizer",
init<>("Default ctor"))
;
}
void export_point_symbolizer()
{
using namespace boost::python;
mapnik::enumeration_<mapnik::point_placement_e>("point_placement")
.value("CENTROID",mapnik::CENTROID_POINT_PLACEMENT)
.value("INTERIOR",mapnik::INTERIOR_POINT_PLACEMENT)
;
class_<point_symbolizer, bases<symbolizer_base> >("PointSymbolizer",
init<>("Default Point Symbolizer - 4x4 black square"))
.def("__hash__",hash_impl_2<point_symbolizer>)
;
}
void export_markers_symbolizer()
{
using namespace boost::python;
mapnik::enumeration_<mapnik::marker_placement_e>("marker_placement")
.value("POINT_PLACEMENT",mapnik::MARKER_POINT_PLACEMENT)
.value("INTERIOR_PLACEMENT",mapnik::MARKER_INTERIOR_PLACEMENT)
.value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT)
;
mapnik::enumeration_<mapnik::marker_multi_policy_e>("marker_multi_policy")
.value("EACH",mapnik::MARKER_EACH_MULTI)
.value("WHOLE",mapnik::MARKER_WHOLE_MULTI)
.value("LARGEST",mapnik::MARKER_LARGEST_MULTI)
;
class_<markers_symbolizer, bases<symbolizer_base> >("MarkersSymbolizer",
init<>("Default Markers Symbolizer - circle"))
.def("__hash__",hash_impl_2<markers_symbolizer>)
;
}
void export_line_symbolizer()
{
using namespace boost::python;
mapnik::enumeration_<mapnik::line_rasterizer_e>("line_rasterizer")
.value("FULL",mapnik::RASTERIZER_FULL)
.value("FAST",mapnik::RASTERIZER_FAST)
;
mapnik::enumeration_<mapnik::line_cap_e>("stroke_linecap",
"The possible values for a line cap used when drawing\n"
"with a stroke.\n")
.value("BUTT_CAP",mapnik::BUTT_CAP)
.value("SQUARE_CAP",mapnik::SQUARE_CAP)
.value("ROUND_CAP",mapnik::ROUND_CAP)
;
mapnik::enumeration_<mapnik::line_join_e>("stroke_linejoin",
"The possible values for the line joining mode\n"
"when drawing with a stroke.\n")
.value("MITER_JOIN",mapnik::MITER_JOIN)
.value("MITER_REVERT_JOIN",mapnik::MITER_REVERT_JOIN)
.value("ROUND_JOIN",mapnik::ROUND_JOIN)
.value("BEVEL_JOIN",mapnik::BEVEL_JOIN)
;
class_<line_symbolizer, bases<symbolizer_base> >("LineSymbolizer",
init<>("Default LineSymbolizer - 1px solid black"))
.def("__hash__",hash_impl_2<line_symbolizer>)
;
}
void export_line_pattern_symbolizer()
{
using namespace boost::python;
class_<line_pattern_symbolizer, bases<symbolizer_base> >("LinePatternSymbolizer",
init<> ("Default LinePatternSymbolizer"))
.def("__hash__",hash_impl_2<line_pattern_symbolizer>)
;
}
void export_debug_symbolizer()
{
using namespace boost::python;
mapnik::enumeration_<mapnik::debug_symbolizer_mode_e>("debug_symbolizer_mode")
.value("COLLISION",mapnik::DEBUG_SYM_MODE_COLLISION)
.value("VERTEX",mapnik::DEBUG_SYM_MODE_VERTEX)
;
class_<debug_symbolizer, bases<symbolizer_base> >("DebugSymbolizer",
init<>("Default debug Symbolizer"))
.def("__hash__",hash_impl_2<debug_symbolizer>)
;
}
void export_building_symbolizer()
{
using namespace boost::python;
class_<building_symbolizer, bases<symbolizer_base> >("BuildingSymbolizer",
init<>("Default BuildingSymbolizer"))
.def("__hash__",hash_impl_2<building_symbolizer>)
;
}
namespace {
void group_symbolizer_properties_set_layout_simple(mapnik::group_symbolizer_properties &p,
mapnik::simple_row_layout &s)
{
p.set_layout(s);
}
void group_symbolizer_properties_set_layout_pair(mapnik::group_symbolizer_properties &p,
mapnik::pair_layout &s)
{
p.set_layout(s);
}
std::shared_ptr<mapnik::group_rule> group_rule_construct1(mapnik::expression_ptr p)
{
return std::make_shared<mapnik::group_rule>(p, mapnik::expression_ptr());
}
} // anonymous namespace
void export_group_symbolizer()
{
using namespace boost::python;
using mapnik::group_rule;
using mapnik::simple_row_layout;
using mapnik::pair_layout;
using mapnik::group_symbolizer_properties;
class_<group_rule, std::shared_ptr<group_rule> >("GroupRule",
init<expression_ptr, expression_ptr>())
.def("__init__", boost::python::make_constructor(group_rule_construct1))
.def("append", &group_rule::append)
.def("set_filter", &group_rule::set_filter)
.def("set_repeat_key", &group_rule::set_repeat_key)
;
class_<simple_row_layout>("SimpleRowLayout")
.def("item_margin", &simple_row_layout::get_item_margin)
.def("set_item_margin", &simple_row_layout::set_item_margin)
;
class_<pair_layout>("PairLayout")
.def("item_margin", &simple_row_layout::get_item_margin)
.def("set_item_margin", &simple_row_layout::set_item_margin)
.def("max_difference", &pair_layout::get_max_difference)
.def("set_max_difference", &pair_layout::set_max_difference)
;
class_<group_symbolizer_properties, std::shared_ptr<group_symbolizer_properties> >("GroupSymbolizerProperties")
.def("add_rule", &group_symbolizer_properties::add_rule)
.def("set_layout", &group_symbolizer_properties_set_layout_simple)
.def("set_layout", &group_symbolizer_properties_set_layout_pair)
;
class_<group_symbolizer, bases<symbolizer_base> >("GroupSymbolizer",
init<>("Default GroupSymbolizer"))
.def("__hash__",hash_impl_2<group_symbolizer>)
;
}

View file

@ -1,587 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#include "boost_std_shared_shim.hpp"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#include <boost/python/stl_iterator.hpp>
#include <boost/noncopyable.hpp>
#pragma GCC diagnostic pop
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/placements/simple.hpp>
#include <mapnik/text/placements/list.hpp>
#include <mapnik/text/formatting/text.hpp>
#include <mapnik/text/formatting/list.hpp>
#include <mapnik/text/formatting/format.hpp>
#include <mapnik/text/formatting/layout.hpp>
#include <mapnik/text/text_layout.hpp>
#include <mapnik/symbolizer.hpp>
#include "mapnik_enumeration.hpp"
#include "mapnik_threads.hpp"
using namespace mapnik;
/* Notes:
Overriding functions in inherited classes:
boost.python documentation doesn't really tell you how to do it.
But this helps:
http://www.gamedev.net/topic/446225-inheritance-in-boostpython/
register_ptr_to_python is required for wrapped classes, but not for unwrapped.
Functions don't have to be members of the class, but can also be
normal functions taking a ref to the class as first parameter.
*/
namespace {
using namespace boost::python;
// This class works around a feature in boost python.
// See http://osdir.com/ml/python.c++/2003-11/msg00158.html
template <typename T,
typename X1 = boost::python::detail::not_specified,
typename X2 = boost::python::detail::not_specified,
typename X3 = boost::python::detail::not_specified>
class class_with_converter : public boost::python::class_<T, X1, X2, X3>
{
public:
using self = class_with_converter<T,X1,X2,X3>;
// Construct with the class name, with or without docstring, and default __init__() function
class_with_converter(char const* name, char const* doc = 0) : boost::python::class_<T, X1, X2, X3>(name, doc) { }
// Construct with class name, no docstring, and an uncallable __init__ function
class_with_converter(char const* name, boost::python::no_init_t y) : boost::python::class_<T, X1, X2, X3>(name, y) { }
// Construct with class name, docstring, and an uncallable __init__ function
class_with_converter(char const* name, char const* doc, boost::python::no_init_t y) : boost::python::class_<T, X1, X2, X3>(name, doc, y) { }
// Construct with class name and init<> function
template <class DerivedT> class_with_converter(char const* name, boost::python::init_base<DerivedT> const& i)
: boost::python::class_<T, X1, X2, X3>(name, i) { }
// Construct with class name, docstring and init<> function
template <class DerivedT>
inline class_with_converter(char const* name, char const* doc, boost::python::init_base<DerivedT> const& i)
: boost::python::class_<T, X1, X2, X3>(name, doc, i) { }
template <class D>
self& def_readwrite_convert(char const* name, D const& d, char const* /*doc*/=0)
{
this->add_property(name,
boost::python::make_getter(d, boost::python::return_value_policy<boost::python::return_by_value>()),
boost::python::make_setter(d, boost::python::default_call_policies()));
return *this;
}
};
/*
boost::python::tuple get_displacement(text_layout_properties const& t)
{
return boost::python::make_tuple(0.0,0.0);// FIXME t.displacement.x, t.displacement.y);
}
void set_displacement(text_layout_properties &t, boost::python::tuple arg)
{
if (len(arg) != 2)
{
PyErr_SetObject(PyExc_ValueError,
("expected 2-item tuple in call to set_displacement; got %s"
% arg).ptr()
);
throw_error_already_set();
}
//double x = extract<double>(arg[0]);
//double y = extract<double>(arg[1]);
//t.displacement.set(x, y); FIXME
}
struct NodeWrap
: formatting::node, wrapper<formatting::node>
{
NodeWrap()
: formatting::node(), wrapper<formatting::node>() {}
void apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
python_block_auto_unblock b;
this->get_override("apply")(ptr(&p), ptr(&feature), ptr(&vars), ptr(&output));
}
virtual void add_expressions(expression_set &output) const
{
override o = this->get_override("add_expressions");
if (o)
{
python_block_auto_unblock b;
o(ptr(&output));
} else
{
formatting::node::add_expressions(output);
}
}
void default_add_expressions(expression_set &output) const
{
formatting::node::add_expressions(output);
}
};
*/
/*
struct TextNodeWrap
: formatting::text_node, wrapper<formatting::text_node>
{
TextNodeWrap(expression_ptr expr)
: formatting::text_node(expr), wrapper<formatting::text_node>() {}
TextNodeWrap(std::string expr_text)
: formatting::text_node(expr_text), wrapper<formatting::text_node>() {}
virtual void apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
if(override o = this->get_override("apply"))
{
python_block_auto_unblock b;
o(ptr(&p), ptr(&feature), ptr(&vars), ptr(&output));
}
else
{
formatting::text_node::apply(p, feature, vars, output);
}
}
void default_apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
formatting::text_node::apply(p, feature, vars, output);
}
};
*/
/*
struct FormatNodeWrap
: formatting::format_node, wrapper<formatting::format_node>
{
virtual void apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
if(override o = this->get_override("apply"))
{
python_block_auto_unblock b;
o(ptr(&p), ptr(&feature), ptr(&vars), ptr(&output));
}
else
{
formatting::format_node::apply(p, feature, vars ,output);
}
}
void default_apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
formatting::format_node::apply(p, feature, vars, output);
}
};
struct ExprFormatWrap: formatting::expression_format, wrapper<formatting::expression_format>
{
virtual void apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
if(override o = this->get_override("apply"))
{
python_block_auto_unblock b;
o(ptr(&p), ptr(&feature), ptr(&vars), ptr(&output));
}
else
{
formatting::expression_format::apply(p, feature, vars, output);
}
}
void default_apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
formatting::expression_format::apply(p, feature, vars, output);
}
};
struct LayoutNodeWrap: formatting::layout_node, wrapper<formatting::layout_node>
{
virtual void apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
if(override o = this->get_override("apply"))
{
python_block_auto_unblock b;
o(ptr(&p), ptr(&feature), ptr(&vars), ptr(&output));
}
else
{
formatting::layout_node::apply(p, feature, vars, output);
}
}
void default_apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
formatting::layout_node::apply(p, feature, vars, output);
}
};
struct ListNodeWrap: formatting::list_node, wrapper<formatting::list_node>
{
//Default constructor
ListNodeWrap() : formatting::list_node(), wrapper<formatting::list_node>()
{
}
//Special constructor: Takes a python sequence as its argument
ListNodeWrap(object l) : formatting::list_node(), wrapper<formatting::list_node>()
{
stl_input_iterator<formatting::node_ptr> begin(l), end;
while (begin != end)
{
children_.push_back(*begin);
++begin;
}
}
// TODO: Add constructor taking variable number of arguments.
http://wiki.python.org/moin/boost.python/HowTo#A.22Raw.22_function
virtual void apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
if(override o = this->get_override("apply"))
{
python_block_auto_unblock b;
o(ptr(&p), ptr(&feature), ptr(&vars), ptr(&output));
}
else
{
formatting::list_node::apply(p, feature, vars, output);
}
}
void default_apply(evaluated_format_properties_ptr p, feature_impl const& feature, attributes const& vars, text_layout &output) const
{
formatting::list_node::apply(p, feature, vars, output);
}
inline void IndexError(){
PyErr_SetString(PyExc_IndexError, "Index out of range");
throw_error_already_set();
}
unsigned get_length()
{
return children_.size();
}
formatting::node_ptr get_item(int i)
{
if (i < 0) i+= children_.size();
if (i < static_cast<int>(children_.size())) return children_[i];
IndexError();
return formatting::node_ptr(); //Avoid compiler warning
}
void set_item(int i, formatting::node_ptr ptr)
{
if (i < 0) i+= children_.size();
if (i < static_cast<int>(children_.size())) children_[i] = ptr;
IndexError();
}
void append(formatting::node_ptr ptr)
{
children_.push_back(ptr);
}
};
*/
/*
struct TextPlacementsWrap: text_placements, wrapper<text_placements>
{
text_placement_info_ptr get_placement_info(double scale_factor_) const
{
python_block_auto_unblock b;
//return this->get_override("get_placement_info")();
return text_placement_info_ptr();
}
};
struct TextPlacementInfoWrap: text_placement_info, wrapper<text_placement_info>
{
TextPlacementInfoWrap(text_placements const* parent,
double scale_factor_)
: text_placement_info(parent, scale_factor_)
{
}
bool next()
{
python_block_auto_unblock b;
return this->get_override("next")();
}
};
void insert_expression(expression_set *set, expression_ptr p)
{
set->insert(p);
}
evaluated_format_properties_ptr get_format(text_symbolizer const& sym)
{
return sym.get_placement_options()->defaults.format;
}
void set_format(text_symbolizer const& sym, evaluated_format_properties_ptr format)
{
sym.get_placement_options()->defaults.format = format;
}
text_symbolizer_properties & get_properties(text_symbolizer const& sym)
{
return sym.get_placement_options()->defaults;
}
void set_properties(text_symbolizer const& sym, text_symbolizer_properties & defaults)
{
sym.get_placement_options()->defaults = defaults;
}
*/
}
void export_text_placement()
{
/*
using namespace boost::python;
enumeration_<label_placement_e>("label_placement")
.value("LINE_PLACEMENT",LINE_PLACEMENT)
.value("POINT_PLACEMENT",POINT_PLACEMENT)
.value("VERTEX_PLACEMENT",VERTEX_PLACEMENT)
.value("INTERIOR_PLACEMENT",INTERIOR_PLACEMENT)
;
enumeration_<vertical_alignment_e>("vertical_alignment")
.value("TOP",V_TOP)
.value("MIDDLE",V_MIDDLE)
.value("BOTTOM",V_BOTTOM)
.value("AUTO",V_AUTO)
;
enumeration_<horizontal_alignment_e>("horizontal_alignment")
.value("LEFT",H_LEFT)
.value("MIDDLE",H_MIDDLE)
.value("RIGHT",H_RIGHT)
.value("AUTO",H_AUTO)
;
enumeration_<justify_alignment_e>("justify_alignment")
.value("LEFT",J_LEFT)
.value("MIDDLE",J_MIDDLE)
.value("RIGHT",J_RIGHT)
.value("AUTO", J_AUTO)
;
enumeration_<text_transform_e>("text_transform")
.value("NONE",NONE)
.value("UPPERCASE",UPPERCASE)
.value("LOWERCASE",LOWERCASE)
.value("CAPITALIZE",CAPITALIZE)
;
enumeration_<halo_rasterizer_e>("halo_rasterizer")
.value("FULL",HALO_RASTERIZER_FULL)
.value("FAST",HALO_RASTERIZER_FAST)
;
*/
class_<text_symbolizer>("TextSymbolizer",
init<>())
;
/*
class_with_converter<text_symbolizer_properties>
("TextSymbolizerProperties")
.def_readwrite_convert("label_placement", &text_symbolizer_properties::label_placement)
.def_readwrite_convert("upright", &text_symbolizer_properties::upright)
.def_readwrite("label_spacing", &text_symbolizer_properties::label_spacing)
.def_readwrite("label_position_tolerance", &text_symbolizer_properties::label_position_tolerance)
.def_readwrite("avoid_edges", &text_symbolizer_properties::avoid_edges)
.def_readwrite("margin", &text_symbolizer_properties::margin)
.def_readwrite("repeat_distance", &text_symbolizer_properties::repeat_distance)
.def_readwrite("minimum_distance", &text_symbolizer_properties::minimum_distance)
.def_readwrite("minimum_padding", &text_symbolizer_properties::minimum_padding)
.def_readwrite("minimum_path_length", &text_symbolizer_properties::minimum_path_length)
.def_readwrite("maximum_angle_char_delta", &text_symbolizer_properties::max_char_angle_delta)
.def_readwrite("allow_overlap", &text_symbolizer_properties::allow_overlap)
.def_readwrite("largest_bbox_only", &text_symbolizer_properties::largest_bbox_only)
.def_readwrite("layout_defaults", &text_symbolizer_properties::layout_defaults)
//.def_readwrite("format", &text_symbolizer_properties::format)
.add_property ("format_tree",
&text_symbolizer_properties::format_tree,
&text_symbolizer_properties::set_format_tree);
//from_xml, to_xml operate on mapnik's internal XML tree and don't make sense in python.
// add_expressions isn't useful in python either. The result is only needed by
// attribute_collector (which isn't exposed in python) and
// it just calls add_expressions of the associated formatting tree.
// set_old_style expression is just a compatibility wrapper and doesn't need to be exposed in python.
;
class_with_converter<text_layout_properties>
("TextLayoutProperties")
.def_readwrite_convert("horizontal_alignment", &text_layout_properties::halign)
.def_readwrite_convert("justify_alignment", &text_layout_properties::jalign)
.def_readwrite_convert("vertical_alignment", &text_layout_properties::valign)
.def_readwrite("text_ratio", &text_layout_properties::text_ratio)
.def_readwrite("wrap_width", &text_layout_properties::wrap_width)
.def_readwrite("wrap_before", &text_layout_properties::wrap_before)
.def_readwrite("orientation", &text_layout_properties::orientation)
.def_readwrite("rotate_displacement", &text_layout_properties::rotate_displacement)
.add_property("displacement", &get_displacement, &set_displacement);
class_with_converter<detail::evaluated_format_properties>
("CharProperties")
.def_readwrite_convert("text_transform", &detail::evaluated_format_properties::text_transform)
.def_readwrite_convert("fontset", &detail::evaluated_format_properties::fontset)
.def(init<detail::evaluated_format_properties const&>()) //Copy constructor
.def_readwrite("face_name", &detail::evaluated_format_properties::face_name)
.def_readwrite("text_size", &detail::evaluated_format_properties::text_size)
.def_readwrite("character_spacing", &detail::evaluated_format_properties::character_spacing)
.def_readwrite("line_spacing", &detail::evaluated_format_properties::line_spacing)
.def_readwrite("text_opacity", &detail::evaluated_format_properties::text_opacity)
.def_readwrite("fill", &detail::evaluated_format_properties::fill)
.def_readwrite("halo_fill", &detail::evaluated_format_properties::halo_fill)
.def_readwrite("halo_radius", &evaluated_format_properties::halo_radius)
//from_xml, to_xml operate on mapnik's internal XML tree and don't make sense in python.
;
class_<TextPlacementsWrap,
std::shared_ptr<TextPlacementsWrap>,
boost::noncopyable>
("TextPlacements")
.def_readwrite("defaults", &text_placements::defaults)
//.def("get_placement_info", pure_virtual(&text_placements::get_placement_info))
// TODO: add_expressions()
;
register_ptr_to_python<std::shared_ptr<text_placements> >();
class_<TextPlacementInfoWrap,
std::shared_ptr<TextPlacementInfoWrap>,
boost::noncopyable>
("TextPlacementInfo",
init<text_placements const*, double>())
.def("next", pure_virtual(&text_placement_info::next))
.def_readwrite("properties", &text_placement_info::properties)
.def_readwrite("scale_factor", &text_placement_info::scale_factor)
;
register_ptr_to_python<std::shared_ptr<text_placement_info> >();
class_<expression_set,std::shared_ptr<expression_set>,
boost::noncopyable>("ExpressionSet")
.def("insert", &insert_expression);
;
class_<formatting::node,std::shared_ptr<formatting::node>,
boost::noncopyable>("FormattingNode")
.def("apply", pure_virtual(&formatting::node::apply))
.def("add_expressions", pure_virtual(&formatting::node::add_expressions))
.def("to_xml", pure_virtual(&formatting::node::to_xml))
;
register_ptr_to_python<std::shared_ptr<formatting::node> >();
class_<formatting::text_node,
std::shared_ptr<formatting::text_node>,
bases<formatting::node>,boost::noncopyable>("FormattingText", init<expression_ptr>())
.def(init<std::string>())
.def("apply", &formatting::text_node::apply)//, &TextNodeWrap::default_apply)
.add_property("text",&formatting::text_node::get_text, &formatting::text_node::set_text)
;
register_ptr_to_python<std::shared_ptr<formatting::text_node> >();
class_with_converter<FormatNodeWrap,
std::shared_ptr<FormatNodeWrap>,
bases<formatting::node>,
boost::noncopyable>
("FormattingFormat")
.def_readwrite_convert("text_size", &formatting::format_node::text_size)
.def_readwrite_convert("face_name", &formatting::format_node::face_name)
.def_readwrite_convert("character_spacing", &formatting::format_node::character_spacing)
.def_readwrite_convert("line_spacing", &formatting::format_node::line_spacing)
.def_readwrite_convert("text_opacity", &formatting::format_node::text_opacity)
.def_readwrite_convert("text_transform", &formatting::format_node::text_transform)
.def_readwrite_convert("fill", &formatting::format_node::fill)
.def_readwrite_convert("halo_fill", &formatting::format_node::halo_fill)
.def_readwrite_convert("halo_radius", &formatting::format_node::halo_radius)
.def("apply", &formatting::format_node::apply, &FormatNodeWrap::default_apply)
.add_property("child",
&formatting::format_node::get_child,
&formatting::format_node::set_child)
;
register_ptr_to_python<std::shared_ptr<formatting::format_node> >();
class_<ListNodeWrap,
std::shared_ptr<ListNodeWrap>,
bases<formatting::node>,
boost::noncopyable>
("FormattingList", init<>())
.def(init<list>())
.def("append", &formatting::list_node::push_back)
.def("apply", &formatting::list_node::apply, &ListNodeWrap::default_apply)
.def("__len__", &ListNodeWrap::get_length)
.def("__getitem__", &ListNodeWrap::get_item)
.def("__setitem__", &ListNodeWrap::set_item)
.def("append", &ListNodeWrap::append)
;
register_ptr_to_python<std::shared_ptr<formatting::list_node> >();
class_<ExprFormatWrap,
std::shared_ptr<ExprFormatWrap>,
bases<formatting::node>,
boost::noncopyable>
("FormattingExpressionFormat")
.def_readwrite("text_size", &formatting::expression_format::text_size)
.def_readwrite("face_name", &formatting::expression_format::face_name)
.def_readwrite("character_spacing", &formatting::expression_format::character_spacing)
.def_readwrite("line_spacing", &formatting::expression_format::line_spacing)
.def_readwrite("text_opacity", &formatting::expression_format::text_opacity)
.def_readwrite("fill", &formatting::expression_format::fill)
.def_readwrite("halo_fill", &formatting::expression_format::halo_fill)
.def_readwrite("halo_radius", &formatting::expression_format::halo_radius)
.def("apply", &formatting::expression_format::apply, &ExprFormatWrap::default_apply)
.add_property("child",
&formatting::expression_format::get_child,
&formatting::expression_format::set_child)
;
register_ptr_to_python<std::shared_ptr<formatting::expression_format> >();
*/
//TODO: registry
}

View file

@ -1,109 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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_THREADS_HPP
#define MAPNIK_THREADS_HPP
#include <boost/thread/tss.hpp> // for thread_specific_ptr
#include <Python.h>
namespace mapnik {
class python_thread
{
/* Docs:
http://docs.python.org/c-api/init.html#thread-state-and-the-global-interpreter-lock
*/
public:
static void unblock()
{
#ifdef MAPNIK_DEBUG
if (state.get())
{
std::cerr << "ERROR: Python threads are already unblocked. "
"Unblocking again will loose the current state and "
"might crash later. Aborting!\n";
abort(); //This is a serious error and can't be handled in any other sane way
}
#endif
PyThreadState *_save = 0; //Name defined by python
Py_UNBLOCK_THREADS;
state.reset(_save);
#ifdef MAPNIK_DEBUG
if (!_save) {
thread_support = false;
}
#endif
}
static void block()
{
#ifdef MAPNIK_DEBUG
if (thread_support && !state.get())
{
std::cerr << "ERROR: Trying to restore python thread state, "
"but no state is saved. Can't continue and also "
"can't raise an exception because the python "
"interpreter might be non-function. Aborting!\n";
abort();
}
#endif
PyThreadState *_save = state.release(); //Name defined by python
Py_BLOCK_THREADS;
}
private:
static boost::thread_specific_ptr<PyThreadState> state;
#ifdef MAPNIK_DEBUG
static bool thread_support;
#endif
};
class python_block_auto_unblock
{
public:
python_block_auto_unblock()
{
python_thread::block();
}
~python_block_auto_unblock()
{
python_thread::unblock();
}
};
class python_unblock_auto_block
{
public:
python_unblock_auto_block()
{
python_thread::unblock();
}
~python_unblock_auto_block()
{
python_thread::block();
}
};
} //namespace
#endif // MAPNIK_THREADS_HPP

View file

@ -1,90 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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_PYTHON_BINDING_VALUE_CONVERTER_INCLUDED
#define MAPNIK_PYTHON_BINDING_VALUE_CONVERTER_INCLUDED
// mapnik
#include <mapnik/value.hpp>
#include <mapnik/util/variant.hpp>
// boost
#include <boost/python.hpp>
#include <boost/implicit_cast.hpp>
namespace boost { namespace python {
struct value_converter
{
PyObject * operator() (mapnik::value_integer val) const
{
return ::PyLong_FromLongLong(val);
}
PyObject * operator() (mapnik::value_double val) const
{
return ::PyFloat_FromDouble(val);
}
PyObject * operator() (mapnik::value_bool val) const
{
return ::PyBool_FromLong(val);
}
PyObject * operator() (std::string const& s) const
{
return ::PyUnicode_DecodeUTF8(s.c_str(),implicit_cast<ssize_t>(s.length()),0);
}
PyObject * operator() (mapnik::value_unicode_string const& s) const
{
std::string buffer;
mapnik::to_utf8(s,buffer);
return ::PyUnicode_DecodeUTF8(buffer.c_str(),implicit_cast<ssize_t>(buffer.length()),0);
}
PyObject * operator() (mapnik::value_null const& /*s*/) const
{
Py_RETURN_NONE;
}
};
struct mapnik_value_to_python
{
static PyObject* convert(mapnik::value const& v)
{
return mapnik::util::apply_visitor(value_converter(),v);
}
};
struct mapnik_param_to_python
{
static PyObject* convert(mapnik::value_holder const& v)
{
return mapnik::util::apply_visitor(value_converter(),v);
}
};
}}
#endif // MAPNIK_PYTHON_BINDING_VALUE_CONVERTER_INCLUDED

View file

@ -1,92 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 Artem Pavlenko, Jean-Francois Doyon
*
* 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 <mapnik/config.hpp>
// boost
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/view_transform.hpp>
using mapnik::view_transform;
struct view_transform_pickle_suite : boost::python::pickle_suite
{
static boost::python::tuple
getinitargs(const view_transform& c)
{
using namespace boost::python;
return boost::python::make_tuple(c.width(),c.height(),c.extent());
}
};
namespace {
mapnik::coord2d forward_point(mapnik::view_transform const& t, mapnik::coord2d const& in)
{
mapnik::coord2d out(in);
t.forward(out);
return out;
}
mapnik::coord2d backward_point(mapnik::view_transform const& t, mapnik::coord2d const& in)
{
mapnik::coord2d out(in);
t.backward(out);
return out;
}
mapnik::box2d<double> forward_envelope(mapnik::view_transform const& t, mapnik::box2d<double> const& in)
{
return t.forward(in);
}
mapnik::box2d<double> backward_envelope(mapnik::view_transform const& t, mapnik::box2d<double> const& in)
{
return t.backward(in);
}
}
void export_view_transform()
{
using namespace boost::python;
using mapnik::box2d;
using mapnik::coord2d;
class_<view_transform>("ViewTransform",init<int,int,box2d<double> const& > (
"Create a ViewTransform with a width and height as integers and extent"))
.def_pickle(view_transform_pickle_suite())
.def("forward", forward_point)
.def("backward",backward_point)
.def("forward", forward_envelope)
.def("backward",backward_envelope)
.def("scale_x",&view_transform::scale_x)
.def("scale_y",&view_transform::scale_y)
;
}

View file

@ -1,405 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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
*
*****************************************************************************/
#if defined(GRID_RENDERER)
#include <mapnik/config.hpp>
// boost
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/map.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/grid/grid_renderer.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/grid/grid_util.hpp>
#include <mapnik/grid/grid_view.hpp>
#include <mapnik/value_error.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/feature_kv_iterator.hpp>
#include "python_grid_utils.hpp"
// stl
#include <stdexcept>
namespace mapnik {
template <typename T>
void grid2utf(T const& grid_type,
boost::python::list& l,
std::vector<typename T::lookup_type>& key_order)
{
using keys_type = std::map< typename T::lookup_type, typename T::value_type>;
using keys_iterator = typename keys_type::iterator;
typename T::data_type const& data = grid_type.data();
typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys();
typename T::feature_key_type::const_iterator feature_pos;
keys_type keys;
// start counting at utf8 codepoint 32, aka space character
std::uint16_t codepoint = 32;
unsigned array_size = data.width();
for (unsigned y = 0; y < data.height(); ++y)
{
std::uint16_t idx = 0;
const std::unique_ptr<Py_UNICODE[]> line(new Py_UNICODE[array_size]);
typename T::value_type const* row = data.getRow(y);
for (unsigned x = 0; x < data.width(); ++x)
{
typename T::value_type feature_id = row[x];
feature_pos = feature_keys.find(feature_id);
if (feature_pos != feature_keys.end())
{
mapnik::grid::lookup_type val = feature_pos->second;
keys_iterator key_pos = keys.find(val);
if (key_pos == keys.end())
{
// Create a new entry for this key. Skip the codepoints that
// can't be encoded directly in JSON.
if (codepoint == 34) ++codepoint; // Skip "
else if (codepoint == 92) ++codepoint; // Skip backslash
if (feature_id == mapnik::grid::base_mask)
{
keys[""] = codepoint;
key_order.push_back("");
}
else
{
keys[val] = codepoint;
key_order.push_back(val);
}
line[idx++] = static_cast<Py_UNICODE>(codepoint);
++codepoint;
}
else
{
line[idx++] = static_cast<Py_UNICODE>(key_pos->second);
}
}
// else, shouldn't get here...
}
l.append(boost::python::object(
boost::python::handle<>(
PyUnicode_FromUnicode(line.get(), array_size))));
}
}
template <typename T>
void grid2utf(T const& grid_type,
boost::python::list& l,
std::vector<typename T::lookup_type>& key_order,
unsigned int resolution)
{
using keys_type = std::map< typename T::lookup_type, typename T::value_type>;
using keys_iterator = typename keys_type::iterator;
typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys();
typename T::feature_key_type::const_iterator feature_pos;
keys_type keys;
// start counting at utf8 codepoint 32, aka space character
std::uint16_t codepoint = 32;
unsigned array_size = std::ceil(grid_type.width()/static_cast<float>(resolution));
for (unsigned y = 0; y < grid_type.height(); y=y+resolution)
{
std::uint16_t idx = 0;
const std::unique_ptr<Py_UNICODE[]> line(new Py_UNICODE[array_size]);
mapnik::grid::value_type const* row = grid_type.getRow(y);
for (unsigned x = 0; x < grid_type.width(); x=x+resolution)
{
typename T::value_type feature_id = row[x];
feature_pos = feature_keys.find(feature_id);
if (feature_pos != feature_keys.end())
{
mapnik::grid::lookup_type val = feature_pos->second;
keys_iterator key_pos = keys.find(val);
if (key_pos == keys.end())
{
// Create a new entry for this key. Skip the codepoints that
// can't be encoded directly in JSON.
if (codepoint == 34) ++codepoint; // Skip "
else if (codepoint == 92) ++codepoint; // Skip backslash
if (feature_id == mapnik::grid::base_mask)
{
keys[""] = codepoint;
key_order.push_back("");
}
else
{
keys[val] = codepoint;
key_order.push_back(val);
}
line[idx++] = static_cast<Py_UNICODE>(codepoint);
++codepoint;
}
else
{
line[idx++] = static_cast<Py_UNICODE>(key_pos->second);
}
}
// else, shouldn't get here...
}
l.append(boost::python::object(
boost::python::handle<>(
PyUnicode_FromUnicode(line.get(), array_size))));
}
}
template <typename T>
void grid2utf2(T const& grid_type,
boost::python::list& l,
std::vector<typename T::lookup_type>& key_order,
unsigned int resolution)
{
using keys_type = std::map< typename T::lookup_type, typename T::value_type>;
using keys_iterator = typename keys_type::iterator;
typename T::data_type const& data = grid_type.data();
typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys();
typename T::feature_key_type::const_iterator feature_pos;
keys_type keys;
// start counting at utf8 codepoint 32, aka space character
uint16_t codepoint = 32;
mapnik::grid::data_type target(data.width()/resolution,data.height()/resolution);
mapnik::scale_grid(target,grid_type.data(),0.0,0.0);
unsigned array_size = target.width();
for (unsigned y = 0; y < target.height(); ++y)
{
uint16_t idx = 0;
const std::unique_ptr<Py_UNICODE[]> line(new Py_UNICODE[array_size]);
mapnik::grid::value_type * row = target.getRow(y);
unsigned x;
for (x = 0; x < target.width(); ++x)
{
feature_pos = feature_keys.find(row[x]);
if (feature_pos != feature_keys.end())
{
mapnik::grid::lookup_type val = feature_pos->second;
keys_iterator key_pos = keys.find(val);
if (key_pos == keys.end())
{
// Create a new entry for this key. Skip the codepoints that
// can't be encoded directly in JSON.
if (codepoint == 34) ++codepoint; // Skip "
else if (codepoint == 92) ++codepoint; // Skip backslash
keys[val] = codepoint;
key_order.push_back(val);
line[idx++] = static_cast<Py_UNICODE>(codepoint);
++codepoint;
}
else
{
line[idx++] = static_cast<Py_UNICODE>(key_pos->second);
}
}
// else, shouldn't get here...
}
l.append(boost::python::object(
boost::python::handle<>(
PyUnicode_FromUnicode(line.get(), array_size))));
}
}
template <typename T>
void write_features(T const& grid_type,
boost::python::dict& feature_data,
std::vector<typename T::lookup_type> const& key_order)
{
typename T::feature_type const& g_features = grid_type.get_grid_features();
if (g_features.size() <= 0)
{
return;
}
std::set<std::string> const& attributes = grid_type.get_fields();
typename T::feature_type::const_iterator feat_end = g_features.end();
for ( std::string const& key_item :key_order )
{
if (key_item.empty())
{
continue;
}
typename T::feature_type::const_iterator feat_itr = g_features.find(key_item);
if (feat_itr == feat_end)
{
continue;
}
bool found = false;
boost::python::dict feat;
mapnik::feature_ptr feature = feat_itr->second;
for ( std::string const& attr : attributes )
{
if (attr == "__id__")
{
feat[attr.c_str()] = feature->id();
}
else if (feature->has_key(attr))
{
found = true;
feat[attr.c_str()] = feature->get(attr);
}
}
if (found)
{
feature_data[feat_itr->first] = feat;
}
}
}
template <typename T>
void grid_encode_utf(T const& grid_type,
boost::python::dict & json,
bool add_features,
unsigned int resolution)
{
// convert buffer to utf and gather key order
boost::python::list l;
std::vector<typename T::lookup_type> key_order;
if (resolution != 1) {
// resample on the fly - faster, less accurate
mapnik::grid2utf<T>(grid_type,l,key_order,resolution);
// resample first - slower, more accurate
//mapnik::grid2utf2<T>(grid_type,l,key_order,resolution);
}
else
{
mapnik::grid2utf<T>(grid_type,l,key_order);
}
// convert key order to proper python list
boost::python::list keys_a;
for ( typename T::lookup_type const& key_id : key_order )
{
keys_a.append(key_id);
}
// gather feature data
boost::python::dict feature_data;
if (add_features) {
mapnik::write_features<T>(grid_type,feature_data,key_order);
}
json["grid"] = l;
json["keys"] = keys_a;
json["data"] = feature_data;
}
template <typename T>
boost::python::dict grid_encode( T const& grid, std::string const& format, bool add_features, unsigned int resolution)
{
if (format == "utf") {
boost::python::dict json;
grid_encode_utf<T>(grid,json,add_features,resolution);
return json;
}
else
{
std::stringstream s;
s << "'utf' is currently the only supported encoding format.";
throw mapnik::value_error(s.str());
}
}
template boost::python::dict grid_encode( mapnik::grid const& grid, std::string const& format, bool add_features, unsigned int resolution);
template boost::python::dict grid_encode( mapnik::grid_view const& grid, std::string const& format, bool add_features, unsigned int resolution);
void render_layer_for_grid(mapnik::Map const& map,
mapnik::grid & grid,
unsigned layer_idx,
boost::python::list const& fields,
double scale_factor,
unsigned offset_x,
unsigned offset_y)
{
std::vector<mapnik::layer> const& layers = map.layers();
std::size_t layer_num = layers.size();
if (layer_idx >= layer_num) {
std::ostringstream s;
s << "Zero-based layer index '" << layer_idx << "' not valid, only '"
<< layer_num << "' layers are in map\n";
throw std::runtime_error(s.str());
}
// convert python list to std::set
boost::python::ssize_t num_fields = boost::python::len(fields);
for(boost::python::ssize_t i=0; i<num_fields; i++) {
boost::python::extract<std::string> name(fields[i]);
if (name.check())
{
grid.add_field(name());
}
else
{
std::stringstream s;
s << "list of field names must be strings";
throw mapnik::value_error(s.str());
}
}
// copy field names
std::set<std::string> attributes = grid.get_fields();
// todo - make this a static constant
std::string known_id_key = "__id__";
if (attributes.find(known_id_key) != attributes.end())
{
attributes.erase(known_id_key);
}
std::string join_field = grid.get_key();
if (known_id_key != join_field &&
attributes.find(join_field) == attributes.end())
{
attributes.insert(join_field);
}
mapnik::grid_renderer<mapnik::grid> ren(map,grid,scale_factor,offset_x,offset_y);
mapnik::layer const& layer = layers[layer_idx];
ren.apply(layer,attributes);
}
}
#endif

View file

@ -1,79 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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_PYTHON_BINDING_GRID_UTILS_INCLUDED
#define MAPNIK_PYTHON_BINDING_GRID_UTILS_INCLUDED
// boost
#include <boost/python.hpp>
// mapnik
#include <mapnik/map.hpp>
#include <mapnik/grid/grid.hpp>
namespace mapnik {
template <typename T>
void grid2utf(T const& grid_type,
boost::python::list& l,
std::vector<typename T::lookup_type>& key_order);
template <typename T>
void grid2utf(T const& grid_type,
boost::python::list& l,
std::vector<typename T::lookup_type>& key_order,
unsigned int resolution);
template <typename T>
void grid2utf2(T const& grid_type,
boost::python::list& l,
std::vector<typename T::lookup_type>& key_order,
unsigned int resolution);
template <typename T>
void write_features(T const& grid_type,
boost::python::dict& feature_data,
std::vector<typename T::lookup_type> const& key_order);
template <typename T>
void grid_encode_utf(T const& grid_type,
boost::python::dict & json,
bool add_features,
unsigned int resolution);
template <typename T>
boost::python::dict grid_encode( T const& grid, std::string const& format, bool add_features, unsigned int resolution);
void render_layer_for_grid(const mapnik::Map& map,
mapnik::grid& grid,
unsigned layer_idx, // TODO - layer by name or index
boost::python::list const& fields,
double scale_factor,
unsigned offset_x,
unsigned offset_y);
}
#endif // MAPNIK_PYTHON_BINDING_GRID_UTILS_INCLUDED

View file

@ -1,198 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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 <boost/optional/optional.hpp>
#include <boost/python.hpp>
#include <mapnik/util/noncopyable.hpp>
// boost::optional<T> to/from converter from John Wiegley
template <typename T, typename TfromPy>
struct object_from_python
{
object_from_python() {
boost::python::converter::registry::push_back
(&TfromPy::convertible, &TfromPy::construct,
boost::python::type_id<T>());
}
};
template <typename T, typename TtoPy, typename TfromPy>
struct register_python_conversion
{
register_python_conversion() {
boost::python::to_python_converter<T, TtoPy>();
object_from_python<T, TfromPy>();
}
};
template <typename T>
struct python_optional : public mapnik::util::noncopyable
{
struct optional_to_python
{
static PyObject * convert(const boost::optional<T>& value)
{
return (value ? boost::python::to_python_value<T>()(*value) :
boost::python::detail::none());
}
};
struct optional_from_python
{
static void * convertible(PyObject * source)
{
using namespace boost::python::converter;
if (source == Py_None)
return source;
const registration& converters(registered<T>::converters);
if (implicit_rvalue_convertible_from_python(source,
converters)) {
rvalue_from_python_stage1_data data =
rvalue_from_python_stage1(source, converters);
return rvalue_from_python_stage2(source, data, converters);
}
return 0;
}
static void construct(PyObject * source,
boost::python::converter::rvalue_from_python_stage1_data * data)
{
using namespace boost::python::converter;
void * const storage = ((rvalue_from_python_storage<T> *)
data)->storage.bytes;
if (data->convertible == source) // == None
new (storage) boost::optional<T>(); // A Boost uninitialized value
else
new (storage) boost::optional<T>(*static_cast<T *>(data->convertible));
data->convertible = storage;
}
};
explicit python_optional()
{
register_python_conversion<boost::optional<T>,
optional_to_python, optional_from_python>();
}
};
// to/from boost::optional<bool>
template <>
struct python_optional<float> : public mapnik::util::noncopyable
{
struct optional_to_python
{
static PyObject * convert(const boost::optional<float>& value)
{
return (value ? PyFloat_FromDouble(*value) :
boost::python::detail::none());
}
};
struct optional_from_python
{
static void * convertible(PyObject * source)
{
using namespace boost::python::converter;
if (source == Py_None || PyFloat_Check(source))
return source;
return 0;
}
static void construct(PyObject * source,
boost::python::converter::rvalue_from_python_stage1_data * data)
{
using namespace boost::python::converter;
void * const storage = ((rvalue_from_python_storage<boost::optional<bool> > *)
data)->storage.bytes;
if (source == Py_None) // == None
new (storage) boost::optional<float>(); // A Boost uninitialized value
else
new (storage) boost::optional<float>(PyFloat_AsDouble(source));
data->convertible = storage;
}
};
explicit python_optional()
{
register_python_conversion<boost::optional<float>,
optional_to_python, optional_from_python>();
}
};
// to/from boost::optional<float>
template <>
struct python_optional<bool> : public mapnik::util::noncopyable
{
struct optional_to_python
{
static PyObject * convert(const boost::optional<bool>& value)
{
if (value)
{
if (*value) Py_RETURN_TRUE;
else Py_RETURN_FALSE;
}
else return boost::python::detail::none();
}
};
struct optional_from_python
{
static void * convertible(PyObject * source)
{
using namespace boost::python::converter;
if (source == Py_None || PyBool_Check(source))
return source;
return 0;
}
static void construct(PyObject * source,
boost::python::converter::rvalue_from_python_stage1_data * data)
{
using namespace boost::python::converter;
void * const storage = ((rvalue_from_python_storage<boost::optional<bool> > *)
data)->storage.bytes;
if (source == Py_None) // == None
new (storage) boost::optional<bool>(); // A Boost uninitialized value
else
{
new (storage) boost::optional<bool>(source == Py_True ? true : false);
}
data->convertible = storage;
}
};
explicit python_optional()
{
register_python_conversion<boost::optional<bool>,
optional_to_python, optional_from_python>();
}
};

View file

@ -1,122 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2014 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_PYTHON_BINDING_PYTHON_TO_VALUE
#define MAPNIK_PYTHON_BINDING_PYTHON_TO_VALUE
// boost
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#include <boost/python.hpp>
#pragma GCC diagnostic pop
// mapnik
#include <mapnik/value.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/attribute.hpp>
namespace mapnik {
static mapnik::attributes dict2attr(boost::python::dict const& d)
{
using namespace boost::python;
mapnik::attributes vars;
mapnik::transcoder tr_("utf8");
boost::python::list keys=d.keys();
for (int i=0; i < len(keys); ++i)
{
std::string key;
object obj_key = keys[i];
if (PyUnicode_Check(obj_key.ptr()))
{
PyObject* temp = PyUnicode_AsUTF8String(obj_key.ptr());
if (temp)
{
#if PY_VERSION_HEX >= 0x03000000
char* c_str = PyBytes_AsString(temp);
#else
char* c_str = PyString_AsString(temp);
#endif
key = c_str;
Py_DecRef(temp);
}
}
else
{
key = extract<std::string>(keys[i]);
}
object obj = d[key];
if (PyUnicode_Check(obj.ptr()))
{
PyObject* temp = PyUnicode_AsUTF8String(obj.ptr());
if (temp)
{
#if PY_VERSION_HEX >= 0x03000000
char* c_str = PyBytes_AsString(temp);
#else
char* c_str = PyString_AsString(temp);
#endif
vars[key] = tr_.transcode(c_str);
Py_DecRef(temp);
}
continue;
}
if (PyBool_Check(obj.ptr()))
{
extract<mapnik::value_bool> ex(obj);
if (ex.check())
{
vars[key] = ex();
}
}
else if (PyFloat_Check(obj.ptr()))
{
extract<mapnik::value_double> ex(obj);
if (ex.check())
{
vars[key] = ex();
}
}
else
{
extract<mapnik::value_integer> ex(obj);
if (ex.check())
{
vars[key] = ex();
}
else
{
extract<std::string> ex0(obj);
if (ex0.check())
{
vars[key] = tr_.transcode(ex0().c_str());
}
}
}
}
return vars;
}
}
#endif // MAPNIK_PYTHON_BINDING_PYTHON_TO_VALUE

View file

@ -8,7 +8,7 @@ todo
- gdal shared lib / avoid dlclose atexit crash - gdal shared lib / avoid dlclose atexit crash
- clang debs to s3 - clang debs to s3
- docs for base setup: sudo apt-get -y install zlib1g-dev python-dev make git python-dev - docs for base setup: sudo apt-get -y install zlib1g-dev make git
- shrink icu data - shrink icu data
' '
@ -50,7 +50,6 @@ function install_mason_deps() {
install boost_libfilesystem 1.57.0 install boost_libfilesystem 1.57.0
install boost_libprogram_options 1.57.0 install boost_libprogram_options 1.57.0
install boost_libregex 1.57.0 install boost_libregex 1.57.0
install boost_libpython 1.57.0
install libpq 9.4.0 install libpq 9.4.0
install sqlite 3.8.8.1 install sqlite 3.8.8.1
install gdal 1.11.1 install gdal 1.11.1
@ -59,14 +58,6 @@ function install_mason_deps() {
install cairo 1.12.18 install cairo 1.12.18
} }
function setup_nose() {
if [[ ! -d $(pwd)/nose-1.3.4 ]]; then
curl -s -O https://pypi.python.org/packages/source/n/nose/nose-1.3.4.tar.gz
tar -xzf nose-1.3.4.tar.gz
fi
export PYTHONPATH=$(pwd)/nose-1.3.4:${PYTHONPATH}
}
MASON_LINKED_ABS=$(pwd)/mason_packages/.link MASON_LINKED_ABS=$(pwd)/mason_packages/.link
MASON_LINKED_REL=./mason_packages/.link MASON_LINKED_REL=./mason_packages/.link
@ -114,11 +105,9 @@ CAIRO_INCLUDES = '${MASON_LINKED_REL}/include'
CAIRO_LIBS = '${MASON_LINKED_REL}/lib' CAIRO_LIBS = '${MASON_LINKED_REL}/lib'
SQLITE_INCLUDES = '${MASON_LINKED_REL}/include' SQLITE_INCLUDES = '${MASON_LINKED_REL}/include'
SQLITE_LIBS = '${MASON_LINKED_REL}/lib' SQLITE_LIBS = '${MASON_LINKED_REL}/lib'
FRAMEWORK_PYTHON = False
BENCHMARK = True BENCHMARK = True
CPP_TESTS = True CPP_TESTS = True
PGSQL2SQLITE = True PGSQL2SQLITE = True
BINDINGS = 'python'
XMLPARSER = 'ptree' XMLPARSER = 'ptree'
SVG2PNG = True SVG2PNG = True
SAMPLE_INPUT_PLUGINS = True SAMPLE_INPUT_PLUGINS = True
@ -134,7 +123,6 @@ function setup_runtime_settings() {
function main() { function main() {
setup_mason setup_mason
install_mason_deps install_mason_deps
setup_nose
make_config make_config
setup_runtime_settings setup_runtime_settings
echo "Ready, now run:" echo "Ready, now run:"

View file

@ -6,7 +6,6 @@ if [ ${UNAME} = 'Darwin' ]; then
else else
export LD_LIBRARY_PATH="${CURRENT_DIR}/src/":${LD_LIBRARY_PATH} export LD_LIBRARY_PATH="${CURRENT_DIR}/src/":${LD_LIBRARY_PATH}
fi fi
export PYTHONPATH="${CURRENT_DIR}/bindings/python/":$PYTHONPATH
export MAPNIK_FONT_DIRECTORY="${CURRENT_DIR}/fonts/dejavu-fonts-ttf-2.34/ttf/" export MAPNIK_FONT_DIRECTORY="${CURRENT_DIR}/fonts/dejavu-fonts-ttf-2.34/ttf/"
export MAPNIK_INPUT_PLUGINS_DIRECTORY="${CURRENT_DIR}/plugins/input/" export MAPNIK_INPUT_PLUGINS_DIRECTORY="${CURRENT_DIR}/plugins/input/"
export PATH="${CURRENT_DIR}/utils/mapnik-config":${PATH} export PATH="${CURRENT_DIR}/utils/mapnik-config":${PATH}

View file

@ -3,24 +3,10 @@
failures=0 failures=0
source ./localize.sh source ./localize.sh
PYTHON=${PYTHON:-python}
echo "*** Running Next Gen C++ tests..." echo "*** Running C++ tests..."
./tests/cxx/run ./tests/cxx/run
failures=$((failures+$?)) failures=$((failures+$?))
echo echo
echo "*** Running Old C++ tests..."
./tests/cpp_tests/run
failures=$((failures+$?))
echo
echo "*** Running visual tests..."
$PYTHON tests/visual_tests/test.py -q
failures=$((failures+$?))
echo "*** Running python tests..."
$PYTHON tests/run_tests.py -q
failures=$((failures+$?))
exit $failures exit $failures

View file

@ -1,207 +0,0 @@
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/util/fs.hpp>
#include <mapnik/map.hpp>
#include <mapnik/load_map.hpp>
#include <mapnik/debug.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include "utils.hpp"
int main(int argc, char** argv)
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
try
{
mapnik::logger logger;
mapnik::logger::severity_type original_severity = logger.get_severity();
BOOST_TEST(set_working_dir(args));
// grab references to global statics of registered/cached fonts
auto const& global_mapping = mapnik::freetype_engine::get_mapping();
auto const& global_cache = mapnik::freetype_engine::get_cache();
// mapnik.Map object has parallel structure for localized fonts
mapnik::Map m(1,1);
auto const& local_mapping = m.get_font_file_mapping();
auto const& local_cache = m.get_font_memory_cache();
// should be empty to start
BOOST_TEST( global_mapping.empty() );
BOOST_TEST( global_cache.empty() );
BOOST_TEST( local_mapping.empty() );
BOOST_TEST( local_cache.empty() );
std::string fontdir("fonts/");
BOOST_TEST( mapnik::util::exists( fontdir ) );
BOOST_TEST( mapnik::util::is_directory( fontdir ) );
// test map cached fonts
BOOST_TEST( m.register_fonts(fontdir , false ) );
BOOST_TEST( m.get_font_memory_cache().size() == 0 );
BOOST_TEST( m.get_font_file_mapping().size() == 1 );
BOOST_TEST( m.load_fonts() );
BOOST_TEST( m.get_font_memory_cache().size() == 1 );
BOOST_TEST( m.register_fonts(fontdir , true ) );
BOOST_TEST( m.get_font_file_mapping().size() == 22 );
BOOST_TEST( m.load_fonts() );
BOOST_TEST( m.get_font_memory_cache().size() == 22 );
// copy discards memory cache but not file mapping
mapnik::Map m2(m);
BOOST_TEST( m2.get_font_memory_cache().size() == 0 );
BOOST_TEST( m2.get_font_file_mapping().size() == 22 );
BOOST_TEST( m2.load_fonts() );
BOOST_TEST( m2.get_font_memory_cache().size() == 22 );
// test font-directory from XML
mapnik::Map m3(1,1);
mapnik::load_map_string(m3,"<Map font-directory=\"fonts/\"></Map>");
BOOST_TEST( m3.get_font_memory_cache().size() == 0 );
BOOST_TEST( m3.load_fonts() );
BOOST_TEST( m3.get_font_memory_cache().size() == 1 );
std::vector<std::string> face_names;
std::string foo("foo");
// fake directories
BOOST_TEST( !mapnik::freetype_engine::register_fonts(foo , true ) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 0 );
BOOST_TEST( !mapnik::freetype_engine::register_fonts(foo) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 0 );
// directories without fonts
// silence warnings here by altering the logging severity
logger.set_severity(mapnik::logger::none);
std::string src("src");
// an empty directory will not return true
// we need to register at least one font and not fail on any
// to return true
BOOST_TEST( mapnik::freetype_engine::register_font(src) == false );
BOOST_TEST( mapnik::freetype_engine::register_fonts(src, true) == false );
BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 );
// bogus, emtpy file that looks like font
BOOST_TEST( mapnik::freetype_engine::register_font("tests/data/fonts/fake.ttf") == false );
BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/fake.ttf") == false );
BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 );
BOOST_TEST( mapnik::freetype_engine::register_font("tests/data/fonts/intentionally-broken.ttf") == false );
BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/intentionally-broken.ttf") == false );
BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 );
// now restore the original severity
logger.set_severity(original_severity);
// register unifont, since we know it sits in the root fonts/ dir
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() > 0 );
BOOST_TEST( face_names.size() == 1 );
// re-register unifont, should not have any affect
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir, false) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 1 );
// single dejavu font in separate location
std::string dejavu_bold_oblique("tests/data/fonts/DejaVuSansMono-BoldOblique.ttf");
BOOST_TEST( mapnik::freetype_engine::register_font(dejavu_bold_oblique) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 2 );
// now, inspect font mapping and confirm the correct 'DejaVu Sans Mono Bold Oblique' is registered
using font_file_mapping = std::map<std::string, std::pair<int,std::string> >;
font_file_mapping const& name2file = mapnik::freetype_engine::get_mapping();
bool found_dejavu = false;
for (auto const& item : name2file)
{
if (item.first == "DejaVu Sans Mono Bold Oblique")
{
found_dejavu = true;
BOOST_TEST( item.second.first == 0 );
BOOST_TEST( item.second.second == dejavu_bold_oblique );
}
}
BOOST_TEST( found_dejavu );
// recurse to find all dejavu fonts
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir, true) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 22 );
// we should have re-registered 'DejaVu Sans Mono Bold Oblique' again,
// but now at a new path
bool found_dejavu2 = false;
for (auto const& item : name2file)
{
if (item.first == "DejaVu Sans Mono Bold Oblique")
{
found_dejavu2 = true;
BOOST_TEST( item.second.first == 0 );
// path should be different
BOOST_TEST( item.second.second != dejavu_bold_oblique );
}
}
BOOST_TEST( found_dejavu2 );
// now that global registry is populated
// now test that a map only loads new fonts
mapnik::Map m4(1,1);
BOOST_TEST( m4.register_fonts(fontdir , true ) );
BOOST_TEST( m4.get_font_memory_cache().size() == 0 );
BOOST_TEST( m4.get_font_file_mapping().size() == 22 );
BOOST_TEST( !m4.load_fonts() );
BOOST_TEST( m4.get_font_memory_cache().size() == 0 );
BOOST_TEST( m4.register_fonts(dejavu_bold_oblique, false) );
BOOST_TEST( m4.load_fonts() );
BOOST_TEST( m4.get_font_memory_cache().size() == 1 );
// check that we can correctly read a .ttc containing
// multiple valid faces
// https://github.com/mapnik/mapnik/issues/2274
BOOST_TEST( mapnik::freetype_engine::register_font("tests/data/fonts/NotoSans-Regular.ttc") );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 24 );
// now blindly register as many system fonts as possible
// the goal here to make sure we don't crash
// linux
mapnik::freetype_engine::register_fonts("/usr/share/fonts/", true);
mapnik::freetype_engine::register_fonts("/usr/local/share/fonts/", true);
// osx
mapnik::freetype_engine::register_fonts("/Library/Fonts/", true);
mapnik::freetype_engine::register_fonts("/System/Library/Fonts/", true);
// windows
mapnik::freetype_engine::register_fonts("C:\\Windows\\Fonts", true);
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() > 22 );
}
catch (std::exception const & ex)
{
std::clog << ex.what() << "\n";
BOOST_TEST(false);
}
if (!::boost::detail::test_errors()) {
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ fonts registration: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
}
}

View file

@ -1,124 +0,0 @@
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
#include <mapnik/value_types.hpp>
#include <mapnik/params.hpp>
#include <mapnik/boolean.hpp>
#include <vector>
#include <algorithm>
namespace detail {
class string_holder {
public:
string_holder() :
member_("member") {}
std::string const& get_string() const
{
return member_;
}
private:
std::string member_;
};
}
int main(int argc, char** argv)
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
try
{
mapnik::parameters params;
// true
params["bool"] = mapnik::value_integer(true);
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "true";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = mapnik::value_integer(1);
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "1";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "True";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "on";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "yes";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
// false
params["bool"] = mapnik::value_integer(false);
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false) );
params["bool"] = "false";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false) );
params["bool"] = mapnik::value_integer(0);
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
params["bool"] = "0";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
params["bool"] = "False";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
params["bool"] = "off";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
params["bool"] = "no";
BOOST_TEST( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
// strings
params["string"] = "hello";
BOOST_TEST( (params.get<std::string>("string") && *params.get<std::string>("string") == "hello") );
// int
params["int"] = mapnik::value_integer(1);
BOOST_TEST( (params.get<mapnik::value_integer>("int") && *params.get<mapnik::value_integer>("int") == 1) );
// double
params["double"] = 1.5;
BOOST_TEST( (params.get<double>("double") && *params.get<double>("double") == 1.5) );
// value_null
params["null"] = mapnik::value_null();
// https://github.com/mapnik/mapnik/issues/2471
//BOOST_TEST( (params.get<mapnik::value_null>("null") && *params.get<mapnik::value_null>("null") == mapnik::value_null()) );
std::string value("value");
params["value"] = value;
BOOST_TEST(params.get<std::string>("value") == std::string("value"));
BOOST_TEST(value == std::string("value"));
// ensure that const member is not moved incorrectly when added to params
detail::string_holder holder;
std::string const& holder_member = holder.get_string();
params["member"] = holder_member;
BOOST_TEST(params.get<std::string>("member") == std::string("member"));
BOOST_TEST(holder_member == std::string("member"));
}
catch (std::exception const& ex)
{
std::cerr << ex.what() << "\n";
BOOST_TEST(false);
}
if (!::boost::detail::test_errors()) {
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ parameters: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
}
}

View file

@ -1,40 +0,0 @@
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
#include <mapnik/symbolizer.hpp>
#include <vector>
#include <algorithm>
using namespace mapnik;
int main(int argc, char** argv)
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
try {
marker_multi_policy_enum policy_in = MARKER_WHOLE_MULTI;
BOOST_TEST_EQ(policy_in,MARKER_WHOLE_MULTI);
markers_symbolizer sym;
put(sym, keys::markers_multipolicy, policy_in);
BOOST_TEST_EQ(sym.properties.count(keys::markers_multipolicy),static_cast<unsigned long>(1));
marker_multi_policy_enum policy_out = get<mapnik::marker_multi_policy_enum>(sym, keys::markers_multipolicy);
BOOST_TEST_EQ(policy_out,MARKER_WHOLE_MULTI);
}
catch (std::exception const & ex)
{
std::clog << ex.what() << std::endl;
BOOST_TEST(false);
}
if (!::boost::detail::test_errors()) {
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ symbolizer test: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
}
}

View file

@ -1,26 +0,0 @@
#include <vector>
#include <algorithm>
#include <string>
#include <mapnik/util/fs.hpp>
#include <boost/filesystem/convenience.hpp>
inline static bool set_working_dir(std::vector<std::string> args)
{
std::vector<std::string>::iterator itr = std::find(args.begin(), args.end(), "-d");
if (itr!=args.end())
{
unsigned dist = std::distance(args.begin(),itr);
if (args.size() > dist+1)
{
std::string chdir = args.at(dist+1);
bool exists = mapnik::util::exists( chdir );
if (exists)
{
boost::filesystem::current_path(chdir);
return true;
}
}
return false;
}
return true;
}

View file

@ -1,4 +1,5 @@
#include <boost/detail/lightweight_test.hpp> #include "catch.hpp"
#include <iostream> #include <iostream>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
@ -132,14 +133,9 @@ template<class ColorT, class Order> struct comp_op_rgba_src_over2
} }
int main(int argc, char** argv) TEST_CASE("blending") {
{
std::vector<std::string> args; SECTION("src over") {
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
using source_over_old_agg = agg::comp_op_rgba_src_over2<color, agg::order_rgba>; using source_over_old_agg = agg::comp_op_rgba_src_over2<color, agg::order_rgba>;
using source_over = agg::comp_op_rgba_src_over<color, agg::order_rgba>; using source_over = agg::comp_op_rgba_src_over<color, agg::order_rgba>;
@ -149,16 +145,16 @@ int main(int argc, char** argv)
color white(255,255,255,255); color white(255,255,255,255);
color black(0,0,0,255); color black(0,0,0,255);
BOOST_TEST_EQ( to_string(blend<source_over>(white,white)), to_string(white) ); REQUIRE( to_string(blend<source_over>(white,white)) == to_string(white) );
BOOST_TEST_EQ( to_string(blend<source_over>(white,black)), to_string(white) ); REQUIRE( to_string(blend<source_over>(white,black)) == to_string(white) );
BOOST_TEST_EQ( to_string(blend<source_over>(black,white)), to_string(black) ); REQUIRE( to_string(blend<source_over>(black,white)) == to_string(black) );
color near_white(254,254,254,254); // Source color near_white(254,254,254,254); // Source
color near_trans(1,1,1,1); // Dest color near_trans(1,1,1,1); // Dest
color expected_color(253,253,253,255); // expected result color expected_color(253,253,253,255); // expected result
BOOST_TEST_EQ( to_string(blend<source_over_old_agg>(near_white,near_trans)), to_string(color(253,253,253,254)) ); REQUIRE( to_string(blend<source_over_old_agg>(near_white,near_trans)) == to_string(color(253,253,253,254)) );
BOOST_TEST_EQ( to_string(blend<source_over>(near_white,near_trans)), to_string(expected_color) ); REQUIRE( to_string(blend<source_over>(near_white,near_trans)) == to_string(expected_color) );
BOOST_TEST_EQ( to_string(normal_blend(near_white,near_trans)), to_string(expected_color) ); REQUIRE( to_string(normal_blend(near_white,near_trans)) == to_string(expected_color) );
// using normal_blend as expected, compare a variety of other colors // using normal_blend as expected, compare a variety of other colors
@ -167,8 +163,8 @@ int main(int argc, char** argv)
color dest(128,128,128,255); color dest(128,128,128,255);
unsigned cover = 128; unsigned cover = 128;
std::string expected_str = to_string(normal_blend(source,dest,cover)); std::string expected_str = to_string(normal_blend(source,dest,cover));
BOOST_TEST_EQ( to_string(blend<source_over>(source,dest,cover)), expected_str ); REQUIRE( to_string(blend<source_over>(source,dest,cover)) == expected_str );
BOOST_TEST_EQ( to_string(blend<source_over_old_agg>(source,dest,cover)), expected_str ); REQUIRE( to_string(blend<source_over_old_agg>(source,dest,cover)) == expected_str );
} }
{ {
@ -176,8 +172,8 @@ int main(int argc, char** argv)
color dest(128,128,128,255); color dest(128,128,128,255);
unsigned cover = 245; unsigned cover = 245;
std::string expected_str = to_string(normal_blend(source,dest,cover)); std::string expected_str = to_string(normal_blend(source,dest,cover));
BOOST_TEST_EQ( to_string(blend<source_over>(source,dest,cover)), expected_str ); REQUIRE( to_string(blend<source_over>(source,dest,cover)) == expected_str );
BOOST_TEST_EQ( to_string(blend<source_over_old_agg>(source,dest,cover)), expected_str ); REQUIRE( to_string(blend<source_over_old_agg>(source,dest,cover)) == expected_str );
} }
// commenting until I study these failures more (dane) // commenting until I study these failures more (dane)
@ -188,8 +184,8 @@ int main(int argc, char** argv)
color dest(127,127,127,127); color dest(127,127,127,127);
unsigned cover = 255; unsigned cover = 255;
std::string expected_str = to_string(normal_blend(source,dest,cover)); std::string expected_str = to_string(normal_blend(source,dest,cover));
BOOST_TEST_EQ( to_string(blend<source_over>(source,dest,cover)), expected_str ); REQUIRE( to_string(blend<source_over>(source,dest,cover)) == expected_str );
BOOST_TEST_EQ( to_string(blend<source_over_old_agg>(source,dest,cover)), expected_str ); REQUIRE( to_string(blend<source_over_old_agg>(source,dest,cover)) == expected_str );
} }
{ {
@ -198,23 +194,16 @@ int main(int argc, char** argv)
color dest(128,128,128,128); color dest(128,128,128,128);
unsigned cover = 128; unsigned cover = 128;
std::string expected_str = to_string(normal_blend(source,dest,cover)); std::string expected_str = to_string(normal_blend(source,dest,cover));
BOOST_TEST_EQ( to_string(blend<source_over>(source,dest,cover)), expected_str ); REQUIRE( to_string(blend<source_over>(source,dest,cover)) == expected_str );
BOOST_TEST_EQ( to_string(blend<source_over_old_agg>(source,dest,cover)), expected_str ); REQUIRE( to_string(blend<source_over_old_agg>(source,dest,cover)) == expected_str );
} }
*/ */
} }
catch (std::exception const & ex) catch (std::exception const & ex)
{ {
std::clog << ex.what() << "\n"; std::clog << ex.what() << "\n";
BOOST_TEST(false); REQUIRE(false);
}
if (!::boost::detail::test_errors()) {
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ AGG blending: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
std::clog << "C++ AGG blending: ";
return ::boost::report_errors();
} }
} }
}

View file

@ -1,3 +1,5 @@
#include "catch.hpp"
// mapnik // mapnik
#include <mapnik/util/conversions.hpp> #include <mapnik/util/conversions.hpp>
#include <mapnik/util/trim.hpp> #include <mapnik/util/trim.hpp>
@ -6,7 +8,6 @@
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Wunused-parameter"
#pragma GCC diagnostic ignored "-Wunused-local-typedef" #pragma GCC diagnostic ignored "-Wunused-local-typedef"
#include <boost/detail/lightweight_test.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
@ -21,10 +22,6 @@
// agg // agg
#include "agg_conv_clip_polygon.h" #include "agg_conv_clip_polygon.h"
#include "agg_conv_clip_polyline.h" #include "agg_conv_clip_polyline.h"
//#include "agg_path_storage.h"
//#include "agg_conv_clipper.h"
#include "utils.hpp"
template <typename T> template <typename T>
std::string dump_path(T & path) std::string dump_path(T & path)
@ -82,19 +79,12 @@ void parse_geom(mapnik::path_type & path,
} }
} }
int main(int argc, char** argv) TEST_CASE("clipping") {
{
std::vector<std::string> args; SECTION("lines") {
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
try { try {
BOOST_TEST(set_working_dir(args));
std::string filename("tests/cpp_tests/data/cases.txt"); std::string filename("tests/cpp_tests/data/cases.txt");
std::ifstream stream(filename.c_str(),std::ios_base::in | std::ios_base::binary); std::ifstream stream(filename.c_str(),std::ios_base::in | std::ios_base::binary);
if (!stream.is_open()) if (!stream.is_open())
@ -116,7 +106,7 @@ int main(int argc, char** argv)
parse_geom(path, parts[1]); parse_geom(path, parts[1]);
//std::clog << dump_path(path) << "\n"; //std::clog << dump_path(path) << "\n";
// third part is expected, clipped geometry // third part is expected, clipped geometry
BOOST_TEST_EQ(clip_line(bbox, path),mapnik::util::trim_copy(parts[2])); REQUIRE(clip_line(bbox, path) == mapnik::util::trim_copy(parts[2]));
} }
stream.close(); stream.close();
} }
@ -125,14 +115,6 @@ int main(int argc, char** argv)
std::cerr << ex.what() << "\n"; std::cerr << ex.what() << "\n";
} }
if (!::boost::detail::test_errors()) }
{
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ clipping: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
}
else
{
return ::boost::report_errors();
}
} }

View file

@ -1,7 +1,8 @@
#include "catch.hpp"
#include <mapnik/value_types.hpp> #include <mapnik/value_types.hpp>
#include <mapnik/value.hpp> #include <mapnik/value.hpp>
#include <mapnik/util/conversions.hpp> #include <mapnik/util/conversions.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
@ -11,17 +12,13 @@
#include <cstdio> #include <cstdio>
#endif #endif
int main(int argc, char** argv) TEST_CASE("conversions") {
{
SECTION("to string") {
#if defined(_MSC_VER) && _MSC_VER < 1900 #if defined(_MSC_VER) && _MSC_VER < 1900
unsigned int old = _set_output_format(_TWO_DIGIT_EXPONENT); unsigned int old = _set_output_format(_TWO_DIGIT_EXPONENT);
#endif #endif
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
using mapnik::util::to_string; using mapnik::util::to_string;
using mapnik::util::string2bool; using mapnik::util::string2bool;
@ -32,236 +29,236 @@ int main(int argc, char** argv)
// Test double // Test double
to_string(out, double(0)); to_string(out, double(0));
BOOST_TEST_EQ( out, "0" ); REQUIRE( out == "0" );
out.clear(); out.clear();
to_string(out, double(1)); to_string(out, double(1));
BOOST_TEST_EQ( out, "1" ); REQUIRE( out == "1" );
out.clear(); out.clear();
to_string(out, double(-1)); to_string(out, double(-1));
BOOST_TEST_EQ( out, "-1" ); REQUIRE( out == "-1" );
out.clear(); out.clear();
to_string(out, double(0.1)); to_string(out, double(0.1));
BOOST_TEST_EQ( out, "0.1" ); REQUIRE( out == "0.1" );
out.clear(); out.clear();
to_string(out, double(-0.1)); to_string(out, double(-0.1));
BOOST_TEST_EQ( out, "-0.1" ); REQUIRE( out == "-0.1" );
out.clear(); out.clear();
to_string(out, double(0.123)); to_string(out, double(0.123));
BOOST_TEST_EQ( out, "0.123" ); REQUIRE( out == "0.123" );
out.clear(); out.clear();
to_string(out, double(-0.123)); to_string(out, double(-0.123));
BOOST_TEST_EQ( out, "-0.123" ); REQUIRE( out == "-0.123" );
out.clear(); out.clear();
to_string(out, double(1e-06)); to_string(out, double(1e-06));
BOOST_TEST_EQ( out, "1e-06" ); REQUIRE( out == "1e-06" );
out.clear(); out.clear();
to_string(out, double(-1e-06)); to_string(out, double(-1e-06));
BOOST_TEST_EQ( out, "-1e-06" ); REQUIRE( out == "-1e-06" );
out.clear(); out.clear();
to_string(out, double(1e-05)); to_string(out, double(1e-05));
BOOST_TEST_EQ( out, "1e-05" ); REQUIRE( out == "1e-05" );
out.clear(); out.clear();
to_string(out, double(-1e-05)); to_string(out, double(-1e-05));
BOOST_TEST_EQ( out, "-1e-05" ); REQUIRE( out == "-1e-05" );
out.clear(); out.clear();
to_string(out, double(0.0001)); to_string(out, double(0.0001));
BOOST_TEST_EQ( out, "0.0001" ); REQUIRE( out == "0.0001" );
out.clear(); out.clear();
to_string(out, double(-0.0001)); to_string(out, double(-0.0001));
BOOST_TEST_EQ( out, "-0.0001" ); REQUIRE( out == "-0.0001" );
out.clear(); out.clear();
to_string(out, double(0.0001)); to_string(out, double(0.0001));
BOOST_TEST_EQ( out, "0.0001" ); REQUIRE( out == "0.0001" );
out.clear(); out.clear();
to_string(out, double(0.00001)); to_string(out, double(0.00001));
BOOST_TEST_EQ( out, "1e-05" ); REQUIRE( out == "1e-05" );
out.clear(); out.clear();
to_string(out, double(0.000001)); to_string(out, double(0.000001));
BOOST_TEST_EQ( out, "1e-06" ); REQUIRE( out == "1e-06" );
out.clear(); out.clear();
to_string(out, double(0.0000001)); to_string(out, double(0.0000001));
BOOST_TEST_EQ( out, "1e-07" ); REQUIRE( out == "1e-07" );
out.clear(); out.clear();
to_string(out, double(0.00000001)); to_string(out, double(0.00000001));
BOOST_TEST_EQ( out, "1e-08" ); REQUIRE( out == "1e-08" );
out.clear(); out.clear();
to_string(out, double(0.000000001)); to_string(out, double(0.000000001));
BOOST_TEST_EQ( out, "1e-09" ); REQUIRE( out == "1e-09" );
out.clear(); out.clear();
to_string(out, double(0.0000000001)); to_string(out, double(0.0000000001));
BOOST_TEST_EQ( out, "1e-10" ); REQUIRE( out == "1e-10" );
out.clear(); out.clear();
to_string(out, double(-1.234e+16)); to_string(out, double(-1.234e+16));
BOOST_TEST_EQ( out, "-1.234e+16" ); REQUIRE( out == "-1.234e+16" );
out.clear(); out.clear();
// critical failure when karam is used // critical failure when karam is used
// https://github.com/mapnik/mapnik/issues/1741 // https://github.com/mapnik/mapnik/issues/1741
// https://github.com/mapbox/tilemill/issues/1456 // https://github.com/mapbox/tilemill/issues/1456
to_string(out, double(8.3)); to_string(out, double(8.3));
BOOST_TEST_EQ( out, "8.3" ); REQUIRE( out == "8.3" );
out.clear(); out.clear();
// non-critical failures if karma is used // non-critical failures if karma is used
to_string(out, double(0.0001234567890123456)); to_string(out, double(0.0001234567890123456));
// TODO: https://github.com/mapnik/mapnik/issues/1676 // TODO: https://github.com/mapnik/mapnik/issues/1676
BOOST_TEST_EQ( out, "0.000123457" ); REQUIRE( out == "0.000123457" );
out.clear(); out.clear();
to_string(out, double(0.00000000001)); to_string(out, double(0.00000000001));
BOOST_TEST_EQ( out, "1e-11" ); REQUIRE( out == "1e-11" );
out.clear(); out.clear();
to_string(out, double(0.000000000001)); to_string(out, double(0.000000000001));
BOOST_TEST_EQ( out, "1e-12" ); REQUIRE( out == "1e-12" );
out.clear(); out.clear();
to_string(out, double(0.0000000000001)); to_string(out, double(0.0000000000001));
BOOST_TEST_EQ( out, "1e-13" ); REQUIRE( out == "1e-13" );
out.clear(); out.clear();
to_string(out, double(0.00000000000001)); to_string(out, double(0.00000000000001));
BOOST_TEST_EQ( out, "1e-14" ); REQUIRE( out == "1e-14" );
out.clear(); out.clear();
to_string(out, double(0.000000000000001)); to_string(out, double(0.000000000000001));
BOOST_TEST_EQ( out, "1e-15" ); REQUIRE( out == "1e-15" );
out.clear(); out.clear();
to_string(out, double(100000)); to_string(out, double(100000));
BOOST_TEST_EQ( out, "100000" ); REQUIRE( out == "100000" );
out.clear(); out.clear();
to_string(out, double(1000000)); to_string(out, double(1000000));
BOOST_TEST_EQ( out, "1e+06" ); REQUIRE( out == "1e+06" );
out.clear(); out.clear();
to_string(out, double(10000000)); to_string(out, double(10000000));
BOOST_TEST_EQ( out, "1e+07" ); REQUIRE( out == "1e+07" );
out.clear(); out.clear();
to_string(out, double(100000000)); to_string(out, double(100000000));
BOOST_TEST_EQ( out, "1e+08" ); REQUIRE( out == "1e+08" );
out.clear(); out.clear();
to_string(out, double(1000000000)); to_string(out, double(1000000000));
BOOST_TEST_EQ( out, "1e+09" ); REQUIRE( out == "1e+09" );
out.clear(); out.clear();
to_string(out, double(10000000000)); to_string(out, double(10000000000));
BOOST_TEST_EQ( out, "1e+10" ); REQUIRE( out == "1e+10" );
out.clear(); out.clear();
to_string(out, double(100000000000)); to_string(out, double(100000000000));
BOOST_TEST_EQ( out, "1e+11" ); REQUIRE( out == "1e+11" );
out.clear(); out.clear();
to_string(out, double(1000000000000)); to_string(out, double(1000000000000));
BOOST_TEST_EQ( out, "1e+12" ); REQUIRE( out == "1e+12" );
out.clear(); out.clear();
to_string(out, double(10000000000000)); to_string(out, double(10000000000000));
BOOST_TEST_EQ( out, "1e+13" ); REQUIRE( out == "1e+13" );
out.clear(); out.clear();
to_string(out, double(100000000000000)); to_string(out, double(100000000000000));
BOOST_TEST_EQ( out, "1e+14" ); REQUIRE( out == "1e+14" );
out.clear(); out.clear();
to_string(out, double(1000000000000005)); to_string(out, double(1000000000000005));
BOOST_TEST_EQ( out, "1e+15" ); REQUIRE( out == "1e+15" );
out.clear(); out.clear();
to_string(out, double(-1000000000000000)); to_string(out, double(-1000000000000000));
BOOST_TEST_EQ( out, "-1e+15" ); REQUIRE( out == "-1e+15" );
out.clear(); out.clear();
to_string(out, double(100000000000000.1)); to_string(out, double(100000000000000.1));
BOOST_TEST_EQ( out, "1e+14" ); REQUIRE( out == "1e+14" );
out.clear(); out.clear();
to_string(out, double(1.00001)); to_string(out, double(1.00001));
BOOST_TEST_EQ( out, "1.00001" ); REQUIRE( out == "1.00001" );
out.clear(); out.clear();
to_string(out, double(67.65)); to_string(out, double(67.65));
BOOST_TEST_EQ( out, "67.65" ); REQUIRE( out == "67.65" );
out.clear(); out.clear();
to_string(out, double(67.35)); to_string(out, double(67.35));
BOOST_TEST_EQ( out, "67.35" ); REQUIRE( out == "67.35" );
out.clear(); out.clear();
to_string(out, double(1234000000000000)); to_string(out, double(1234000000000000));
BOOST_TEST_EQ( out, "1.234e+15" ); REQUIRE( out == "1.234e+15" );
out.clear(); out.clear();
to_string(out, double(1e+16)); to_string(out, double(1e+16));
BOOST_TEST_EQ( out, "1e+16" ); REQUIRE( out == "1e+16" );
out.clear(); out.clear();
to_string(out, double(1.234e+16)); to_string(out, double(1.234e+16));
BOOST_TEST_EQ( out, "1.234e+16" ); REQUIRE( out == "1.234e+16" );
out.clear(); out.clear();
// int // int
to_string(out, int(2)); to_string(out, int(2));
BOOST_TEST_EQ( out, "2" ); REQUIRE( out == "2" );
out.clear(); out.clear();
to_string(out, int(0)); to_string(out, int(0));
BOOST_TEST_EQ( out, "0" ); REQUIRE( out == "0" );
out.clear(); out.clear();
to_string(out, int(-2)); to_string(out, int(-2));
BOOST_TEST_EQ( out, "-2" ); REQUIRE( out == "-2" );
out.clear(); out.clear();
to_string(out, int(2147483647)); to_string(out, int(2147483647));
BOOST_TEST_EQ( out, "2147483647" ); REQUIRE( out == "2147483647" );
out.clear(); out.clear();
to_string(out, int(-2147483648)); to_string(out, int(-2147483648));
BOOST_TEST_EQ( out, "-2147483648" ); REQUIRE( out == "-2147483648" );
out.clear(); out.clear();
// unsigned // unsigned
to_string(out, unsigned(4294967295)); to_string(out, unsigned(4294967295));
BOOST_TEST_EQ( out, "4294967295" ); REQUIRE( out == "4294967295" );
out.clear(); out.clear();
#ifdef BIGINT #ifdef BIGINT
// long long // long long
to_string(out,mapnik::value_integer(-0)); to_string(out,mapnik::value_integer(-0));
BOOST_TEST_EQ( out, "0" ); REQUIRE( out == "0" );
out.clear(); out.clear();
to_string(out,mapnik::value_integer(-2)); to_string(out,mapnik::value_integer(-2));
BOOST_TEST_EQ( out, "-2" ); REQUIRE( out == "-2" );
out.clear(); out.clear();
to_string(out,mapnik::value_integer(9223372036854775807)); to_string(out,mapnik::value_integer(9223372036854775807));
BOOST_TEST_EQ( out, "9223372036854775807" ); REQUIRE( out == "9223372036854775807" );
out.clear(); out.clear();
#else #else
#ifdef _MSC_VER #ifdef _MSC_VER
@ -272,38 +269,32 @@ int main(int argc, char** argv)
#endif #endif
// bool // bool
to_string(out, true); to_string(out, true);
BOOST_TEST_EQ( out, "true" ); REQUIRE( out == "true" );
out.clear(); out.clear();
to_string(out, false); to_string(out, false);
BOOST_TEST_EQ( out, "false" ); REQUIRE( out == "false" );
out.clear(); out.clear();
bool val = false; bool val = false;
BOOST_TEST( !string2bool("this is invalid",val) ); REQUIRE( !string2bool("this is invalid",val) );
BOOST_TEST_EQ( val, false ); REQUIRE( val == false );
BOOST_TEST( string2bool("true",val) ); REQUIRE( string2bool("true",val) );
BOOST_TEST_EQ( val, true ); REQUIRE( val == true );
// mapnik::value hashability // mapnik::value hashability
using values_container = boost::unordered_map<mapnik::value, unsigned>; using values_container = boost::unordered_map<mapnik::value, unsigned>;
values_container vc; values_container vc;
mapnik::value val2(1); mapnik::value val2(1);
vc[val2] = 1; vc[val2] = 1;
BOOST_TEST_EQ( (int)vc[1], (int)1 ); REQUIRE( vc[1] == static_cast<int>(1) );
} }
catch (std::exception const & ex) catch (std::exception const & ex)
{ {
std::clog << ex.what() << "\n"; std::clog << ex.what() << "\n";
BOOST_TEST(false); REQUIRE(false);
}
if (!::boost::detail::test_errors()) {
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ type conversions: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
} }
} }
}

View file

@ -1,5 +1,4 @@
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
#include <mapnik/layer.hpp> #include <mapnik/layer.hpp>
#include <mapnik/map.hpp> #include <mapnik/map.hpp>
#include <mapnik/color.hpp> #include <mapnik/color.hpp>
@ -9,19 +8,20 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
int main(int argc, char** argv) #include "catch.hpp"
{
std::vector<std::string> args;
for (int i=1;i<argc;++i) TEST_CASE("copy") {
{
args.push_back(argv[i]); SECTION("layers") {
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
try try
{ {
mapnik::Map m0(100,100); mapnik::Map m0(100,100);
mapnik::Map m2(200,100); mapnik::Map m2(200,100);
// FIXME: not compiling when ported to catch.hpp
// due to some conflict: 'include/mapnik/value.hpp:832:11: error: no matching constructor for initialization of 'value_base''
/*
// mapnik::datasource // mapnik::datasource
mapnik::datasource_cache::instance().register_datasources("plugins/input/shape.input"); mapnik::datasource_cache::instance().register_datasources("plugins/input/shape.input");
@ -32,29 +32,29 @@ int main(int argc, char** argv)
auto ds0 = mapnik::datasource_cache::instance().create(p); auto ds0 = mapnik::datasource_cache::instance().create(p);
auto ds1 = ds0; // shared ptr copy auto ds1 = ds0; // shared ptr copy
BOOST_TEST(ds1 == ds0); REQUIRE(ds1 == ds0);
BOOST_TEST(*ds1 == *ds0); //REQUIRE(*ds1 == *ds0);
ds1 = mapnik::datasource_cache::instance().create(p); // new with the same parameters ds1 = mapnik::datasource_cache::instance().create(p); // new with the same parameters
BOOST_TEST(ds1 != ds0); REQUIRE(ds1 != ds0);
BOOST_TEST(*ds1 == *ds0); REQUIRE(*ds1 == *ds0);
auto ds2 = std::move(ds1); auto ds2 = std::move(ds1);
BOOST_TEST(ds2 != ds0); REQUIRE(ds2 != ds0);
BOOST_TEST(*ds2 == *ds0); REQUIRE(*ds2 == *ds0);
// mapnik::layer // mapnik::layer
mapnik::layer l0("test-layer"); mapnik::layer l0("test-layer");
l0.set_datasource(ds0); l0.set_datasource(ds0);
mapnik::layer l1 = l0; // copy assignment mapnik::layer l1 = l0; // copy assignment
BOOST_TEST(l1 == l0); REQUIRE(l1 == l0);
mapnik::layer l2(l0); // copy ctor mapnik::layer l2(l0); // copy ctor
BOOST_TEST(l2 == l0); REQUIRE(l2 == l0);
mapnik::layer l3(mapnik::layer("test-layer")); // move ctor mapnik::layer l3(mapnik::layer("test-layer")); // move ctor
l3.set_datasource(ds2); l3.set_datasource(ds2);
BOOST_TEST(l3 == l0); REQUIRE(l3 == l0);
mapnik::layer l4 = std::move(l3); mapnik::layer l4 = std::move(l3);
BOOST_TEST(l4 == l0); // move assignment REQUIRE(l4 == l0); // move assignment
m0.add_layer(l4); m0.add_layer(l4);
m0.set_background(mapnik::color("skyblue")); m0.set_background(mapnik::color("skyblue"));
@ -62,31 +62,22 @@ int main(int argc, char** argv)
auto m1 = m0; //copy auto m1 = m0; //copy
BOOST_TEST(m0 == m1); REQUIRE(m0 == m1);
BOOST_TEST(m0 != m2); REQUIRE(m0 != m2);
m2 = m1; // copy m2 = m1; // copy
BOOST_TEST(m2 == m1); REQUIRE(m2 == m1);
m2 = std::move(m1); m2 = std::move(m1);
BOOST_TEST(m2 == m0); REQUIRE(m2 == m0);
BOOST_TEST(m1 != m0); REQUIRE(m1 != m0);
BOOST_TEST(m0 == m2); REQUIRE(m0 == m2);
*/
} }
catch (std::exception const & ex) catch (std::exception const & ex)
{ {
std::clog << ex.what() << "\n"; std::clog << ex.what() << "\n";
BOOST_TEST(false); REQUIRE(false);
}
if (!::boost::detail::test_errors())
{
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ copy/move/assignment tests: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
}
else
{
return ::boost::report_errors();
} }
} }
}

View file

@ -1,4 +1,5 @@
#include <boost/detail/lightweight_test.hpp> #include "catch.hpp"
#include <iostream> #include <iostream>
#include <mapnik/projection.hpp> #include <mapnik/projection.hpp>
#include <mapnik/unicode.hpp> #include <mapnik/unicode.hpp>
@ -19,45 +20,35 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include "utils.hpp" TEST_CASE("exceptions") {
int main(int argc, char** argv) SECTION("handling") {
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
BOOST_TEST(set_working_dir(args));
try { try {
mapnik::projection srs("foo"); mapnik::projection srs("foo");
// to avoid unused variable warning // to avoid unused variable warning
srs.params(); srs.params();
BOOST_TEST(false); REQUIRE(false);
} catch (...) { } catch (...) {
BOOST_TEST(true); REQUIRE(true);
} }
// https://github.com/mapnik/mapnik/issues/2170 // https://github.com/mapnik/mapnik/issues/2170
try { try {
BOOST_TEST(set_working_dir(args));
mapnik::projection srs("+proj=longlat foo",true); mapnik::projection srs("+proj=longlat foo",true);
BOOST_TEST(srs.is_geographic()); REQUIRE(srs.is_geographic());
BOOST_TEST(true); REQUIRE(true);
srs.init_proj4(); srs.init_proj4();
// oddly init_proj4 does not throw with old proj/ubuntu precise // oddly init_proj4 does not throw with old proj/ubuntu precise
//BOOST_TEST(false); //REQUIRE(false);
} catch (...) { } catch (...) {
BOOST_TEST(true); REQUIRE(true);
} }
try { try {
mapnik::transcoder tr("bogus encoding"); mapnik::transcoder tr("bogus encoding");
BOOST_TEST(false); REQUIRE(false);
} catch (...) { } catch (...) {
BOOST_TEST(true); REQUIRE(true);
} }
mapnik::Map map(256,256); mapnik::Map map(256,256);
@ -85,12 +76,12 @@ int main(int argc, char** argv)
mapnik::image_rgba8 im(m.width(),m.height()); mapnik::image_rgba8 im(m.width(),m.height());
mapnik::agg_renderer<mapnik::image_rgba8> ren(m,im); mapnik::agg_renderer<mapnik::image_rgba8> ren(m,im);
//std::clog << mapnik::save_map_to_string(m) << "\n"; //std::clog << mapnik::save_map_to_string(m) << "\n";
BOOST_TEST(true); REQUIRE(true);
// should throw here with "CSV Plugin: no attribute 'foo'. Valid attributes are: x,y." // should throw here with "CSV Plugin: no attribute 'foo'. Valid attributes are: x,y."
ren.apply(); ren.apply();
BOOST_TEST(false); REQUIRE(false);
} catch (...) { } catch (...) {
BOOST_TEST(true); REQUIRE(true);
} }
} }
@ -102,17 +93,11 @@ int main(int argc, char** argv)
p2["type"]="shape"; p2["type"]="shape";
p2["file"]="foo"; p2["file"]="foo";
mapnik::datasource_cache::instance().create(p2); mapnik::datasource_cache::instance().create(p2);
BOOST_TEST(false); REQUIRE(false);
} catch (...) { } catch (...) {
BOOST_TEST(true); REQUIRE(true);
} }
} }
if (!::boost::detail::test_errors()) { }
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ exceptions: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
}
} }

View file

@ -0,0 +1,192 @@
#include "catch.hpp"
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/util/fs.hpp>
#include <mapnik/map.hpp>
#include <mapnik/load_map.hpp>
#include <mapnik/debug.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
TEST_CASE("font") {
SECTION("registration") {
try
{
mapnik::logger logger;
mapnik::logger::severity_type original_severity = logger.get_severity();
// grab references to global statics of registered/cached fonts
auto const& global_mapping = mapnik::freetype_engine::get_mapping();
auto const& global_cache = mapnik::freetype_engine::get_cache();
// mapnik.Map object has parallel structure for localized fonts
mapnik::Map m(1,1);
auto const& local_mapping = m.get_font_file_mapping();
auto const& local_cache = m.get_font_memory_cache();
// should be empty to start
REQUIRE( global_mapping.empty() );
REQUIRE( global_cache.empty() );
REQUIRE( local_mapping.empty() );
REQUIRE( local_cache.empty() );
std::string fontdir("fonts/");
REQUIRE( mapnik::util::exists( fontdir ) );
REQUIRE( mapnik::util::is_directory( fontdir ) );
// test map cached fonts
REQUIRE( m.register_fonts(fontdir , false ) );
REQUIRE( m.get_font_memory_cache().size() == 0 );
REQUIRE( m.get_font_file_mapping().size() == 1 );
REQUIRE( m.load_fonts() );
REQUIRE( m.get_font_memory_cache().size() == 1 );
REQUIRE( m.register_fonts(fontdir , true ) );
REQUIRE( m.get_font_file_mapping().size() == 22 );
REQUIRE( m.load_fonts() );
REQUIRE( m.get_font_memory_cache().size() == 22 );
// copy discards memory cache but not file mapping
mapnik::Map m2(m);
REQUIRE( m2.get_font_memory_cache().size() == 0 );
REQUIRE( m2.get_font_file_mapping().size() == 22 );
REQUIRE( m2.load_fonts() );
REQUIRE( m2.get_font_memory_cache().size() == 22 );
// test font-directory from XML
mapnik::Map m3(1,1);
mapnik::load_map_string(m3,"<Map font-directory=\"fonts/\"></Map>");
REQUIRE( m3.get_font_memory_cache().size() == 0 );
REQUIRE( m3.load_fonts() );
REQUIRE( m3.get_font_memory_cache().size() == 1 );
std::vector<std::string> face_names;
std::string foo("foo");
// fake directories
REQUIRE( !mapnik::freetype_engine::register_fonts(foo , true ) );
face_names = mapnik::freetype_engine::face_names();
REQUIRE( face_names.size() == 0 );
REQUIRE( !mapnik::freetype_engine::register_fonts(foo) );
face_names = mapnik::freetype_engine::face_names();
REQUIRE( face_names.size() == 0 );
// directories without fonts
// silence warnings here by altering the logging severity
logger.set_severity(mapnik::logger::none);
std::string src("src");
// an empty directory will not return true
// we need to register at least one font and not fail on any
// to return true
REQUIRE( mapnik::freetype_engine::register_font(src) == false );
REQUIRE( mapnik::freetype_engine::register_fonts(src, true) == false );
REQUIRE( mapnik::freetype_engine::face_names().size() == 0 );
// bogus, emtpy file that looks like font
REQUIRE( mapnik::freetype_engine::register_font("tests/data/fonts/fake.ttf") == false );
REQUIRE( mapnik::freetype_engine::register_fonts("tests/data/fonts/fake.ttf") == false );
REQUIRE( mapnik::freetype_engine::face_names().size() == 0 );
REQUIRE( mapnik::freetype_engine::register_font("tests/data/fonts/intentionally-broken.ttf") == false );
REQUIRE( mapnik::freetype_engine::register_fonts("tests/data/fonts/intentionally-broken.ttf") == false );
REQUIRE( mapnik::freetype_engine::face_names().size() == 0 );
// now restore the original severity
logger.set_severity(original_severity);
// register unifont, since we know it sits in the root fonts/ dir
REQUIRE( mapnik::freetype_engine::register_fonts(fontdir) );
face_names = mapnik::freetype_engine::face_names();
REQUIRE( face_names.size() > 0 );
REQUIRE( face_names.size() == 1 );
// re-register unifont, should not have any affect
REQUIRE( mapnik::freetype_engine::register_fonts(fontdir, false) );
face_names = mapnik::freetype_engine::face_names();
REQUIRE( face_names.size() == 1 );
// single dejavu font in separate location
std::string dejavu_bold_oblique("tests/data/fonts/DejaVuSansMono-BoldOblique.ttf");
REQUIRE( mapnik::freetype_engine::register_font(dejavu_bold_oblique) );
face_names = mapnik::freetype_engine::face_names();
REQUIRE( face_names.size() == 2 );
// now, inspect font mapping and confirm the correct 'DejaVu Sans Mono Bold Oblique' is registered
using font_file_mapping = std::map<std::string, std::pair<int,std::string> >;
font_file_mapping const& name2file = mapnik::freetype_engine::get_mapping();
bool found_dejavu = false;
for (auto const& item : name2file)
{
if (item.first == "DejaVu Sans Mono Bold Oblique")
{
found_dejavu = true;
REQUIRE( item.second.first == 0 );
REQUIRE( item.second.second == dejavu_bold_oblique );
}
}
REQUIRE( found_dejavu );
// recurse to find all dejavu fonts
REQUIRE( mapnik::freetype_engine::register_fonts(fontdir, true) );
face_names = mapnik::freetype_engine::face_names();
REQUIRE( face_names.size() == 22 );
// we should have re-registered 'DejaVu Sans Mono Bold Oblique' again,
// but now at a new path
bool found_dejavu2 = false;
for (auto const& item : name2file)
{
if (item.first == "DejaVu Sans Mono Bold Oblique")
{
found_dejavu2 = true;
REQUIRE( item.second.first == 0 );
// path should be different
REQUIRE( item.second.second != dejavu_bold_oblique );
}
}
REQUIRE( found_dejavu2 );
// now that global registry is populated
// now test that a map only loads new fonts
mapnik::Map m4(1,1);
REQUIRE( m4.register_fonts(fontdir , true ) );
REQUIRE( m4.get_font_memory_cache().size() == 0 );
REQUIRE( m4.get_font_file_mapping().size() == 22 );
REQUIRE( !m4.load_fonts() );
REQUIRE( m4.get_font_memory_cache().size() == 0 );
REQUIRE( m4.register_fonts(dejavu_bold_oblique, false) );
REQUIRE( m4.load_fonts() );
REQUIRE( m4.get_font_memory_cache().size() == 1 );
// check that we can correctly read a .ttc containing
// multiple valid faces
// https://github.com/mapnik/mapnik/issues/2274
REQUIRE( mapnik::freetype_engine::register_font("tests/data/fonts/NotoSans-Regular.ttc") );
face_names = mapnik::freetype_engine::face_names();
REQUIRE( face_names.size() == 24 );
// now blindly register as many system fonts as possible
// the goal here to make sure we don't crash
// linux
mapnik::freetype_engine::register_fonts("/usr/share/fonts/", true);
mapnik::freetype_engine::register_fonts("/usr/local/share/fonts/", true);
// osx
mapnik::freetype_engine::register_fonts("/Library/Fonts/", true);
mapnik::freetype_engine::register_fonts("/System/Library/Fonts/", true);
// windows
mapnik::freetype_engine::register_fonts("C:\\Windows\\Fonts", true);
face_names = mapnik::freetype_engine::face_names();
REQUIRE( face_names.size() > 22 );
}
catch (std::exception const & ex)
{
std::clog << ex.what() << "\n";
REQUIRE(false);
}
}
}

View file

@ -1,4 +1,5 @@
#include <boost/detail/lightweight_test.hpp> #include "catch.hpp"
#include <iostream> #include <iostream>
#include <mapnik/memory_datasource.hpp> #include <mapnik/memory_datasource.hpp>
#include <mapnik/datasource_cache.hpp> #include <mapnik/datasource_cache.hpp>
@ -26,19 +27,11 @@
// icu - for memory cleanup (to make valgrind happy) // icu - for memory cleanup (to make valgrind happy)
#include "unicode/uclean.h" #include "unicode/uclean.h"
#include "utils.hpp" TEST_CASE("fontset") {
int main(int argc, char** argv) SECTION("error") {
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
try { try {
BOOST_TEST(set_working_dir(args));
// create a renderable map with a fontset and a text symbolizer // create a renderable map with a fontset and a text symbolizer
// and do not register any fonts, to ensure the error thrown is reasonable // and do not register any fonts, to ensure the error thrown is reasonable
@ -85,14 +78,8 @@ int main(int argc, char** argv)
mapnik::agg_renderer<mapnik::image_rgba8> ren(m,buf); mapnik::agg_renderer<mapnik::image_rgba8> ren(m,buf);
ren.apply(); ren.apply();
} catch (std::exception const& ex) { } catch (std::exception const& ex) {
BOOST_TEST_EQ(std::string(ex.what()),std::string("Unable to find specified font face 'DejaVu Sans Book' in font set: 'fontset'")); REQUIRE(std::string(ex.what()) == std::string("Unable to find specified font face 'DejaVu Sans Book' in font set: 'fontset'"));
} }
u_cleanup(); u_cleanup();
if (!::boost::detail::test_errors()) { }
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ fontset runtime: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
}
} }

View file

@ -1,8 +1,8 @@
#include <boost/detail/lightweight_test.hpp> #include "catch.hpp"
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include "utils.hpp"
#include <mapnik/layer.hpp> #include <mapnik/layer.hpp>
#include <mapnik/feature_type_style.hpp> #include <mapnik/feature_type_style.hpp>
@ -133,16 +133,9 @@ boost::optional<std::string> polygon_bbox_clipping(mapnik::box2d<double> bbox,
#endif #endif
int main(int argc, char** argv) TEST_CASE("geometry converters") {
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
BOOST_TEST(set_working_dir(args)); SECTION("TODO") {
try try
{ {
@ -151,60 +144,49 @@ int main(int argc, char** argv)
{ {
std::string wkt_in("LineString(0 0,200 200)"); std::string wkt_in("LineString(0 0,200 200)");
boost::optional<std::string> result = linestring_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in); boost::optional<std::string> result = linestring_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
BOOST_TEST(result); REQUIRE(result);
BOOST_TEST_EQ(*result,std::string("LineString(50 50,150 150)")); REQUIRE(*result == std::string("LineString(50 50,150 150)"));
} }
// Polygon/bbox clipping // Polygon/bbox clipping
{ {
std::string wkt_in("Polygon((50 50,150 50,150 150,50 150,50 50))"); std::string wkt_in("Polygon((50 50,150 50,150 150,50 150,50 50))");
boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in); boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
BOOST_TEST(result); REQUIRE(result);
// TODO - the extra 50 50 is not ideal, but we enforce this result for now to prevent // TODO - the extra 50 50 is not ideal, but we enforce this result for now to prevent
// regressions and because we don't have actionable solution to drop extra 50 50 // regressions and because we don't have actionable solution to drop extra 50 50
BOOST_TEST_EQ(*result,std::string("Polygon((50 50,150 50,150 150,50 150,50 50,50 50))")); REQUIRE(*result == std::string("Polygon((50 50,150 50,150 150,50 150,50 50,50 50))"));
// below is ideal, but not current result // below is ideal, but not current result
//BOOST_TEST_EQ(*result,std::string("Polygon((50 50,150 50,150 150,50 150,50 50))")); //REQUIRE(*result == std::string("Polygon((50 50,150 50,150 150,50 150,50 50))"));
} }
{ {
std::string wkt_in("Polygon((60 60,140 60,140 160,60 140,60 60))"); std::string wkt_in("Polygon((60 60,140 60,140 160,60 140,60 60))");
boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in); boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
BOOST_TEST(result); REQUIRE(result);
BOOST_TEST_EQ(*result,std::string("Polygon((60 60,140 60,140 150,100 150,60 140,60 60,60 60))")); REQUIRE(*result == std::string("Polygon((60 60,140 60,140 150,100 150,60 140,60 60,60 60))"));
//BOOST_TEST_EQ(*result,std::string("Polygon((60 60,140 60,140 160,60 140,60 60))")); //REQUIRE(*result == std::string("Polygon((60 60,140 60,140 160,60 140,60 60))"));
} }
{ {
std::string wkt_in("Polygon((0 0,10 0,10 10,0 10,0 0))"); std::string wkt_in("Polygon((0 0,10 0,10 10,0 10,0 0))");
boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in); boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
BOOST_TEST(result); REQUIRE(result);
// TODO - this is completely wrong: should not have )) and ideally should be EMPTY // TODO - this is completely wrong: should not have )) and ideally should be EMPTY
BOOST_TEST_EQ(*result, std::string("Polygon())")); REQUIRE(*result == std::string("Polygon())"));
} }
{ {
std::string wkt_in("Polygon((0 0,100 200,200 0,0 0 ))"); std::string wkt_in("Polygon((0 0,100 200,200 0,0 0 ))");
boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in); boost::optional<std::string> result = polygon_bbox_clipping(mapnik::box2d<double>(50,50,150,150),wkt_in);
BOOST_TEST(result); REQUIRE(result);
BOOST_TEST_EQ(*result, std::string("Polygon((50 50,50 100,75 150,125 150,150 100,150 50))")); REQUIRE(*result == std::string("Polygon((50 50,50 100,75 150,125 150,150 100,150 50))"));
//BOOST_TEST_EQ(*result,std::string("Polygon((50 50,50 100,75 150,125 150,150 100,150 50,50 50))")); //REQUIRE(*result == std::string("Polygon((50 50,50 100,75 150,125 150,150 100,150 50,50 50))"));
} }
#endif #endif
} }
catch (std::exception const & ex) catch (std::exception const & ex)
{ {
std::clog << ex.what() << "\n"; std::clog << ex.what() << "\n";
BOOST_TEST(false); REQUIRE(false);
}
if (!::boost::detail::test_errors())
{
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ geometry conversions: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
}
else
{
return ::boost::report_errors();
} }
} }
}

View file

@ -1,4 +1,5 @@
#include <boost/detail/lightweight_test.hpp> #include "catch.hpp"
#include <iostream> #include <iostream>
#include <mapnik/image.hpp> #include <mapnik/image.hpp>
#include <mapnik/image_reader.hpp> #include <mapnik/image_reader.hpp>
@ -11,46 +12,38 @@
#include <mapnik/cairo/cairo_image_util.hpp> #include <mapnik/cairo/cairo_image_util.hpp>
#endif #endif
#include "utils.hpp" TEST_CASE("image io") {
int main(int argc, char** argv) SECTION("readers") {
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
std::string should_throw; std::string should_throw;
boost::optional<std::string> type; boost::optional<std::string> type;
try try
{ {
BOOST_TEST(set_working_dir(args));
#if defined(HAVE_JPEG) #if defined(HAVE_JPEG)
should_throw = "./tests/cpp_tests/data/blank.jpg"; should_throw = "./tests/cpp_tests/data/blank.jpg";
BOOST_TEST( mapnik::util::exists( should_throw ) ); REQUIRE( mapnik::util::exists( should_throw ) );
type = mapnik::type_from_filename(should_throw); type = mapnik::type_from_filename(should_throw);
BOOST_TEST( type ); REQUIRE( type );
try try
{ {
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type)); std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
BOOST_TEST( false ); REQUIRE( false );
} }
catch (std::exception const&) catch (std::exception const&)
{ {
BOOST_TEST( true ); REQUIRE( true );
} }
#endif #endif
try try
{ {
mapnik::image_rgba8 im(-10,-10); // should throw rather than overflow mapnik::image_rgba8 im(-10,-10); // should throw rather than overflow
BOOST_TEST( im.width() < 10 ); // should not get here, but if we did this test should fail REQUIRE( im.width() < 10 ); // should not get here, but if we did this test should fail
} }
catch (std::exception const& ex) catch (std::exception const& ex)
{ {
BOOST_TEST( true ); // should hit bad alloc here REQUIRE( true ); // should hit bad alloc here
} }
#if defined(HAVE_CAIRO) #if defined(HAVE_CAIRO)
@ -59,85 +52,79 @@ int main(int argc, char** argv)
mapnik::cairo_surface_closer()); mapnik::cairo_surface_closer());
mapnik::image_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface)); mapnik::image_rgba8 im_data(cairo_image_surface_get_width(&*image_surface), cairo_image_surface_get_height(&*image_surface));
im_data.set(1); im_data.set(1);
BOOST_TEST( (unsigned)im_data(0,0) == unsigned(1) ); REQUIRE( (unsigned)im_data(0,0) == unsigned(1) );
// Should set back to fully transparent // Should set back to fully transparent
mapnik::cairo_image_to_rgba8(im_data, image_surface); mapnik::cairo_image_to_rgba8(im_data, image_surface);
BOOST_TEST( (unsigned)im_data(0,0) == unsigned(0) ); REQUIRE( (unsigned)im_data(0,0) == unsigned(0) );
#endif #endif
#if defined(HAVE_PNG) #if defined(HAVE_PNG)
should_throw = "./tests/cpp_tests/data/blank.png"; should_throw = "./tests/cpp_tests/data/blank.png";
BOOST_TEST( mapnik::util::exists( should_throw ) ); REQUIRE( mapnik::util::exists( should_throw ) );
type = mapnik::type_from_filename(should_throw); type = mapnik::type_from_filename(should_throw);
BOOST_TEST( type ); REQUIRE( type );
try try
{ {
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type)); std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
BOOST_TEST( false ); REQUIRE( false );
} }
catch (std::exception const&) catch (std::exception const&)
{ {
BOOST_TEST( true ); REQUIRE( true );
} }
should_throw = "./tests/data/images/xcode-CgBI.png"; should_throw = "./tests/data/images/xcode-CgBI.png";
BOOST_TEST( mapnik::util::exists( should_throw ) ); REQUIRE( mapnik::util::exists( should_throw ) );
type = mapnik::type_from_filename(should_throw); type = mapnik::type_from_filename(should_throw);
BOOST_TEST( type ); REQUIRE( type );
try try
{ {
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type)); std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
BOOST_TEST( false ); REQUIRE( false );
} }
catch (std::exception const&) catch (std::exception const&)
{ {
BOOST_TEST( true ); REQUIRE( true );
} }
#endif #endif
#if defined(HAVE_TIFF) #if defined(HAVE_TIFF)
should_throw = "./tests/cpp_tests/data/blank.tiff"; should_throw = "./tests/cpp_tests/data/blank.tiff";
BOOST_TEST( mapnik::util::exists( should_throw ) ); REQUIRE( mapnik::util::exists( should_throw ) );
type = mapnik::type_from_filename(should_throw); type = mapnik::type_from_filename(should_throw);
BOOST_TEST( type ); REQUIRE( type );
try try
{ {
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type)); std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
BOOST_TEST( false ); REQUIRE( false );
} }
catch (std::exception const&) catch (std::exception const&)
{ {
BOOST_TEST( true ); REQUIRE( true );
} }
#endif #endif
#if defined(HAVE_WEBP) #if defined(HAVE_WEBP)
should_throw = "./tests/cpp_tests/data/blank.webp"; should_throw = "./tests/cpp_tests/data/blank.webp";
BOOST_TEST( mapnik::util::exists( should_throw ) ); REQUIRE( mapnik::util::exists( should_throw ) );
type = mapnik::type_from_filename(should_throw); type = mapnik::type_from_filename(should_throw);
BOOST_TEST( type ); REQUIRE( type );
try try
{ {
std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type)); std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(should_throw,*type));
BOOST_TEST( false ); REQUIRE( false );
} }
catch (std::exception const&) catch (std::exception const&)
{ {
BOOST_TEST( true ); REQUIRE( true );
} }
#endif #endif
} }
catch (std::exception const & ex) catch (std::exception const & ex)
{ {
std::clog << ex.what() << "\n"; std::clog << ex.what() << "\n";
BOOST_TEST(false); REQUIRE(false);
} }
if (!::boost::detail::test_errors()) { }
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ image i/o: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
}
} }

View file

@ -1,7 +1,6 @@
#include "catch.hpp"
#include <iostream> #include <iostream>
#include <boost/detail/lightweight_test.hpp>
#include <mapnik/map.hpp> #include <mapnik/map.hpp>
#include <mapnik/layer.hpp> #include <mapnik/layer.hpp>
#include <mapnik/rule.hpp> #include <mapnik/rule.hpp>
@ -10,14 +9,9 @@
#include <mapnik/agg_renderer.hpp> #include <mapnik/agg_renderer.hpp>
#include <mapnik/expression.hpp> #include <mapnik/expression.hpp>
int main(int argc, char** argv) TEST_CASE("image") {
{
std::vector<std::string> args; SECTION("painting") {
for (int i = 1; i < argc; ++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q") != args.end();
using namespace mapnik; using namespace mapnik;
@ -63,22 +57,13 @@ int main(int argc, char** argv)
agg_renderer<image_rgba8> ren(m, image); agg_renderer<image_rgba8> ren(m, image);
ren.apply(); ren.apply();
BOOST_TEST_EQ(image.painted(), true); REQUIRE(image.painted() == true);
} }
catch (std::exception const & ex) catch (std::exception const & ex)
{ {
std::clog << ex.what() << std::endl; std::clog << ex.what() << std::endl;
BOOST_TEST(false); REQUIRE(false);
} }
if (::boost::detail::test_errors()) }
{
return ::boost::report_errors();
}
else
{
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ image painted: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
}
} }

View file

@ -1,4 +1,5 @@
#include <boost/detail/lightweight_test.hpp> #include "catch.hpp"
#include <iostream> #include <iostream>
#include <mapnik/geometry.hpp> #include <mapnik/geometry.hpp>
#include <mapnik/geometry_adapters.hpp> #include <mapnik/geometry_adapters.hpp>
@ -6,14 +7,9 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
int main(int argc, char** argv) TEST_CASE("labeling") {
{
std::vector<std::string> args; SECTION("algorithms") {
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
try try
{ {
@ -22,9 +18,9 @@ int main(int argc, char** argv)
{ {
// single point // single point
mapnik::geometry::point<double> pt(10,10); mapnik::geometry::point<double> pt(10,10);
BOOST_TEST( mapnik::geometry::centroid(pt, centroid)); REQUIRE( mapnik::geometry::centroid(pt, centroid));
BOOST_TEST( pt.x == centroid.x); REQUIRE( pt.x == centroid.x);
BOOST_TEST( pt.y == centroid.y); REQUIRE( pt.y == centroid.y);
} }
// linestring with three consecutive verticies // linestring with three consecutive verticies
@ -33,9 +29,9 @@ int main(int argc, char** argv)
line.add_coord(0, 0); line.add_coord(0, 0);
line.add_coord(25, 25); line.add_coord(25, 25);
line.add_coord(50, 50); line.add_coord(50, 50);
BOOST_TEST(mapnik::geometry::centroid(line, centroid)); REQUIRE(mapnik::geometry::centroid(line, centroid));
BOOST_TEST( centroid.x == 25 ); REQUIRE( centroid.x == 25 );
BOOST_TEST( centroid.y == 25 ); REQUIRE( centroid.y == 25 );
} }
// TODO - centroid and interior should be equal but they appear not to be (check largest) // TODO - centroid and interior should be equal but they appear not to be (check largest)
// MULTIPOLYGON(((-52 40,-60 32,-68 40,-60 48,-52 40)),((-60 50,-80 30,-100 49.9999999999999,-80.0000000000001 70,-60 50)),((-52 60,-60 52,-68 60,-60 68,-52 60))) // MULTIPOLYGON(((-52 40,-60 32,-68 40,-60 48,-52 40)),((-60 50,-80 30,-100 49.9999999999999,-80.0000000000001 70,-60 50)),((-52 60,-60 52,-68 60,-60 68,-52 60)))
@ -45,32 +41,25 @@ int main(int argc, char** argv)
mapnik::geometry_type pt_hit(mapnik::geometry::geometry_types::Point); mapnik::geometry_type pt_hit(mapnik::geometry::geometry_types::Point);
pt_hit.move_to(10,10); pt_hit.move_to(10,10);
mapnik::vertex_adapter va(pt_hit); mapnik::vertex_adapter va(pt_hit);
BOOST_TEST( mapnik::label::hit_test(va, 10, 10, 0.1) ); REQUIRE( mapnik::label::hit_test(va, 10, 10, 0.1) );
BOOST_TEST( !mapnik::label::hit_test(va, 9, 9, 0) ); REQUIRE( !mapnik::label::hit_test(va, 9, 9, 0) );
BOOST_TEST( mapnik::label::hit_test(va, 9, 9, 1.5) ); REQUIRE( mapnik::label::hit_test(va, 9, 9, 1.5) );
} }
{ {
mapnik::geometry_type line_hit(mapnik::geometry::geometry_types::LineString); mapnik::geometry_type line_hit(mapnik::geometry::geometry_types::LineString);
line_hit.move_to(0,0); line_hit.move_to(0,0);
line_hit.line_to(50,50); line_hit.line_to(50,50);
mapnik::vertex_adapter va(line_hit); mapnik::vertex_adapter va(line_hit);
BOOST_TEST( mapnik::label::hit_test(va, 0, 0, 0.001) ); REQUIRE( mapnik::label::hit_test(va, 0, 0, 0.001) );
BOOST_TEST( !mapnik::label::hit_test(va, 1, 1, 0) ); REQUIRE( !mapnik::label::hit_test(va, 1, 1, 0) );
BOOST_TEST( mapnik::label::hit_test(va, 1, 1, 1.001) ); REQUIRE( mapnik::label::hit_test(va, 1, 1, 1.001) );
} }
#endif #endif
} }
catch (std::exception const & ex) catch (std::exception const & ex)
{ {
std::clog << ex.what() << "\n"; std::clog << ex.what() << "\n";
BOOST_TEST(false); REQUIRE(false);
}
if (!::boost::detail::test_errors()) {
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ label algorithms: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
} }
} }
}

View file

@ -1,10 +1,9 @@
#include "catch.hpp"
// mapnik // mapnik
#include <mapnik/coord.hpp> #include <mapnik/coord.hpp>
#include <mapnik/vertex_cache.hpp> #include <mapnik/vertex_cache.hpp>
// boost
#include <boost/detail/lightweight_test.hpp>
// stl // stl
#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
@ -13,9 +12,6 @@
#include <tuple> #include <tuple>
#include <algorithm> #include <algorithm>
// test
#include "utils.hpp"
struct fake_path struct fake_path
{ {
using coord_type = std::tuple<double, double, unsigned>; using coord_type = std::tuple<double, double, unsigned>;
@ -68,27 +64,6 @@ double dist(mapnik::pixel_position const &a,
return std::sqrt(d.x*d.x + d.y*d.y); return std::sqrt(d.x*d.x + d.y*d.y);
} }
namespace boost { namespace detail {
template<class T, class U>
inline void test_leq_impl(char const * expr1, char const * expr2,
char const * file, int line, char const * function,
T const & t, U const & u)
{
if( t > u )
{
BOOST_LIGHTWEIGHT_TEST_OSTREAM
<< file << "(" << line << "): test '" << expr1 << " == " << expr2
<< "' failed in function '" << function << "': "
<< "'" << t << "' > '" << u << "'" << std::endl;
++test_errors();
}
}
} }
#define BOOST_TEST_LEQ(expr1,expr2) ( ::boost::detail::test_leq_impl(#expr1, #expr2, __FILE__, __LINE__, BOOST_CURRENT_FUNCTION, expr1, expr2) )
void test_simple_segment(double const &offset) void test_simple_segment(double const &offset)
{ {
const double dx = 0.01; const double dx = 0.01;
@ -101,7 +76,7 @@ void test_simple_segment(double const &offset)
while (vc.move(dx)) { while (vc.move(dx)) {
double pos = vc.linear_position(); double pos = vc.linear_position();
double off_pos = off_vc.position_closest_to(vc.current_position()); double off_pos = off_vc.position_closest_to(vc.current_position());
BOOST_TEST_LEQ(std::abs(pos - off_pos), 1.0e-6); REQUIRE(std::abs(pos - off_pos) < 1.0e-6);
} }
} }
@ -117,7 +92,7 @@ void test_straight_line(double const &offset) {
while (vc.move(dx)) { while (vc.move(dx)) {
double pos = vc.linear_position(); double pos = vc.linear_position();
double off_pos = off_vc.position_closest_to(vc.current_position()); double off_pos = off_vc.position_closest_to(vc.current_position());
BOOST_TEST_LEQ(std::abs(pos - off_pos), 1.0e-6); REQUIRE(std::abs(pos - off_pos) < 1.0e-6);
} }
} }
@ -145,9 +120,11 @@ void test_offset_curve(double const &offset) {
{ {
mapnik::vertex_cache::scoped_state s(off_vc); mapnik::vertex_cache::scoped_state s(off_vc);
off_vc.move(off_pos); off_vc.move(off_pos);
BOOST_TEST_LEQ(dist(vc.current_position(), off_vc.current_position()), (1.001 * offset)); auto eps = (1.001 * offset);
auto actual = dist(vc.current_position(), off_vc.current_position());
REQUIRE(actual < eps);
} }
BOOST_TEST_LEQ(std::abs((pos / vc.length()) - (off_pos / off_vc.length())), 1.0e-3); REQUIRE(std::abs((pos / vc.length()) - (off_pos / off_vc.length())) < 1.0e-3);
} }
} }
@ -180,24 +157,16 @@ void test_s_shaped_curve(double const &offset) {
{ {
mapnik::vertex_cache::scoped_state s(off_vc); mapnik::vertex_cache::scoped_state s(off_vc);
off_vc.move(off_pos); off_vc.move(off_pos);
BOOST_TEST_LEQ(dist(vc.current_position(), off_vc.current_position()), (1.002 * offset)); REQUIRE(dist(vc.current_position(), off_vc.current_position()) < (1.002 * offset));
} }
} }
} }
int main(int argc, char** argv) TEST_CASE("offsets") {
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
SECTION("line") {
try { try {
BOOST_TEST(set_working_dir(args));
std::vector<double> offsets = { 0.01, 0.02, 0.1, 0.2 }; std::vector<double> offsets = { 0.01, 0.02, 0.1, 0.2 };
for (double offset : offsets) { for (double offset : offsets) {
// test simple straight line segment - should be easy to // test simple straight line segment - should be easy to
@ -220,17 +189,7 @@ int main(int argc, char** argv)
catch (std::exception const& ex) catch (std::exception const& ex)
{ {
std::cerr << ex.what() << "\n"; std::cerr << ex.what() << "\n";
BOOST_TEST(false); REQUIRE(false);
}
if (!::boost::detail::test_errors())
{
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ line offset: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
}
else
{
return ::boost::report_errors();
} }
} }
}

View file

@ -1,4 +1,4 @@
#include <boost/detail/lightweight_test.hpp> #include "catch.hpp"
#include <iostream> #include <iostream>
#include <mapnik/map.hpp> #include <mapnik/map.hpp>
@ -19,7 +19,6 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include "utils.hpp"
bool compare_images(std::string const& src_fn,std::string const& dest_fn) bool compare_images(std::string const& src_fn,std::string const& dest_fn)
{ {
@ -58,20 +57,14 @@ bool compare_images(std::string const& src_fn,std::string const& dest_fn)
return true; return true;
} }
int main(int argc, char** argv) TEST_CASE("mapnik::request") {
{
std::vector<std::string> args; SECTION("rendering") {
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
std::string expected("./tests/cpp_tests/support/map-request-marker-text-line-expected.png"); std::string expected("./tests/cpp_tests/support/map-request-marker-text-line-expected.png");
std::string expected_cairo("./tests/cpp_tests/support/map-request-marker-text-line-expected-cairo.png"); std::string expected_cairo("./tests/cpp_tests/support/map-request-marker-text-line-expected-cairo.png");
try { try {
BOOST_TEST(set_working_dir(args));
mapnik::datasource_cache::instance().register_datasources("plugins/input/csv.input"); mapnik::datasource_cache::instance().register_datasources("plugins/input/csv.input");
mapnik::freetype_engine::register_fonts("./fonts", true ); mapnik::freetype_engine::register_fonts("./fonts", true );
mapnik::Map m(256,256); mapnik::Map m(256,256);
@ -88,7 +81,7 @@ int main(int argc, char** argv)
mapnik::save_to_file(im,actual1); mapnik::save_to_file(im,actual1);
// TODO - re-enable if we can control the freetype/cairo versions used // TODO - re-enable if we can control the freetype/cairo versions used
// https://github.com/mapnik/mapnik/issues/1868 // https://github.com/mapnik/mapnik/issues/1868
//BOOST_TEST(compare_images(actual1,expected)); //REQUIRE(compare_images(actual1,expected));
// reset image // reset image
mapnik::fill(im, 0); mapnik::fill(im, 0);
@ -105,7 +98,7 @@ int main(int argc, char** argv)
mapnik::save_to_file(im,actual2); mapnik::save_to_file(im,actual2);
// TODO - re-enable if we can control the freetype/cairo versions used // TODO - re-enable if we can control the freetype/cairo versions used
// https://github.com/mapnik/mapnik/issues/1868 // https://github.com/mapnik/mapnik/issues/1868
//BOOST_TEST(compare_images(actual2,expected)); //REQUIRE(compare_images(actual2,expected));
// reset image // reset image
mapnik::fill(im, 0); mapnik::fill(im, 0);
@ -139,7 +132,7 @@ int main(int argc, char** argv)
mapnik::save_to_file(im,actual3); mapnik::save_to_file(im,actual3);
// TODO - re-enable if we can control the freetype/cairo versions used // TODO - re-enable if we can control the freetype/cairo versions used
// https://github.com/mapnik/mapnik/issues/1868 // https://github.com/mapnik/mapnik/issues/1868
//BOOST_TEST(compare_images(actual3,expected)); //REQUIRE(compare_images(actual3,expected));
// also test cairo // also test cairo
#if defined(HAVE_CAIRO) #if defined(HAVE_CAIRO)
@ -154,18 +147,12 @@ int main(int argc, char** argv)
cairo_surface_write_to_png(&*image_surface, actual_cairo.c_str()); cairo_surface_write_to_png(&*image_surface, actual_cairo.c_str());
// TODO - re-enable if we can control the freetype/cairo versions used // TODO - re-enable if we can control the freetype/cairo versions used
// https://github.com/mapnik/mapnik/issues/1868 // https://github.com/mapnik/mapnik/issues/1868
//BOOST_TEST(compare_images(actual_cairo,expected_cairo)); //REQUIRE(compare_images(actual_cairo,expected_cairo));
#endif #endif
// TODO - test grid_renderer // TODO - test grid_renderer
} catch (std::exception const& ex) { } catch (std::exception const& ex) {
std::clog << ex.what() << "\n"; std::clog << ex.what() << "\n";
} }
if (!::boost::detail::test_errors()) { }
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ Map Request rendering hook: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
}
} }

115
tests/cxx/params_test.cpp Normal file
View file

@ -0,0 +1,115 @@
#include "catch.hpp"
#include <iostream>
#include <mapnik/value_types.hpp>
#include <mapnik/params.hpp>
#include <mapnik/boolean.hpp>
#include <vector>
#include <algorithm>
#include <ostream>
namespace detail {
class string_holder {
public:
string_holder() :
member_("member") {}
std::string const& get_string() const
{
return member_;
}
private:
std::string member_;
};
}
TEST_CASE("parameters") {
SECTION("get/set") {
try
{
mapnik::parameters params;
// true
params["bool"] = mapnik::value_integer(true);
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "true";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = mapnik::value_integer(1);
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "1";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "True";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "on";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
params["bool"] = "yes";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == true));
// false
params["bool"] = mapnik::value_integer(false);
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false) );
params["bool"] = "false";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false) );
params["bool"] = mapnik::value_integer(0);
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
params["bool"] = "0";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
params["bool"] = "False";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
params["bool"] = "off";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
params["bool"] = "no";
REQUIRE( (params.get<mapnik::boolean_type>("bool") && *params.get<mapnik::boolean_type>("bool") == false));
// strings
params["string"] = "hello";
REQUIRE( (params.get<std::string>("string") && *params.get<std::string>("string") == "hello") );
// int
params["int"] = mapnik::value_integer(1);
REQUIRE( (params.get<mapnik::value_integer>("int") && *params.get<mapnik::value_integer>("int") == 1) );
// double
params["double"] = 1.5;
REQUIRE( (params.get<double>("double") && *params.get<double>("double") == 1.5) );
// value_null
params["null"] = mapnik::value_null();
// https://github.com/mapnik/mapnik/issues/2471
//REQUIRE( (params.get<mapnik::value_null>("null") && *params.get<mapnik::value_null>("null") == mapnik::value_null()) );
std::string value("value");
params["value"] = value;
REQUIRE( (params.get<std::string>("value") == std::string("value")) ) ;
REQUIRE(value == std::string("value"));
// ensure that const member is not moved incorrectly when added to params
detail::string_holder holder;
std::string const& holder_member = holder.get_string();
params["member"] = holder_member;
REQUIRE( (params.get<std::string>("member") == std::string("member")) );
REQUIRE( (holder_member == std::string("member")) );
}
catch (std::exception const& ex)
{
std::cerr << ex.what() << "\n";
REQUIRE(false);
}
}
}

View file

@ -1,9 +1,9 @@
#include <boost/detail/lightweight_test.hpp> #include "catch.hpp"
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include "utils.hpp"
#include <mapnik/layer.hpp> #include <mapnik/layer.hpp>
#include <mapnik/wkt/wkt_factory.hpp> #include <mapnik/wkt/wkt_factory.hpp>
@ -41,21 +41,14 @@ void simplify(std::string const& wkt_in, double tolerance, std::string const& me
mapnik::geometry_container multi_out; mapnik::geometry_container multi_out;
multi_out.push_back(output); multi_out.push_back(output);
std::string wkt_out; std::string wkt_out;
BOOST_TEST(mapnik::to_wkt(multi_out, wkt_out)); REQUIRE(mapnik::to_wkt(multi_out, wkt_out));
BOOST_TEST_EQ(wkt_out, expected); REQUIRE(wkt_out == expected);
#endif #endif
} }
int main(int argc, char** argv) TEST_CASE("converters") {
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
BOOST_TEST(set_working_dir(args)); SECTION("simplify") {
simplify( std::string("LineString(0 0,2 2,3 5,4 1,5 0,6 7,7 0)"), simplify( std::string("LineString(0 0,2 2,3 5,4 1,5 0,6 7,7 0)"),
4, "douglas-peucker", 4, "douglas-peucker",
@ -85,14 +78,5 @@ int main(int argc, char** argv)
3, "douglas-peucker", 3, "douglas-peucker",
std::string("LineString(0 0,0 -10,-5 7,4 6)")); std::string("LineString(0 0,0 -10,-5 7,4 6)"));
if (!::boost::detail::test_errors()) }
{
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ simplify conversions: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
}
else
{
return ::boost::report_errors();
}
} }

View file

@ -0,0 +1,30 @@
#include "catch.hpp"
#include <iostream>
#include <mapnik/symbolizer.hpp>
#include <vector>
#include <algorithm>
using namespace mapnik;
TEST_CASE("symbolizer") {
SECTION("enums") {
try {
marker_multi_policy_enum policy_in = MARKER_WHOLE_MULTI;
REQUIRE(policy_in == MARKER_WHOLE_MULTI);
markers_symbolizer sym;
put(sym, keys::markers_multipolicy, policy_in);
REQUIRE(sym.properties.count(keys::markers_multipolicy) == static_cast<unsigned long>(1));
marker_multi_policy_enum policy_out = get<mapnik::marker_multi_policy_enum>(sym, keys::markers_multipolicy);
REQUIRE(policy_out == MARKER_WHOLE_MULTI);
}
catch (std::exception const & ex)
{
std::clog << ex.what() << std::endl;
REQUIRE(false);
}
}
}

View file

@ -1,4 +1,5 @@
#include <boost/detail/lightweight_test.hpp> #include "catch.hpp"
#include <iostream> #include <iostream>
#include <mapnik/params.hpp> #include <mapnik/params.hpp>
#include <mapnik/wkb.hpp> #include <mapnik/wkb.hpp>
@ -11,23 +12,9 @@
#include <algorithm> #include <algorithm>
#include <boost/version.hpp> #include <boost/version.hpp>
namespace { TEST_CASE("geometry formats") {
void test_simple_and_valid(const mapnik::geometry::geometry<double> &geom) {
// only Boost >= 1.56 has is_valid and is_simple
#if BOOST_VERSION >= 105600
BOOST_TEST(mapnik::geometry::is_valid(geom) && mapnik::geometry::is_simple(geom));
#endif
}
}
int main(int argc, char** argv) SECTION("wkb") {
{
std::vector<std::string> args;
for (int i=1;i<argc;++i)
{
args.push_back(argv[i]);
}
bool quiet = std::find(args.begin(), args.end(), "-q")!=args.end();
unsigned char sp_valid_blob[] = { unsigned char sp_valid_blob[] = {
0x0, 0x1, 0xBC, 0xB, 0x0, 0x0, 0x1F, 0x12, 0xDB, 0xCF, 0xC3, 0xA2, 0x41, 0x41, 0x9D, 0x74, 0xB0, 0x31, 0xE6, 0x34, 0x53, 0x41, 0xDB, 0x0, 0x1, 0xBC, 0xB, 0x0, 0x0, 0x1F, 0x12, 0xDB, 0xCF, 0xC3, 0xA2, 0x41, 0x41, 0x9D, 0x74, 0xB0, 0x31, 0xE6, 0x34, 0x53, 0x41, 0xDB,
@ -83,47 +70,52 @@ int main(int argc, char** argv)
mapnik::wkbSpatiaLite); mapnik::wkbSpatiaLite);
// winding order is not correct per OGC so we'll fix it // winding order is not correct per OGC so we'll fix it
mapnik::geometry::correct(geom); mapnik::geometry::correct(geom);
test_simple_and_valid(geom); #if BOOST_VERSION >= 105600
REQUIRE(mapnik::geometry::is_valid(geom));
REQUIRE(mapnik::geometry::is_simple(geom));
#endif
geom = mapnik::geometry_utils::from_wkb((const char*)sp_valid_blob, geom = mapnik::geometry_utils::from_wkb((const char*)sp_valid_blob,
sizeof(sp_valid_blob) / sizeof(sp_valid_blob[0]), sizeof(sp_valid_blob) / sizeof(sp_valid_blob[0]),
mapnik::wkbAuto); mapnik::wkbAuto);
mapnik::geometry::correct(geom); mapnik::geometry::correct(geom);
test_simple_and_valid(geom); #if BOOST_VERSION >= 105600
REQUIRE(mapnik::geometry::is_valid(geom));
REQUIRE(mapnik::geometry::is_simple(geom));
#endif
geom = mapnik::geometry_utils::from_wkb((const char*)sp_invalid_blob, geom = mapnik::geometry_utils::from_wkb((const char*)sp_invalid_blob,
sizeof(sp_invalid_blob) / sizeof(sp_invalid_blob[0]), sizeof(sp_invalid_blob) / sizeof(sp_invalid_blob[0]),
mapnik::wkbAuto); mapnik::wkbAuto);
BOOST_TEST(geom.is<mapnik::geometry::geometry_empty>()); // returns geometry_empty REQUIRE(geom.is<mapnik::geometry::geometry_empty>()); // returns geometry_empty
// sqlite generic wkb blob // sqlite generic wkb blob
geom = mapnik::geometry_utils::from_wkb((const char*)sq_valid_blob, geom = mapnik::geometry_utils::from_wkb((const char*)sq_valid_blob,
sizeof(sq_valid_blob) / sizeof(sq_valid_blob[0]), sizeof(sq_valid_blob) / sizeof(sq_valid_blob[0]),
mapnik::wkbGeneric); mapnik::wkbGeneric);
test_simple_and_valid(geom); #if BOOST_VERSION >= 105600
REQUIRE(mapnik::geometry::is_valid(geom));
REQUIRE(mapnik::geometry::is_simple(geom));
#endif
geom = mapnik::geometry_utils::from_wkb( (const char*)sq_valid_blob, geom = mapnik::geometry_utils::from_wkb( (const char*)sq_valid_blob,
sizeof(sq_valid_blob) / sizeof(sq_valid_blob[0]), sizeof(sq_valid_blob) / sizeof(sq_valid_blob[0]),
mapnik::wkbAuto); mapnik::wkbAuto);
test_simple_and_valid(geom); #if BOOST_VERSION >= 105600
REQUIRE(mapnik::geometry::is_valid(geom));
REQUIRE(mapnik::geometry::is_simple(geom));
#endif
geom = mapnik::geometry_utils::from_wkb((const char*)sq_invalid_blob, geom = mapnik::geometry_utils::from_wkb((const char*)sq_invalid_blob,
sizeof(sq_invalid_blob) / sizeof(sq_invalid_blob[0]), sizeof(sq_invalid_blob) / sizeof(sq_invalid_blob[0]),
mapnik::wkbGeneric); mapnik::wkbGeneric);
BOOST_TEST(geom.is<mapnik::geometry::geometry_empty>()); // returns geometry_empty REQUIRE(geom.is<mapnik::geometry::geometry_empty>()); // returns geometry_empty
} catch (std::exception const& ex) { } catch (std::exception const& ex) {
BOOST_TEST(false); REQUIRE(false);
std::clog << "threw: " << ex.what() << "\n"; std::clog << "threw: " << ex.what() << "\n";
} }
}
if (!::boost::detail::test_errors()) {
if (quiet) std::clog << "\x1b[1;32m.\x1b[0m";
else std::clog << "C++ WKB formats test: \x1b[1;32m✓ \x1b[0m\n";
::boost::detail::report_errors_remind().called_report_errors_function = true;
} else {
return ::boost::report_errors();
}
} }

View file

@ -1,71 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from nose.tools import eq_
from utilities import run_all
import mapnik
import json
# geojson box of the world
geojson = { "type": "Feature", "properties": { }, "geometry": { "type": "Polygon", "coordinates": [ [ [ -17963313.143242701888084, -6300857.11560364998877 ], [ -17963313.143242701888084, 13071343.332991421222687 ], [ 7396658.353099936619401, 13071343.332991421222687 ], [ 7396658.353099936619401, -6300857.11560364998877 ], [ -17963313.143242701888084, -6300857.11560364998877 ] ] ] } }
def test_that_coordinates_do_not_overflow_and_polygon_is_rendered_memory():
expected_color = mapnik.Color('white')
projection = '+init=epsg:4326'
ds = mapnik.MemoryDatasource()
context = mapnik.Context()
feat = mapnik.Feature.from_geojson(json.dumps(geojson),context)
ds.add_feature(feat)
s = mapnik.Style()
r = mapnik.Rule()
sym = mapnik.PolygonSymbolizer()
sym.fill = expected_color
r.symbols.append(sym)
s.rules.append(r)
lyr = mapnik.Layer('Layer',projection)
lyr.datasource = ds
lyr.styles.append('style')
m = mapnik.Map(256,256,projection)
m.background_color = mapnik.Color('green')
m.append_style('style',s)
m.layers.append(lyr)
# 17/20864/45265.png
m.zoom_to_box(mapnik.Box2d(-13658379.710221574,6197514.253362091,-13657768.213995293,6198125.749588372))
# works 15/5216/11316.png
#m.zoom_to_box(mapnik.Box2d(-13658379.710221574,6195679.764683247,-13655933.72531645,6198125.749588372))
im = mapnik.Image(256,256)
mapnik.render(m,im)
eq_(im.get_pixel(128,128),expected_color.packed())
def test_that_coordinates_do_not_overflow_and_polygon_is_rendered_csv():
expected_color = mapnik.Color('white')
projection = '+init=epsg:4326'
ds = mapnik.MemoryDatasource()
context = mapnik.Context()
feat = mapnik.Feature.from_geojson(json.dumps(geojson),context)
ds.add_feature(feat)
geojson_string = "geojson\n'%s'" % json.dumps(geojson['geometry'])
ds = mapnik.Datasource(**{'type':'csv','inline':geojson_string})
s = mapnik.Style()
r = mapnik.Rule()
sym = mapnik.PolygonSymbolizer()
sym.fill = expected_color
r.symbols.append(sym)
s.rules.append(r)
lyr = mapnik.Layer('Layer',projection)
lyr.datasource = ds
lyr.styles.append('style')
m = mapnik.Map(256,256,projection)
m.background_color = mapnik.Color('green')
m.append_style('style',s)
m.layers.append(lyr)
# 17/20864/45265.png
m.zoom_to_box(mapnik.Box2d(-13658379.710221574,6197514.253362091,-13657768.213995293,6198125.749588372))
# works 15/5216/11316.png
#m.zoom_to_box(mapnik.Box2d(-13658379.710221574,6195679.764683247,-13655933.72531645,6198125.749588372))
im = mapnik.Image(256,256)
mapnik.render(m,im)
eq_(im.get_pixel(128,128),expected_color.packed())
if __name__ == "__main__":
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,176 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from nose.tools import eq_,assert_true,assert_almost_equal,assert_false
from utilities import run_all
import mapnik
def test_coord_init():
c = mapnik.Coord(100, 100)
eq_(c.x, 100)
eq_(c.y, 100)
def test_coord_multiplication():
c = mapnik.Coord(100, 100)
c *= 2
eq_(c.x, 200)
eq_(c.y, 200)
def test_envelope_init():
e = mapnik.Box2d(100, 100, 200, 200)
assert_true(e.contains(100, 100))
assert_true(e.contains(100, 200))
assert_true(e.contains(200, 200))
assert_true(e.contains(200, 100))
assert_true(e.contains(e.center()))
assert_false(e.contains(99.9, 99.9))
assert_false(e.contains(99.9, 200.1))
assert_false(e.contains(200.1, 200.1))
assert_false(e.contains(200.1, 99.9))
eq_(e.width(), 100)
eq_(e.height(), 100)
eq_(e.minx, 100)
eq_(e.miny, 100)
eq_(e.maxx, 200)
eq_(e.maxy, 200)
eq_(e[0],100)
eq_(e[1],100)
eq_(e[2],200)
eq_(e[3],200)
eq_(e[0],e[-4])
eq_(e[1],e[-3])
eq_(e[2],e[-2])
eq_(e[3],e[-1])
c = e.center()
eq_(c.x, 150)
eq_(c.y, 150)
def test_envelope_static_init():
e = mapnik.Box2d.from_string('100 100 200 200')
e2 = mapnik.Box2d.from_string('100,100,200,200')
e3 = mapnik.Box2d.from_string('100 , 100 , 200 , 200')
eq_(e,e2)
eq_(e,e3)
assert_true(e.contains(100, 100))
assert_true(e.contains(100, 200))
assert_true(e.contains(200, 200))
assert_true(e.contains(200, 100))
assert_true(e.contains(e.center()))
assert_false(e.contains(99.9, 99.9))
assert_false(e.contains(99.9, 200.1))
assert_false(e.contains(200.1, 200.1))
assert_false(e.contains(200.1, 99.9))
eq_(e.width(), 100)
eq_(e.height(), 100)
eq_(e.minx, 100)
eq_(e.miny, 100)
eq_(e.maxx, 200)
eq_(e.maxy, 200)
eq_(e[0],100)
eq_(e[1],100)
eq_(e[2],200)
eq_(e[3],200)
eq_(e[0],e[-4])
eq_(e[1],e[-3])
eq_(e[2],e[-2])
eq_(e[3],e[-1])
c = e.center()
eq_(c.x, 150)
eq_(c.y, 150)
def test_envelope_multiplication():
# no width then no impact of multiplication
a = mapnik.Box2d(100, 100, 100, 100)
a *= 5
eq_(a.minx,100)
eq_(a.miny,100)
eq_(a.maxx,100)
eq_(a.maxy,100)
a = mapnik.Box2d(100.0, 100.0, 100.0, 100.0)
a *= 5
eq_(a.minx,100)
eq_(a.miny,100)
eq_(a.maxx,100)
eq_(a.maxy,100)
a = mapnik.Box2d(100.0, 100.0, 100.001, 100.001)
a *= 5
assert_almost_equal(a.minx, 99.9979, places=3)
assert_almost_equal(a.miny, 99.9979, places=3)
assert_almost_equal(a.maxx, 100.0030, places=3)
assert_almost_equal(a.maxy, 100.0030, places=3)
e = mapnik.Box2d(100, 100, 200, 200)
e *= 2
eq_(e.minx,50)
eq_(e.miny,50)
eq_(e.maxx,250)
eq_(e.maxy,250)
assert_true(e.contains(50, 50))
assert_true(e.contains(50, 250))
assert_true(e.contains(250, 250))
assert_true(e.contains(250, 50))
assert_false(e.contains(49.9, 49.9))
assert_false(e.contains(49.9, 250.1))
assert_false(e.contains(250.1, 250.1))
assert_false(e.contains(250.1, 49.9))
assert_true(e.contains(e.center()))
eq_(e.width(), 200)
eq_(e.height(), 200)
eq_(e.minx, 50)
eq_(e.miny, 50)
eq_(e.maxx, 250)
eq_(e.maxy, 250)
c = e.center()
eq_(c.x, 150)
eq_(c.y, 150)
def test_envelope_clipping():
e1 = mapnik.Box2d(-180,-90,180,90)
e2 = mapnik.Box2d(-120,40,-110,48)
e1.clip(e2)
eq_(e1,e2)
# madagascar in merc
e1 = mapnik.Box2d(4772116.5490, -2744395.0631, 5765186.4203, -1609458.0673)
e2 = mapnik.Box2d(5124338.3753, -2240522.1727, 5207501.8621, -2130452.8520)
e1.clip(e2)
eq_(e1,e2)
# nz in lon/lat
e1 = mapnik.Box2d(163.8062, -47.1897, 179.3628, -33.9069)
e2 = mapnik.Box2d(173.7378, -39.6395, 174.4849, -38.9252)
e1.clip(e2)
eq_(e1,e2)
if __name__ == "__main__":
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,61 +0,0 @@
import os, mapnik
from nose.tools import eq_
from utilities import execution_path, run_all
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_clearing_image_data():
im = mapnik.Image(256,256)
# make sure it equals itself
bytes = im.tostring()
eq_(im.tostring(),bytes)
# set background, then clear
im.fill(mapnik.Color('green'))
eq_(im.tostring()!=bytes,True)
# clear image, should now equal original
im.clear()
eq_(im.tostring(),bytes)
def make_map():
ds = mapnik.MemoryDatasource()
context = mapnik.Context()
context.push('Name')
pixel_key = 1
f = mapnik.Feature(context,pixel_key)
f['Name'] = str(pixel_key)
f.geometry=mapnik.Geometry.from_wkt('POLYGON ((0 0, 0 256, 256 256, 256 0, 0 0))')
ds.add_feature(f)
s = mapnik.Style()
r = mapnik.Rule()
symb = mapnik.PolygonSymbolizer()
r.symbols.append(symb)
s.rules.append(r)
lyr = mapnik.Layer('Places')
lyr.datasource = ds
lyr.styles.append('places_labels')
width,height = 256,256
m = mapnik.Map(width,height)
m.append_style('places_labels',s)
m.layers.append(lyr)
m.zoom_all()
return m
if mapnik.has_grid_renderer():
def test_clearing_grid_data():
g = mapnik.Grid(256,256)
utf = g.encode()
# make sure it equals itself
eq_(g.encode(),utf)
m = make_map()
mapnik.render_layer(m,g,layer=0,fields=['__id__','Name'])
eq_(g.encode()!=utf,True)
# clear grid, should now match original
g.clear()
eq_(g.encode(),utf)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,196 +0,0 @@
#!/usr/bin/env python
import os
import shutil
import mapnik
from nose.tools import eq_
from utilities import execution_path, run_all
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def make_tmp_map():
m = mapnik.Map(512,512)
m.background_color = mapnik.Color('steelblue')
ds = mapnik.MemoryDatasource()
context = mapnik.Context()
context.push('Name')
f = mapnik.Feature(context,1)
f['Name'] = 'Hello'
f.geometry = mapnik.Geometry.from_wkt('POINT (0 0)')
ds.add_feature(f)
s = mapnik.Style()
r = mapnik.Rule()
sym = mapnik.MarkersSymbolizer()
sym.allow_overlap = True
r.symbols.append(sym)
s.rules.append(r)
lyr = mapnik.Layer('Layer')
lyr.datasource = ds
lyr.styles.append('style')
m.append_style('style',s)
m.layers.append(lyr)
return m
def draw_title(m,ctx,text,size=10,color=mapnik.Color('black')):
""" Draw a Map Title near the top of a page."""
middle = m.width/2.0
ctx.set_source_rgba(*cairo_color(color))
ctx.select_font_face("DejaVu Sans Book", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
ctx.set_font_size(size)
x_bearing, y_bearing, width, height = ctx.text_extents(text)[:4]
ctx.move_to(middle - width / 2 - x_bearing, 20.0 - height / 2 - y_bearing)
ctx.show_text(text)
def draw_neatline(m,ctx):
w,h = m.width, m.height
ctx.set_source_rgba(*cairo_color(mapnik.Color('black')))
outline = [
[0,0],[w,0],[w,h],[0,h]
]
ctx.set_line_width(1)
for idx,pt in enumerate(outline):
if (idx == 0):
ctx.move_to(*pt)
else:
ctx.line_to(*pt)
ctx.close_path()
inset = 6
inline = [
[inset,inset],[w-inset,inset],[w-inset,h-inset],[inset,h-inset]
]
ctx.set_line_width(inset/2)
for idx,pt in enumerate(inline):
if (idx == 0):
ctx.move_to(*pt)
else:
ctx.line_to(*pt)
ctx.close_path()
ctx.stroke()
def cairo_color(c):
""" Return a Cairo color tuple from a Mapnik Color."""
ctx_c = (c.r/255.0,c.g/255.0,c.b/255.0,c.a/255.0)
return ctx_c
if mapnik.has_pycairo():
import cairo
def test_passing_pycairo_context_svg():
m = make_tmp_map()
m.zoom_to_box(mapnik.Box2d(-180,-90,180,90))
test_cairo_file = '/tmp/mapnik-cairo-context-test.svg'
surface = cairo.SVGSurface(test_cairo_file, m.width, m.height)
expected_cairo_file = './images/pycairo/cairo-cairo-expected.svg'
context = cairo.Context(surface)
mapnik.render(m,context)
draw_title(m,context,"Hello Map",size=20)
draw_neatline(m,context)
surface.finish()
if not os.path.exists(expected_cairo_file) or os.environ.get('UPDATE'):
print 'generated expected cairo surface file %s' % expected_cairo_file
shutil.copy(test_cairo_file,expected_cairo_file)
diff = abs(os.stat(expected_cairo_file).st_size-os.stat(test_cairo_file).st_size)
msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,test_cairo_file,'tests/python_tests/'+ expected_cairo_file)
eq_( diff < 1500, True, msg)
os.remove(test_cairo_file)
def test_passing_pycairo_context_pdf():
m = make_tmp_map()
m.zoom_to_box(mapnik.Box2d(-180,-90,180,90))
test_cairo_file = '/tmp/mapnik-cairo-context-test.pdf'
surface = cairo.PDFSurface(test_cairo_file, m.width, m.height)
expected_cairo_file = './images/pycairo/cairo-cairo-expected.pdf'
context = cairo.Context(surface)
mapnik.render(m,context)
draw_title(m,context,"Hello Map",size=20)
draw_neatline(m,context)
surface.finish()
if not os.path.exists(expected_cairo_file) or os.environ.get('UPDATE'):
print 'generated expected cairo surface file %s' % expected_cairo_file
shutil.copy(test_cairo_file,expected_cairo_file)
diff = abs(os.stat(expected_cairo_file).st_size-os.stat(test_cairo_file).st_size)
msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,test_cairo_file,'tests/python_tests/'+ expected_cairo_file)
eq_( diff < 1500, True, msg)
os.remove(test_cairo_file)
def test_passing_pycairo_context_png():
m = make_tmp_map()
m.zoom_to_box(mapnik.Box2d(-180,-90,180,90))
test_cairo_file = '/tmp/mapnik-cairo-context-test.png'
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, m.width, m.height)
expected_cairo_file = './images/pycairo/cairo-cairo-expected.png'
expected_cairo_file2 = './images/pycairo/cairo-cairo-expected-reduced.png'
context = cairo.Context(surface)
mapnik.render(m,context)
draw_title(m,context,"Hello Map",size=20)
draw_neatline(m,context)
surface.write_to_png(test_cairo_file)
reduced_color_image = test_cairo_file.replace('png','-mapnik.png')
im = mapnik.Image.from_cairo(surface)
im.save(reduced_color_image,'png8')
surface.finish()
if not os.path.exists(expected_cairo_file) or os.environ.get('UPDATE'):
print 'generated expected cairo surface file %s' % expected_cairo_file
shutil.copy(test_cairo_file,expected_cairo_file)
diff = abs(os.stat(expected_cairo_file).st_size-os.stat(test_cairo_file).st_size)
msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,test_cairo_file,'tests/python_tests/'+ expected_cairo_file)
eq_( diff < 500, True, msg)
os.remove(test_cairo_file)
if not os.path.exists(expected_cairo_file2) or os.environ.get('UPDATE'):
print 'generated expected cairo surface file %s' % expected_cairo_file2
shutil.copy(reduced_color_image,expected_cairo_file2)
diff = abs(os.stat(expected_cairo_file2).st_size-os.stat(reduced_color_image).st_size)
msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,reduced_color_image,'tests/python_tests/'+ expected_cairo_file2)
eq_( diff < 500, True, msg)
os.remove(reduced_color_image)
if 'sqlite' in mapnik.DatasourceCache.plugin_names():
def _pycairo_surface(type,sym):
test_cairo_file = '/tmp/mapnik-cairo-surface-test.%s.%s' % (sym,type)
expected_cairo_file = './images/pycairo/cairo-surface-expected.%s.%s' % (sym,type)
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/%s_symbolizer.xml' % sym)
m.zoom_all()
if hasattr(cairo,'%sSurface' % type.upper()):
surface = getattr(cairo,'%sSurface' % type.upper())(test_cairo_file, m.width,m.height)
mapnik.render(m, surface)
surface.finish()
if not os.path.exists(expected_cairo_file) or os.environ.get('UPDATE'):
print 'generated expected cairo surface file %s' % expected_cairo_file
shutil.copy(test_cairo_file,expected_cairo_file)
diff = abs(os.stat(expected_cairo_file).st_size-os.stat(test_cairo_file).st_size)
msg = 'diff in size (%s) between actual (%s) and expected(%s)' % (diff,test_cairo_file,'tests/python_tests/'+ expected_cairo_file)
if os.uname()[0] == 'Darwin':
eq_( diff < 2100, True, msg)
else:
eq_( diff < 23000, True, msg)
os.remove(test_cairo_file)
return True
else:
print 'skipping cairo.%s test since surface is not available' % type.upper()
return True
def test_pycairo_svg_surface1():
eq_(_pycairo_surface('svg','point'),True)
def test_pycairo_svg_surface2():
eq_(_pycairo_surface('svg','building'),True)
def test_pycairo_svg_surface3():
eq_(_pycairo_surface('svg','polygon'),True)
def test_pycairo_pdf_surface1():
eq_(_pycairo_surface('pdf','point'),True)
def test_pycairo_pdf_surface2():
eq_(_pycairo_surface('pdf','building'),True)
def test_pycairo_pdf_surface3():
eq_(_pycairo_surface('pdf','polygon'),True)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,115 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os, mapnik
from timeit import Timer, time
from nose.tools import *
from utilities import execution_path, run_all, get_unique_colors
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_color_init():
c = mapnik.Color(12, 128, 255)
eq_(c.r, 12)
eq_(c.g, 128)
eq_(c.b, 255)
eq_(c.a, 255)
eq_(False, c.get_premultiplied())
c = mapnik.Color(16, 32, 64, 128)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(False, c.get_premultiplied())
c = mapnik.Color(16, 32, 64, 128,True)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(True, c.get_premultiplied())
c = mapnik.Color('rgba(16,32,64,0.5)')
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(False, c.get_premultiplied())
c = mapnik.Color('rgba(16,32,64,0.5)', True)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(True, c.get_premultiplied())
hex_str = '#10204080'
c = mapnik.Color(hex_str)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(hex_str, c.to_hex_string())
eq_(False, c.get_premultiplied())
c = mapnik.Color(hex_str, True)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(hex_str, c.to_hex_string())
eq_(True, c.get_premultiplied())
rgba_int = 2151686160
c = mapnik.Color(rgba_int)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(rgba_int, c.packed())
eq_(False, c.get_premultiplied())
c = mapnik.Color(rgba_int, True)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
eq_(rgba_int, c.packed())
eq_(True, c.get_premultiplied())
def test_color_properties():
c = mapnik.Color(16, 32, 64, 128)
eq_(c.r, 16)
eq_(c.g, 32)
eq_(c.b, 64)
eq_(c.a, 128)
c.r = 17
eq_(c.r, 17)
c.g = 33
eq_(c.g, 33)
c.b = 65
eq_(c.b, 65)
c.a = 128
eq_(c.a, 128)
def test_color_premultiply():
c = mapnik.Color(16, 33, 255, 128)
eq_(c.premultiply(), True)
eq_(c.r, 8)
eq_(c.g, 17)
eq_(c.b, 128)
eq_(c.a, 128)
# Repeating it again should do nothing
eq_(c.premultiply(), False)
eq_(c.r, 8)
eq_(c.g, 17)
eq_(c.b, 128)
eq_(c.a, 128)
c.demultiply()
c.demultiply()
# This will not return the same values as before but we expect that
eq_(c.r,15)
eq_(c.g,33)
eq_(c.b,255)
eq_(c.a,128)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,112 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, mapnik
from nose.tools import *
from utilities import execution_path, run_all
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_another_compare():
im = mapnik.Image(5,5)
im2 = mapnik.Image(5,5)
im2.fill(mapnik.Color('rgba(255,255,255,0)'))
eq_(im.compare(im2,16), im.width() * im.height())
def test_compare_rgba8():
im = mapnik.Image(5,5,mapnik.ImageType.rgba8)
im.fill(mapnik.Color(0,0,0,0))
eq_(im.compare(im), 0)
im2 = mapnik.Image(5,5,mapnik.ImageType.rgba8)
im2.fill(mapnik.Color(0,0,0,0))
eq_(im.compare(im2), 0)
eq_(im2.compare(im), 0)
im2.fill(mapnik.Color(0,0,0,12))
eq_(im.compare(im2), 25)
eq_(im.compare(im2, 0, False), 0)
im3 = mapnik.Image(5,5,mapnik.ImageType.rgba8)
im3.set_pixel(0,0, mapnik.Color(0,0,0,0))
im3.set_pixel(0,1, mapnik.Color(1,1,1,1))
im3.set_pixel(1,0, mapnik.Color(2,2,2,2))
im3.set_pixel(1,1, mapnik.Color(3,3,3,3))
eq_(im.compare(im3), 3)
eq_(im.compare(im3,1),2)
eq_(im.compare(im3,2),1)
eq_(im.compare(im3,3),0)
def test_compare_2_image():
im = mapnik.Image(5,5)
im.set_pixel(0,0, mapnik.Color(254, 254, 254, 254))
im.set_pixel(4,4, mapnik.Color('white'))
im2 = mapnik.Image(5,5)
eq_(im2.compare(im,16), 2)
def test_compare_dimensions():
im = mapnik.Image(2,2)
im2 = mapnik.Image(3,3)
eq_(im.compare(im2), 4)
eq_(im2.compare(im), 9)
def test_compare_gray8():
im = mapnik.Image(2,2,mapnik.ImageType.gray8)
im.fill(0)
eq_(im.compare(im), 0)
im2 = mapnik.Image(2,2,mapnik.ImageType.gray8)
im2.fill(0)
eq_(im.compare(im2), 0)
eq_(im2.compare(im), 0)
eq_(im.compare(im2, 0, False), 0)
im3 = mapnik.Image(2,2,mapnik.ImageType.gray8)
im3.set_pixel(0,0,0)
im3.set_pixel(0,1,1)
im3.set_pixel(1,0,2)
im3.set_pixel(1,1,3)
eq_(im.compare(im3),3)
eq_(im.compare(im3,1),2)
eq_(im.compare(im3,2),1)
eq_(im.compare(im3,3),0)
def test_compare_gray16():
im = mapnik.Image(2,2,mapnik.ImageType.gray16)
im.fill(0)
eq_(im.compare(im), 0)
im2 = mapnik.Image(2,2,mapnik.ImageType.gray16)
im2.fill(0)
eq_(im.compare(im2), 0)
eq_(im2.compare(im), 0)
eq_(im.compare(im2, 0, False), 0)
im3 = mapnik.Image(2,2,mapnik.ImageType.gray16)
im3.set_pixel(0,0,0)
im3.set_pixel(0,1,1)
im3.set_pixel(1,0,2)
im3.set_pixel(1,1,3)
eq_(im.compare(im3),3)
eq_(im.compare(im3,1),2)
eq_(im.compare(im3,2),1)
eq_(im.compare(im3,3),0)
def test_compare_gray32f():
im = mapnik.Image(2,2,mapnik.ImageType.gray32f)
im.fill(0.5)
eq_(im.compare(im), 0)
im2 = mapnik.Image(2,2,mapnik.ImageType.gray32f)
im2.fill(0.5)
eq_(im.compare(im2), 0)
eq_(im2.compare(im), 0)
eq_(im.compare(im2, 0, False), 0)
im3 = mapnik.Image(2,2,mapnik.ImageType.gray32f)
im3.set_pixel(0,0,0.5)
im3.set_pixel(0,1,1.5)
im3.set_pixel(1,0,2.5)
im3.set_pixel(1,1,3.5)
eq_(im.compare(im3),3)
eq_(im.compare(im3,1.0),2)
eq_(im.compare(im3,2.0),1)
eq_(im.compare(im3,3.0),0)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,258 +0,0 @@
#encoding: utf8
from nose.tools import eq_
import os
from utilities import execution_path, run_all
from utilities import get_unique_colors, pixel2channels, side_by_side_image
import mapnik
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def is_pre(color,alpha):
return (color*255.0/alpha) <= 255
def debug_image(image,step=2):
for x in range(0,image.width(),step):
for y in range(0,image.height(),step):
pixel = image.get_pixel(x,y)
red,green,blue,alpha = pixel2channels(pixel)
print "rgba(%s,%s,%s,%s) at %s,%s" % (red,green,blue,alpha,x,y)
def replace_style(m, name, style):
m.remove_style(name)
m.append_style(name, style)
# note: it is impossible to know for all pixel colors
# we can only detect likely cases of non premultiplied colors
def validate_pixels_are_not_premultiplied(image):
over_alpha = False
transparent = True
fully_opaque = True
for x in range(0,image.width(),2):
for y in range(0,image.height(),2):
pixel = image.get_pixel(x,y)
red,green,blue,alpha = pixel2channels(pixel)
if alpha > 0:
transparent = False
if alpha < 255:
fully_opaque = False
color_max = max(red,green,blue)
if color_max > alpha:
over_alpha = True
return over_alpha or transparent or fully_opaque
def validate_pixels_are_not_premultiplied2(image):
looks_not_multiplied = False
for x in range(0,image.width(),2):
for y in range(0,image.height(),2):
pixel = image.get_pixel(x,y)
red,green,blue,alpha = pixel2channels(pixel)
#each value of the color channels will never be bigger than that of the alpha channel.
if alpha > 0:
if red > 0 and red > alpha:
print 'red: %s, a: %s' % (red,alpha)
looks_not_multiplied = True
return looks_not_multiplied
def validate_pixels_are_premultiplied(image):
bad_pixels = []
for x in range(0,image.width(),2):
for y in range(0,image.height(),2):
pixel = image.get_pixel(x,y)
red,green,blue,alpha = pixel2channels(pixel)
if alpha > 0:
pixel = image.get_pixel(x,y)
is_valid = ((0 <= red <= alpha) and is_pre(red,alpha)) \
and ((0 <= green <= alpha) and is_pre(green,alpha)) \
and ((0 <= blue <= alpha) and is_pre(blue,alpha)) \
and (alpha >= 0 and alpha <= 255)
if not is_valid:
bad_pixels.append("rgba(%s,%s,%s,%s) at %s,%s" % (red,green,blue,alpha,x,y))
num_bad = len(bad_pixels)
return (num_bad == 0,bad_pixels)
def test_compare_images():
b = mapnik.Image.open('./images/support/b.png')
b.premultiply()
num_ops = len(mapnik.CompositeOp.names)
successes = []
fails = []
for name in mapnik.CompositeOp.names:
a = mapnik.Image.open('./images/support/a.png')
a.premultiply()
a.composite(b,getattr(mapnik.CompositeOp,name))
actual = '/tmp/mapnik-comp-op-test-' + name + '.png'
expected = 'images/composited/' + name + '.png'
valid = validate_pixels_are_premultiplied(a)
if not valid[0]:
fails.append('%s not validly premultiplied!:\n\t %s pixels (%s)' % (name,len(valid[1]),valid[1][0]))
a.demultiply()
if not validate_pixels_are_not_premultiplied(a):
fails.append('%s not validly demultiplied' % (name))
a.save(actual,'png32')
if not os.path.exists(expected) or os.environ.get('UPDATE'):
print 'generating expected test image: %s' % expected
a.save(expected,'png32')
expected_im = mapnik.Image.open(expected)
# compare them
if a.tostring('png32') == expected_im.tostring('png32'):
successes.append(name)
else:
fails.append('failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
fail_im = side_by_side_image(expected_im, a)
fail_im.save('/tmp/mapnik-comp-op-test-' + name + '.fail.png','png32')
eq_(len(successes),num_ops,'\n'+'\n'.join(fails))
b.demultiply()
# b will be slightly modified by pre and then de multiplication rounding errors
# TODO - write test to ensure the image is 99% the same.
#expected_b = mapnik.Image.open('./images/support/b.png')
#b.save('/tmp/mapnik-comp-op-test-original-mask.png')
#eq_(b.tostring('png32'),expected_b.tostring('png32'), '/tmp/mapnik-comp-op-test-original-mask.png is no longer equivalent to original mask: ./images/support/b.png')
def test_pre_multiply_status():
b = mapnik.Image.open('./images/support/b.png')
# not premultiplied yet, should appear that way
result = validate_pixels_are_not_premultiplied(b)
eq_(result,True)
# not yet premultiplied therefore should return false
result = validate_pixels_are_premultiplied(b)
eq_(result[0],False)
# now actually premultiply the pixels
b.premultiply()
# now checking if premultiplied should succeed
result = validate_pixels_are_premultiplied(b)
eq_(result[0],True)
# should now not appear to look not premultiplied
result = validate_pixels_are_not_premultiplied(b)
eq_(result,False)
# now actually demultiply the pixels
b.demultiply()
# should now appear demultiplied
result = validate_pixels_are_not_premultiplied(b)
eq_(result,True)
def test_pre_multiply_status_of_map1():
m = mapnik.Map(256,256)
im = mapnik.Image(m.width,m.height)
eq_(validate_pixels_are_not_premultiplied(im),True)
mapnik.render(m,im)
eq_(validate_pixels_are_not_premultiplied(im),True)
def test_pre_multiply_status_of_map2():
m = mapnik.Map(256,256)
m.background = mapnik.Color(1,1,1,255)
im = mapnik.Image(m.width,m.height)
eq_(validate_pixels_are_not_premultiplied(im),True)
mapnik.render(m,im)
eq_(validate_pixels_are_not_premultiplied(im),True)
if 'shape' in mapnik.DatasourceCache.plugin_names():
def test_style_level_comp_op():
m = mapnik.Map(256, 256)
mapnik.load_map(m, '../data/good_maps/style_level_comp_op.xml')
m.zoom_all()
successes = []
fails = []
for name in mapnik.CompositeOp.names:
# find_style returns a copy of the style object
style_markers = m.find_style("markers")
style_markers.comp_op = getattr(mapnik.CompositeOp, name)
# replace the original style with the modified one
replace_style(m, "markers", style_markers)
im = mapnik.Image(m.width, m.height)
mapnik.render(m, im)
actual = '/tmp/mapnik-style-comp-op-' + name + '.png'
expected = 'images/style-comp-op/' + name + '.png'
im.save(actual,'png32')
if not os.path.exists(expected) or os.environ.get('UPDATE'):
print 'generating expected test image: %s' % expected
im.save(expected,'png32')
expected_im = mapnik.Image.open(expected)
# compare them
if im.tostring('png32') == expected_im.tostring('png32'):
successes.append(name)
else:
fails.append('failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
fail_im = side_by_side_image(expected_im, im)
fail_im.save('/tmp/mapnik-style-comp-op-' + name + '.fail.png','png32')
eq_(len(fails), 0, '\n'+'\n'.join(fails))
def test_style_level_opacity():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/style_level_opacity_and_blur.xml')
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-style-level-opacity.png'
expected = 'images/support/mapnik-style-level-opacity.png'
im.save(actual,'png32')
expected_im = mapnik.Image.open(expected)
eq_(im.tostring('png32'),expected_im.tostring('png32'), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
def test_rounding_and_color_expectations():
m = mapnik.Map(1,1)
m.background = mapnik.Color('rgba(255,255,255,.4999999)')
im = mapnik.Image(m.width,m.height)
mapnik.render(m,im)
eq_(get_unique_colors(im),['rgba(255,255,255,127)'])
m = mapnik.Map(1,1)
m.background = mapnik.Color('rgba(255,255,255,.5)')
im = mapnik.Image(m.width,m.height)
mapnik.render(m,im)
eq_(get_unique_colors(im),['rgba(255,255,255,128)'])
im_file = mapnik.Image.open('../data/images/stripes_pattern.png')
eq_(get_unique_colors(im_file),['rgba(0,0,0,0)', 'rgba(74,74,74,255)'])
# should have no effect
im_file.premultiply()
eq_(get_unique_colors(im_file),['rgba(0,0,0,0)', 'rgba(74,74,74,255)'])
im_file.set_alpha(.5)
# should have effect now that image has transparency
im_file.premultiply()
eq_(get_unique_colors(im_file),['rgba(0,0,0,0)', 'rgba(37,37,37,127)'])
# should restore to original nonpremultiplied colors
im_file.demultiply()
eq_(get_unique_colors(im_file),['rgba(0,0,0,0)', 'rgba(74,74,74,127)'])
def test_background_image_and_background_color():
m = mapnik.Map(8,8)
m.background = mapnik.Color('rgba(255,255,255,.5)')
m.background_image = '../data/images/stripes_pattern.png'
im = mapnik.Image(m.width,m.height)
mapnik.render(m,im)
eq_(get_unique_colors(im),['rgba(255,255,255,128)', 'rgba(74,74,74,255)'])
def test_background_image_with_alpha_and_background_color():
m = mapnik.Map(10,10)
m.background = mapnik.Color('rgba(255,255,255,.5)')
m.background_image = '../data/images/yellow_half_trans.png'
im = mapnik.Image(m.width,m.height)
mapnik.render(m,im)
eq_(get_unique_colors(im),['rgba(255,255,85,191)'])
def test_background_image_with_alpha_and_background_color_against_composited_control():
m = mapnik.Map(10,10)
m.background = mapnik.Color('rgba(255,255,255,.5)')
m.background_image = '../data/images/yellow_half_trans.png'
im = mapnik.Image(m.width,m.height)
mapnik.render(m,im)
# create and composite the expected result
im1 = mapnik.Image(10,10)
im1.fill(mapnik.Color('rgba(255,255,255,.5)'))
im1.premultiply()
im2 = mapnik.Image(10,10)
im2.fill(mapnik.Color('rgba(255,255,0,.5)'))
im2.premultiply()
im1.composite(im2)
im1.demultiply()
# compare image rendered (compositing in `agg_renderer<T>::setup`)
# vs image composited via python bindings
#raise Todo("looks like we need to investigate PNG color rounding when saving")
#eq_(get_unique_colors(im),get_unique_colors(im1))
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,93 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, mapnik
from nose.tools import *
from utilities import execution_path, run_all
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_image_16_8_simple():
im = mapnik.Image(2,2,mapnik.ImageType.gray16)
im.set_pixel(0,0, 256)
im.set_pixel(0,1, 999)
im.set_pixel(1,0, 5)
im.set_pixel(1,1, 2)
im2 = im.copy(mapnik.ImageType.gray8)
eq_(im2.get_pixel(0,0), 255)
eq_(im2.get_pixel(0,1), 255)
eq_(im2.get_pixel(1,0), 5)
eq_(im2.get_pixel(1,1), 2)
# Cast back!
im = im2.copy(mapnik.ImageType.gray16)
eq_(im.get_pixel(0,0), 255)
eq_(im.get_pixel(0,1), 255)
eq_(im.get_pixel(1,0), 5)
eq_(im.get_pixel(1,1), 2)
def test_image_32f_8_simple():
im = mapnik.Image(2,2,mapnik.ImageType.gray32f)
im.set_pixel(0,0, 120.1234)
im.set_pixel(0,1, -23.4)
im.set_pixel(1,0, 120.6)
im.set_pixel(1,1, 360.2)
im2 = im.copy(mapnik.ImageType.gray8)
eq_(im2.get_pixel(0,0), 120)
eq_(im2.get_pixel(0,1), 0)
eq_(im2.get_pixel(1,0), 120) # Notice this is truncated!
eq_(im2.get_pixel(1,1), 255)
def test_image_offset_and_scale():
im = mapnik.Image(2,2,mapnik.ImageType.gray16)
eq_(im.offset, 0.0)
eq_(im.scaling, 1.0)
im.offset = 1.0
im.scaling = 2.0
eq_(im.offset, 1.0)
eq_(im.scaling, 2.0)
def test_image_16_8_scale_and_offset():
im = mapnik.Image(2,2,mapnik.ImageType.gray16)
im.set_pixel(0,0, 256)
im.set_pixel(0,1, 258)
im.set_pixel(1,0, 99999)
im.set_pixel(1,1, 615)
offset = 255
scaling = 3
im2 = im.copy(mapnik.ImageType.gray8, offset, scaling)
eq_(im2.get_pixel(0,0), 0)
eq_(im2.get_pixel(0,1), 1)
eq_(im2.get_pixel(1,0), 255)
eq_(im2.get_pixel(1,1), 120)
# pixels will be a little off due to offsets in reverting!
im3 = im2.copy(mapnik.ImageType.gray16)
eq_(im3.get_pixel(0,0), 255) # Rounding error with ints
eq_(im3.get_pixel(0,1), 258) # same
eq_(im3.get_pixel(1,0), 1020) # The other one was way out of range for our scale/offset
eq_(im3.get_pixel(1,1), 615) # same
def test_image_16_32f_scale_and_offset():
im = mapnik.Image(2,2,mapnik.ImageType.gray16)
im.set_pixel(0,0, 256)
im.set_pixel(0,1, 258)
im.set_pixel(1,0, 0)
im.set_pixel(1,1, 615)
offset = 255
scaling = 3.2
im2 = im.copy(mapnik.ImageType.gray32f, offset, scaling)
eq_(im2.get_pixel(0,0), 0.3125)
eq_(im2.get_pixel(0,1), 0.9375)
eq_(im2.get_pixel(1,0), -79.6875)
eq_(im2.get_pixel(1,1), 112.5)
im3 = im2.copy(mapnik.ImageType.gray16)
eq_(im3.get_pixel(0,0), 256)
eq_(im3.get_pixel(0,1), 258)
eq_(im3.get_pixel(1,0), 0)
eq_(im3.get_pixel(1,1), 615)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,605 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import glob
from nose.tools import eq_,raises
from utilities import execution_path
import os, mapnik
default_logging_severity = mapnik.logger.get_severity()
def setup():
# make the tests silent since we intentially test error conditions that are noisy
mapnik.logger.set_severity(mapnik.severity_type.None)
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def teardown():
mapnik.logger.set_severity(default_logging_severity)
if 'csv' in mapnik.DatasourceCache.plugin_names():
def get_csv_ds(filename):
return mapnik.Datasource(type='csv',file=os.path.join('../data/csv/',filename))
def test_broken_files(visual=False):
broken = glob.glob("../data/csv/fails/*.*")
broken.extend(glob.glob("../data/csv/warns/*.*"))
# Add a filename that doesn't exist
broken.append("../data/csv/fails/does_not_exist.csv")
for csv in broken:
if visual:
try:
mapnik.Datasource(type='csv',file=csv,strict=True)
print '\x1b[33mfailed: should have thrown\x1b[0m',csv
except Exception:
print '\x1b[1;32m✓ \x1b[0m', csv
def test_good_files(visual=False):
good_files = glob.glob("../data/csv/*.*")
good_files.extend(glob.glob("../data/csv/warns/*.*"))
ignorable = os.path.join('..','data','csv','long_lat.vrt')
good_files.remove(ignorable)
for csv in good_files:
if visual:
try:
mapnik.Datasource(type='csv',file=csv)
print '\x1b[1;32m✓ \x1b[0m', csv
except Exception, e:
print '\x1b[33mfailed: should not have thrown\x1b[0m',csv,str(e)
def test_lon_lat_detection(**kwargs):
ds = get_csv_ds('lon_lat.csv')
eq_(len(ds.fields()),2)
eq_(ds.fields(),['lon','lat'])
eq_(ds.field_types(),['int','int'])
query = mapnik.Query(ds.envelope())
for fld in ds.fields():
query.add_property_name(fld)
fs = ds.features(query)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
feat = fs.next()
attr = {'lon': 0, 'lat': 0}
eq_(feat.attributes,attr)
def test_lng_lat_detection(**kwargs):
ds = get_csv_ds('lng_lat.csv')
eq_(len(ds.fields()),2)
eq_(ds.fields(),['lng','lat'])
eq_(ds.field_types(),['int','int'])
query = mapnik.Query(ds.envelope())
for fld in ds.fields():
query.add_property_name(fld)
fs = ds.features(query)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
feat = fs.next()
attr = {'lng': 0, 'lat': 0}
eq_(feat.attributes,attr)
def test_type_detection(**kwargs):
ds = get_csv_ds('nypd.csv')
eq_(ds.fields(),['Precinct','Phone','Address','City','geo_longitude','geo_latitude','geo_accuracy'])
eq_(ds.field_types(),['str','str','str','str','float','float','str'])
feat = ds.featureset().next()
attr = {'City': u'New York, NY', 'geo_accuracy': u'house', 'Phone': u'(212) 334-0711', 'Address': u'19 Elizabeth Street', 'Precinct': u'5th Precinct', 'geo_longitude': -70, 'geo_latitude': 40}
eq_(feat.attributes,attr)
eq_(len(ds.all_features()),2)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_skipping_blank_rows(**kwargs):
ds = get_csv_ds('blank_rows.csv')
eq_(ds.fields(),['x','y','name'])
eq_(ds.field_types(),['int','int','str'])
eq_(len(ds.all_features()),2)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_empty_rows(**kwargs):
ds = get_csv_ds('empty_rows.csv')
eq_(len(ds.fields()),10)
eq_(len(ds.field_types()),10)
eq_(ds.fields(),['x', 'y', 'text', 'date', 'integer', 'boolean', 'float', 'time', 'datetime', 'empty_column'])
eq_(ds.field_types(),['int', 'int', 'str', 'str', 'int', 'bool', 'float', 'str', 'str', 'str'])
fs = ds.featureset()
attr = {'x': 0, 'empty_column': u'', 'text': u'a b', 'float': 1.0, 'datetime': u'1971-01-01T04:14:00', 'y': 0, 'boolean': True, 'time': u'04:14:00', 'date': u'1971-01-01', 'integer': 40}
first = True
for feat in fs:
if first:
first=False
eq_(feat.attributes,attr)
eq_(len(feat),10)
eq_(feat['empty_column'],u'')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_slashes(**kwargs):
ds = get_csv_ds('has_attributes_with_slashes.csv')
eq_(len(ds.fields()),3)
fs = ds.all_features()
eq_(fs[0].attributes,{'x':0,'y':0,'name':u'a/a'})
eq_(fs[1].attributes,{'x':1,'y':4,'name':u'b/b'})
eq_(fs[2].attributes,{'x':10,'y':2.5,'name':u'c/c'})
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_wkt_field(**kwargs):
ds = get_csv_ds('wkt.csv')
eq_(len(ds.fields()),1)
eq_(ds.fields(),['type'])
eq_(ds.field_types(),['str'])
fs = ds.all_features()
#eq_(len(fs[0].geometries()),1)
eq_(fs[0].geometry.type(),mapnik.GeometryType.Point)
#eq_(len(fs[1].geometries()),1)
eq_(fs[1].geometry.type(),mapnik.GeometryType.LineString)
#eq_(len(fs[2].geometries()),1)
eq_(fs[2].geometry.type(),mapnik.GeometryType.Polygon)
#eq_(len(fs[3].geometries()),1) # one geometry, two parts
eq_(fs[3].geometry.type(),mapnik.GeometryType.Polygon)
#eq_(len(fs[4].geometries()),4)
eq_(fs[4].geometry.type(),mapnik.GeometryType.MultiPoint)
#eq_(len(fs[5].geometries()),2)
eq_(fs[5].geometry.type(),mapnik.GeometryType.MultiLineString)
#eq_(len(fs[6].geometries()),2)
eq_(fs[6].geometry.type(),mapnik.GeometryType.MultiPolygon)
#eq_(len(fs[7].geometries()),2)
eq_(fs[7].geometry.type(),mapnik.GeometryType.MultiPolygon)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Collection)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_handling_of_missing_header(**kwargs):
ds = get_csv_ds('missing_header.csv')
eq_(len(ds.fields()),6)
eq_(ds.fields(),['one','two','x','y','_4','aftermissing'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['_4'],'missing')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_handling_of_headers_that_are_numbers(**kwargs):
ds = get_csv_ds('numbers_for_headers.csv')
eq_(len(ds.fields()),5)
eq_(ds.fields(),['x','y','1990','1991','1992'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['1990'],1)
eq_(feat['1991'],2)
eq_(feat['1992'],3)
eq_(mapnik.Expression("[1991]=2").evaluate(feat),True)
def test_quoted_numbers(**kwargs):
ds = get_csv_ds('points.csv')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','label'])
fs = ds.all_features()
eq_(fs[0]['label'],"0,0")
eq_(fs[1]['label'],"5,5")
eq_(fs[2]['label'],"0,5")
eq_(fs[3]['label'],"5,0")
eq_(fs[4]['label'],"2.5,2.5")
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_reading_windows_newlines(**kwargs):
ds = get_csv_ds('windows_newlines.csv')
eq_(len(ds.fields()),3)
feats = ds.all_features()
eq_(len(feats),1)
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],1)
eq_(feat['y'],10)
eq_(feat['z'],9999.9999)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_reading_mac_newlines(**kwargs):
ds = get_csv_ds('mac_newlines.csv')
eq_(len(ds.fields()),3)
feats = ds.all_features()
eq_(len(feats),1)
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],1)
eq_(feat['y'],10)
eq_(feat['z'],9999.9999)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def check_newlines(filename):
ds = get_csv_ds(filename)
eq_(len(ds.fields()),3)
feats = ds.all_features()
eq_(len(feats),1)
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['line'],'many\n lines\n of text\n with unix newlines')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_mixed_mac_unix_newlines(**kwargs):
check_newlines('mac_newlines_with_unix_inline.csv')
def test_mixed_mac_unix_newlines_escaped(**kwargs):
check_newlines('mac_newlines_with_unix_inline_escaped.csv')
# To hard to support this case
#def test_mixed_unix_windows_newlines(**kwargs):
# check_newlines('unix_newlines_with_windows_inline.csv')
# To hard to support this case
#def test_mixed_unix_windows_newlines_escaped(**kwargs):
# check_newlines('unix_newlines_with_windows_inline_escaped.csv')
def test_mixed_windows_unix_newlines(**kwargs):
check_newlines('windows_newlines_with_unix_inline.csv')
def test_mixed_windows_unix_newlines_escaped(**kwargs):
check_newlines('windows_newlines_with_unix_inline_escaped.csv')
def test_tabs(**kwargs):
ds = get_csv_ds('tabs_in_csv.csv')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','z'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],-122)
eq_(feat['y'],48)
eq_(feat['z'],0)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_separator_pipes(**kwargs):
ds = get_csv_ds('pipe_delimiters.csv')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','z'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['z'],'hello')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_separator_semicolon(**kwargs):
ds = get_csv_ds('semicolon_delimiters.csv')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','z'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['z'],'hello')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_that_null_and_bool_keywords_are_empty_strings(**kwargs):
ds = get_csv_ds('nulls_and_booleans_as_strings.csv')
eq_(len(ds.fields()),4)
eq_(ds.fields(),['x','y','null','boolean'])
eq_(ds.field_types(),['int', 'int', 'str', 'bool'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['null'],'null')
eq_(feat['boolean'],True)
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['null'],'')
eq_(feat['boolean'],False)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
@raises(RuntimeError)
def test_that_nonexistant_query_field_throws(**kwargs):
ds = get_csv_ds('lon_lat.csv')
eq_(len(ds.fields()),2)
eq_(ds.fields(),['lon','lat'])
eq_(ds.field_types(),['int','int'])
query = mapnik.Query(ds.envelope())
for fld in ds.fields():
query.add_property_name(fld)
# also add an invalid one, triggering throw
query.add_property_name('bogus')
ds.features(query)
def test_that_leading_zeros_mean_strings(**kwargs):
ds = get_csv_ds('leading_zeros.csv')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','fips'])
eq_(ds.field_types(),['int','int','str'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['fips'],'001')
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['fips'],'003')
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['fips'],'005')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
def test_advanced_geometry_detection(**kwargs):
ds = get_csv_ds('point_wkt.csv')
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Point)
ds = get_csv_ds('poly_wkt.csv')
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Polygon)
ds = get_csv_ds('multi_poly_wkt.csv')
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Polygon)
ds = get_csv_ds('line_wkt.csv')
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.LineString)
def test_creation_of_csv_from_in_memory_string(**kwargs):
csv_string = '''
wkt,Name
"POINT (120.15 48.47)","Winthrop, WA"
''' # csv plugin will test lines <= 10 chars for being fully blank
ds = mapnik.Datasource(**{"type":"csv","inline":csv_string})
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Point)
fs = ds.featureset()
feat = fs.next()
eq_(feat['Name'],u"Winthrop, WA")
def test_creation_of_csv_from_in_memory_string_with_uft8(**kwargs):
csv_string = '''
wkt,Name
"POINT (120.15 48.47)","Québec"
''' # csv plugin will test lines <= 10 chars for being fully blank
ds = mapnik.Datasource(**{"type":"csv","inline":csv_string})
eq_(ds.describe()['geometry_type'],mapnik.DataGeometryType.Point)
fs = ds.featureset()
feat = fs.next()
eq_(feat['Name'],u"Québec")
def validate_geojson_datasource(ds):
eq_(len(ds.fields()),1)
eq_(ds.fields(),['type'])
eq_(ds.field_types(),['str'])
fs = ds.all_features()
#eq_(len(fs[0].geometries()),1)
eq_(fs[0].geometry.type(),mapnik.GeometryType.Point)
#eq_(len(fs[1].geometries()),1)
eq_(fs[1].geometry.type(),mapnik.GeometryType.LineString)
#eq_(len(fs[2].geometries()),1)
eq_(fs[2].geometry.type(), mapnik.GeometryType.Polygon)
#eq_(len(fs[3].geometries()),1) # one geometry, two parts
eq_(fs[3].geometry.type(),mapnik.GeometryType.Polygon)
#eq_(len(fs[4].geometries()),4)
eq_(fs[4].geometry.type(),mapnik.GeometryType.MultiPoint)
#eq_(len(fs[5].geometries()),2)
eq_(fs[5].geometry.type(),mapnik.GeometryType.MultiLineString)
#eq_(len(fs[6].geometries()),2)
eq_(fs[6].geometry.type(),mapnik.GeometryType.MultiPolygon)
#eq_(len(fs[7].geometries()),2)
eq_(fs[7].geometry.type(),mapnik.GeometryType.MultiPolygon)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Collection)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_json_field1(**kwargs):
ds = get_csv_ds('geojson_double_quote_escape.csv')
validate_geojson_datasource(ds)
def test_json_field2(**kwargs):
ds = get_csv_ds('geojson_single_quote.csv')
validate_geojson_datasource(ds)
def test_json_field3(**kwargs):
ds = get_csv_ds('geojson_2x_double_quote_filebakery_style.csv')
validate_geojson_datasource(ds)
def test_that_blank_undelimited_rows_are_still_parsed(**kwargs):
ds = get_csv_ds('more_headers_than_column_values.csv')
eq_(len(ds.fields()),5)
eq_(ds.fields(),['x','y','one', 'two','three'])
eq_(ds.field_types(),['int','int','str','str','str'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['one'],'')
eq_(feat['two'],'')
eq_(feat['three'],'')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
@raises(RuntimeError)
def test_that_fewer_headers_than_rows_throws(**kwargs):
# this has invalid header # so throw
get_csv_ds('more_column_values_than_headers.csv')
def test_that_feature_id_only_incremented_for_valid_rows(**kwargs):
ds = mapnik.Datasource(type='csv',
file=os.path.join('../data/csv/warns','feature_id_counting.csv'))
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','id'])
eq_(ds.field_types(),['int','int','int'])
fs = ds.featureset()
# first
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['id'],1)
# second, should have skipped bogus one
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['id'],2)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(len(ds.all_features()),2)
def test_dynamically_defining_headers1(**kwargs):
ds = mapnik.Datasource(type='csv',
file=os.path.join('../data/csv/fails','needs_headers_two_lines.csv'),
headers='x,y,name')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','name'])
eq_(ds.field_types(),['int','int','str'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['name'],'data_name')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(len(ds.all_features()),2)
def test_dynamically_defining_headers2(**kwargs):
ds = mapnik.Datasource(type='csv',
file=os.path.join('../data/csv/fails','needs_headers_one_line.csv'),
headers='x,y,name')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','name'])
eq_(ds.field_types(),['int','int','str'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['name'],'data_name')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(len(ds.all_features()),1)
def test_dynamically_defining_headers3(**kwargs):
ds = mapnik.Datasource(type='csv',
file=os.path.join('../data/csv/fails','needs_headers_one_line_no_newline.csv'),
headers='x,y,name')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','name'])
eq_(ds.field_types(),['int','int','str'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['name'],'data_name')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(len(ds.all_features()),1)
def test_that_64bit_int_fields_work(**kwargs):
ds = get_csv_ds('64bit_int.csv')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','bigint'])
eq_(ds.field_types(),['int','int','int'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['bigint'],2147483648)
feat = fs.next()
eq_(feat['bigint'],9223372036854775807)
eq_(feat['bigint'],0x7FFFFFFFFFFFFFFF)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(len(ds.all_features()),2)
def test_various_number_types(**kwargs):
ds = get_csv_ds('number_types.csv')
eq_(len(ds.fields()),3)
eq_(ds.fields(),['x','y','floats'])
eq_(ds.field_types(),['int','int','float'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['floats'],.0)
feat = fs.next()
eq_(feat['floats'],+.0)
feat = fs.next()
eq_(feat['floats'],1e-06)
feat = fs.next()
eq_(feat['floats'],-1e-06)
feat = fs.next()
eq_(feat['floats'],0.000001)
feat = fs.next()
eq_(feat['floats'],1.234e+16)
feat = fs.next()
eq_(feat['floats'],1.234e+16)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(len(ds.all_features()),8)
def test_manually_supplied_extent(**kwargs):
csv_string = '''
wkt,Name
'''
ds = mapnik.Datasource(**{"type":"csv","extent":"-180,-90,180,90","inline":csv_string})
b = ds.envelope()
eq_(b.minx,-180)
eq_(b.miny,-90)
eq_(b.maxx,180)
eq_(b.maxy,90)
def test_inline_geojson(**kwargs):
csv_string = "geojson\n'{\"coordinates\":[-92.22568,38.59553],\"type\":\"Point\"}'"
ds = mapnik.Datasource(**{"type":"csv","inline":csv_string})
eq_(len(ds.fields()),0)
eq_(ds.fields(),[])
# FIXME - re-enable after https://github.com/mapnik/mapnik/issues/2319 is fixed
#fs = ds.featureset()
#feat = fs.next()
#eq_(feat.num_geometries(),1)
if __name__ == "__main__":
setup()
[eval(run)(visual=True) for run in dir() if 'test_' in run]

View file

@ -1,168 +0,0 @@
#!/usr/bin/env python
from nose.tools import eq_, raises
from utilities import execution_path, run_all
import os, mapnik
from itertools import groupby
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_that_datasources_exist():
if len(mapnik.DatasourceCache.plugin_names()) == 0:
print '***NOTICE*** - no datasource plugins have been loaded'
# adapted from raster_symboliser_test#test_dataraster_query_point
@raises(RuntimeError)
def test_vrt_referring_to_missing_files():
srs = '+init=epsg:32630'
if 'gdal' in mapnik.DatasourceCache.plugin_names():
lyr = mapnik.Layer('dataraster')
lyr.datasource = mapnik.Gdal(
file = '../data/raster/missing_raster.vrt',
band = 1,
)
lyr.srs = srs
_map = mapnik.Map(256, 256, srs)
_map.layers.append(lyr)
# center of extent of raster
x, y = 556113.0,4381428.0 # center of extent of raster
_map.zoom_all()
# Fancy stuff to supress output of error
# open 2 fds
null_fds = [os.open(os.devnull, os.O_RDWR) for x in xrange(2)]
# save the current file descriptors to a tuple
save = os.dup(1), os.dup(2)
# put /dev/null fds on 1 and 2
os.dup2(null_fds[0], 1)
os.dup2(null_fds[1], 2)
# *** run the function ***
try:
# Should RuntimeError here
_map.query_point(0, x, y).features
finally:
# restore file descriptors so I can print the results
os.dup2(save[0], 1)
os.dup2(save[1], 2)
# close the temporary fds
os.close(null_fds[0])
os.close(null_fds[1])
def test_field_listing():
if 'shape' in mapnik.DatasourceCache.plugin_names():
ds = mapnik.Shapefile(file='../data/shp/poly.shp')
fields = ds.fields()
eq_(fields, ['AREA', 'EAS_ID', 'PRFEDEA'])
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Polygon)
eq_(desc['name'],'shape')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_total_feature_count_shp():
if 'shape' in mapnik.DatasourceCache.plugin_names():
ds = mapnik.Shapefile(file='../data/shp/poly.shp')
features = ds.all_features()
num_feats = len(features)
eq_(num_feats, 10)
def test_total_feature_count_json():
if 'ogr' in mapnik.DatasourceCache.plugin_names():
ds = mapnik.Ogr(file='../data/json/points.geojson',layer_by_index=0)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(desc['name'],'ogr')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
features = ds.all_features()
num_feats = len(features)
eq_(num_feats, 5)
def test_sqlite_reading():
if 'sqlite' in mapnik.DatasourceCache.plugin_names():
ds = mapnik.SQLite(file='../data/sqlite/world.sqlite',table_by_index=0)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Polygon)
eq_(desc['name'],'sqlite')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
features = ds.all_features()
num_feats = len(features)
eq_(num_feats, 245)
def test_reading_json_from_string():
json = open('../data/json/points.geojson','r').read()
if 'ogr' in mapnik.DatasourceCache.plugin_names():
ds = mapnik.Ogr(file=json,layer_by_index=0)
features = ds.all_features()
num_feats = len(features)
eq_(num_feats, 5)
def test_feature_envelope():
if 'shape' in mapnik.DatasourceCache.plugin_names():
ds = mapnik.Shapefile(file='../data/shp/poly.shp')
features = ds.all_features()
for feat in features:
env = feat.envelope()
contains = ds.envelope().contains(env)
eq_(contains, True)
intersects = ds.envelope().contains(env)
eq_(intersects, True)
def test_feature_attributes():
if 'shape' in mapnik.DatasourceCache.plugin_names():
ds = mapnik.Shapefile(file='../data/shp/poly.shp')
features = ds.all_features()
feat = features[0]
attrs = {'PRFEDEA': u'35043411', 'EAS_ID': 168, 'AREA': 215229.266}
eq_(feat.attributes, attrs)
eq_(ds.fields(),['AREA', 'EAS_ID', 'PRFEDEA'])
eq_(ds.field_types(),['float','int','str'])
def test_ogr_layer_by_sql():
if 'ogr' in mapnik.DatasourceCache.plugin_names():
ds = mapnik.Ogr(file='../data/shp/poly.shp', layer_by_sql='SELECT * FROM poly WHERE EAS_ID = 168')
features = ds.all_features()
num_feats = len(features)
eq_(num_feats, 1)
def test_hit_grid():
def rle_encode(l):
""" encode a list of strings with run-length compression """
return ["%d:%s" % (len(list(group)), name) for name, group in groupby(l)]
m = mapnik.Map(256,256);
try:
mapnik.load_map(m,'../data/good_maps/agg_poly_gamma_map.xml');
m.zoom_all()
join_field = 'NAME'
fg = [] # feature grid
for y in range(0, 256, 4):
for x in range(0, 256, 4):
featureset = m.query_map_point(0,x,y)
added = False
for feature in featureset.features:
fg.append(feature[join_field])
added = True
if not added:
fg.append('')
hit_list = '|'.join(rle_encode(fg))
eq_(hit_list[:16],'730:|2:Greenland')
eq_(hit_list[-12:],'1:Chile|812:')
except RuntimeError, e:
# only test datasources that we have installed
if not 'Could not create datasource' in str(e):
raise RuntimeError(str(e))
if __name__ == '__main__':
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,23 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from utilities import execution_path, run_all
import mapnik
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_datasource_template_is_working():
m = mapnik.Map(256,256)
try:
mapnik.load_map(m,'../data/good_maps/datasource.xml')
except RuntimeError, e:
if "Required parameter 'type'" in str(e):
raise RuntimeError(e)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,54 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from nose.tools import eq_
from utilities import execution_path, run_all
import os, mapnik
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_arbitrary_parameters_attached_to_map():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/extra_arbitary_map_parameters.xml')
eq_(len(m.parameters),5)
eq_(m.parameters['key'],'value2')
eq_(m.parameters['key3'],'value3')
eq_(m.parameters['unicode'],u'iván')
eq_(m.parameters['integer'],10)
eq_(m.parameters['decimal'],.999)
m2 = mapnik.Map(256,256)
for k,v in m.parameters:
m2.parameters.append(mapnik.Parameter(k,v))
eq_(len(m2.parameters),5)
eq_(m2.parameters['key'],'value2')
eq_(m2.parameters['key3'],'value3')
eq_(m2.parameters['unicode'],u'iván')
eq_(m2.parameters['integer'],10)
eq_(m2.parameters['decimal'],.999)
map_string = mapnik.save_map_to_string(m)
m3 = mapnik.Map(256,256)
mapnik.load_map_from_string(m3,map_string)
eq_(len(m3.parameters),5)
eq_(m3.parameters['key'],'value2')
eq_(m3.parameters['key3'],'value3')
eq_(m3.parameters['unicode'],u'iván')
eq_(m3.parameters['integer'],10)
eq_(m3.parameters['decimal'],.999)
def test_serializing_arbitrary_parameters():
m = mapnik.Map(256,256)
m.parameters.append(mapnik.Parameter('width',m.width))
m.parameters.append(mapnik.Parameter('height',m.height))
m2 = mapnik.Map(1,1)
mapnik.load_map_from_string(m2,mapnik.save_map_to_string(m))
eq_(m2.parameters['width'],m.width)
eq_(m2.parameters['height'],m.height)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,66 +0,0 @@
#!/usr/bin/env python
from nose.tools import eq_
from utilities import execution_path, run_all
import os, mapnik
import itertools
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def compare_shape_between_mapnik_and_ogr(shapefile,query=None):
plugins = mapnik.DatasourceCache.plugin_names()
if 'shape' in plugins and 'ogr' in plugins:
ds1 = mapnik.Ogr(file=shapefile,layer_by_index=0)
ds2 = mapnik.Shapefile(file=shapefile)
if query:
fs1 = ds1.features(query)
fs2 = ds2.features(query)
else:
fs1 = ds1.featureset()
fs2 = ds2.featureset()
count = 0;
for feat1,feat2 in itertools.izip(fs1,fs2):
count += 1
eq_(feat1.id(),feat2.id(),
'%s : ogr feature id %s "%s" does not equal shapefile feature id %s "%s"'
% (count,feat1.id(),str(feat1.attributes), feat2.id(),str(feat2.attributes)))
return True
def test_shapefile_line_featureset_id():
compare_shape_between_mapnik_and_ogr('../data/shp/polylines.shp')
def test_shapefile_polygon_featureset_id():
compare_shape_between_mapnik_and_ogr('../data/shp/poly.shp')
def test_shapefile_polygon_feature_query_id():
bbox = (15523428.2632, 4110477.6323, -11218494.8310, 7495720.7404)
query = mapnik.Query(mapnik.Box2d(*bbox))
if 'ogr' in mapnik.DatasourceCache.plugin_names():
ds = mapnik.Ogr(file='../data/shp/world_merc.shp',layer_by_index=0)
for fld in ds.fields():
query.add_property_name(fld)
compare_shape_between_mapnik_and_ogr('../data/shp/world_merc.shp',query)
def test_feature_hit_count():
pass
#raise Todo("need to optimize multigeom bbox handling in shapeindex: https://github.com/mapnik/mapnik/issues/783")
# results in different results between shp and ogr!
#bbox = (-14284551.8434, 2074195.1992, -7474929.8687, 8140237.7628)
#bbox = (1113194.91,4512803.085,2226389.82,6739192.905)
#query = mapnik.Query(mapnik.Box2d(*bbox))
#if 'ogr' in mapnik.DatasourceCache.plugin_names():
# ds1 = mapnik.Ogr(file='../data/shp/world_merc.shp',layer_by_index=0)
# for fld in ds1.fields():
# query.add_property_name(fld)
# ds2 = mapnik.Shapefile(file='../data/shp/world_merc.shp')
# count1 = len(ds1.features(query).features)
# count2 = len(ds2.features(query).features)
# eq_(count1,count2,"Feature count differs between OGR driver (%s features) and Shapefile Driver (%s features) when querying the same bbox" % (count1,count2))
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,110 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from nose.tools import eq_,raises
from utilities import run_all
import mapnik
from binascii import unhexlify
def test_default_constructor():
f = mapnik.Feature(mapnik.Context(),1)
eq_(f is not None,True)
def test_feature_geo_interface():
ctx = mapnik.Context()
feat = mapnik.Feature(ctx,1)
feat.geometry = mapnik.Geometry.from_wkt('Point (0 0)')
eq_(feat.__geo_interface__['geometry'],{u'type': u'Point', u'coordinates': [0, 0]})
def test_python_extended_constructor():
context = mapnik.Context()
context.push('foo')
context.push('foo')
f = mapnik.Feature(context,1)
wkt = 'POLYGON ((35 10, 10 20, 15 40, 45 45, 35 10),(20 30, 35 35, 30 20, 20 30))'
f.geometry = mapnik.Geometry.from_wkt(wkt)
f['foo'] = 'bar'
eq_(f['foo'], 'bar')
eq_(f.envelope(),mapnik.Box2d(10.0,10.0,45.0,45.0))
# reset
f['foo'] = u"avión"
eq_(f['foo'], u"avión")
f['foo'] = 1.4
eq_(f['foo'], 1.4)
f['foo'] = True
eq_(f['foo'], True)
def test_add_geom_wkb():
# POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))
wkb = '010300000001000000050000000000000000003e4000000000000024400000000000002440000000000000344000000000000034400000000000004440000000000000444000000000000044400000000000003e400000000000002440'
geometry = mapnik.Geometry.from_wkb(unhexlify(wkb))
eq_(geometry.is_valid(), False) # False because winding order is wrong according to OGC or because end point != first point
eq_(geometry.is_simple(), True)
eq_(geometry.envelope(), mapnik.Box2d(10.0,10.0,40.0,40.0))
geometry.correct()
# valid after calling correct
eq_(geometry.is_valid(), True)
def test_feature_expression_evaluation():
context = mapnik.Context()
context.push('name')
f = mapnik.Feature(context,1)
f['name'] = 'a'
eq_(f['name'],u'a')
expr = mapnik.Expression("[name]='a'")
evaluated = expr.evaluate(f)
eq_(evaluated,True)
num_attributes = len(f)
eq_(num_attributes,1)
eq_(f.id(),1)
# https://github.com/mapnik/mapnik/issues/933
def test_feature_expression_evaluation_missing_attr():
context = mapnik.Context()
context.push('name')
f = mapnik.Feature(context,1)
f['name'] = u'a'
eq_(f['name'],u'a')
expr = mapnik.Expression("[fielddoesnotexist]='a'")
eq_(f.has_key('fielddoesnotexist'),False)
try:
expr.evaluate(f)
except Exception, e:
eq_("Key does not exist" in str(e),True)
num_attributes = len(f)
eq_(num_attributes,1)
eq_(f.id(),1)
# https://github.com/mapnik/mapnik/issues/934
def test_feature_expression_evaluation_attr_with_spaces():
context = mapnik.Context()
context.push('name with space')
f = mapnik.Feature(context,1)
f['name with space'] = u'a'
eq_(f['name with space'],u'a')
expr = mapnik.Expression("[name with space]='a'")
eq_(str(expr),"([name with space]='a')")
eq_(expr.evaluate(f),True)
# https://github.com/mapnik/mapnik/issues/2390
@raises(RuntimeError)
def test_feature_from_geojson():
ctx = mapnik.Context()
inline_string = """
{
"geometry" : {
"coordinates" : [ 0,0 ]
"type" : "Point"
},
"type" : "Feature",
"properties" : {
"this":"that"
"known":"nope because missing comma"
}
}
"""
mapnik.Feature.from_geojson(inline_string,ctx)
if __name__ == "__main__":
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,451 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from nose.tools import eq_,raises
from utilities import run_all
import mapnik
if hasattr(mapnik,'Expression'):
mapnik.Filter = mapnik.Expression
map_ = '''<Map>
<Style name="s">
<Rule>
<Filter><![CDATA[(([region]>=0) and ([region]<=50))]]></Filter>
</Rule>
<Rule>
<Filter><![CDATA[([region]>=0) and ([region]<=50)]]></Filter>
</Rule>
<Rule>
<Filter>
<![CDATA[
([region] >= 0)
and
([region] <= 50)
]]>
</Filter>
</Rule>
<Rule>
<Filter>([region]&gt;=0) and ([region]&lt;=50)</Filter>
</Rule>
<Rule>
<Filter>
([region] &gt;= 0)
and
([region] &lt;= 50)
</Filter>
</Rule>
</Style>
<Style name="s2" filter-mode="first">
<Rule>
</Rule>
<Rule>
</Rule>
</Style>
</Map>'''
def test_filter_init():
m = mapnik.Map(1,1)
mapnik.load_map_from_string(m,map_)
filters = []
filters.append(mapnik.Filter("([region]>=0) and ([region]<=50)"))
filters.append(mapnik.Filter("(([region]>=0) and ([region]<=50))"))
filters.append(mapnik.Filter("((([region]>=0) and ([region]<=50)))"))
filters.append(mapnik.Filter('((([region]>=0) and ([region]<=50)))'))
filters.append(mapnik.Filter('''((([region]>=0) and ([region]<=50)))'''))
filters.append(mapnik.Filter('''
((([region]>=0)
and
([region]<=50)))
'''))
filters.append(mapnik.Filter('''
([region]>=0)
and
([region]<=50)
'''))
filters.append(mapnik.Filter('''
([region]
>=
0)
and
([region]
<=
50)
'''))
s = m.find_style('s')
for r in s.rules:
filters.append(r.filter)
first = filters[0]
for f in filters:
eq_(str(first),str(f))
s = m.find_style('s2')
eq_(s.filter_mode,mapnik.filter_mode.FIRST)
def test_geometry_type_eval():
# clashing field called 'mapnik::geometry'
context2 = mapnik.Context()
context2.push('mapnik::geometry_type')
f = mapnik.Feature(context2,0)
f["mapnik::geometry_type"] = 'sneaky'
expr = mapnik.Expression("[mapnik::geometry_type]")
eq_(expr.evaluate(f),0)
expr = mapnik.Expression("[mapnik::geometry_type]")
context = mapnik.Context()
# no geometry
f = mapnik.Feature(context,0)
eq_(expr.evaluate(f),0)
eq_(mapnik.Expression("[mapnik::geometry_type]=0").evaluate(f),True)
# POINT = 1
f = mapnik.Feature(context,0)
f.geometry = mapnik.Geometry.from_wkt('POINT(10 40)')
eq_(expr.evaluate(f),1)
eq_(mapnik.Expression("[mapnik::geometry_type]=point").evaluate(f),True)
# LINESTRING = 2
f = mapnik.Feature(context,0)
f.geometry = mapnik.Geometry.from_wkt('LINESTRING (30 10, 10 30, 40 40)')
eq_(expr.evaluate(f),2)
eq_(mapnik.Expression("[mapnik::geometry_type] = linestring").evaluate(f),True)
# POLYGON = 3
f = mapnik.Feature(context,0)
f.geometry = mapnik.Geometry.from_wkt('POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))')
eq_(expr.evaluate(f),3)
eq_(mapnik.Expression("[mapnik::geometry_type] = polygon").evaluate(f),True)
# COLLECTION = 4
f = mapnik.Feature(context,0)
geom = mapnik.Geometry.from_wkt('GEOMETRYCOLLECTION(POLYGON((1 1,2 1,2 2,1 2,1 1)),POINT(2 3),LINESTRING(2 3,3 4))')
f.geometry = geom;
eq_(expr.evaluate(f),4)
eq_(mapnik.Expression("[mapnik::geometry_type] = collection").evaluate(f),True)
def test_regex_match():
context = mapnik.Context()
context.push('name')
f = mapnik.Feature(context,0)
f["name"] = 'test'
expr = mapnik.Expression("[name].match('test')")
eq_(expr.evaluate(f),True) # 1 == True
def test_unicode_regex_match():
context = mapnik.Context()
context.push('name')
f = mapnik.Feature(context,0)
f["name"] = 'Québec'
expr = mapnik.Expression("[name].match('Québec')")
eq_(expr.evaluate(f),True) # 1 == True
def test_regex_replace():
context = mapnik.Context()
context.push('name')
f = mapnik.Feature(context,0)
f["name"] = 'test'
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
eq_(expr.evaluate(f),'t e s t')
def test_unicode_regex_replace_to_str():
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
eq_(str(expr),"[name].replace('(\B)|( )','$1 ')")
def test_unicode_regex_replace():
context = mapnik.Context()
context.push('name')
f = mapnik.Feature(context,0)
f["name"] = 'Québec'
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
# will fail if -DBOOST_REGEX_HAS_ICU is not defined
eq_(expr.evaluate(f), u'Q u é b e c')
def test_float_precision():
context = mapnik.Context()
context.push('num')
f = mapnik.Feature(context,0)
f["num1"] = 1.0000
f["num2"] = 1.0001
eq_(f["num1"],1.0000)
eq_(f["num2"],1.0001)
expr = mapnik.Expression("[num1] = 1.0000")
eq_(expr.evaluate(f),True)
expr = mapnik.Expression("[num1].match('1')")
eq_(expr.evaluate(f),True)
expr = mapnik.Expression("[num2] = 1.0001")
eq_(expr.evaluate(f),True)
expr = mapnik.Expression("[num2].match('1.0001')")
eq_(expr.evaluate(f),True)
def test_string_matching_on_precision():
context = mapnik.Context()
context.push('num')
f = mapnik.Feature(context,0)
f["num"] = "1.0000"
eq_(f["num"],"1.0000")
expr = mapnik.Expression("[num].match('.*(^0|00)$')")
eq_(expr.evaluate(f),True)
def test_creation_of_null_value():
context = mapnik.Context()
context.push('nv')
f = mapnik.Feature(context,0)
f["nv"] = None
eq_(f["nv"],None)
eq_(f["nv"] is None,True)
# test boolean
f["nv"] = 0
eq_(f["nv"],0)
eq_(f["nv"] is not None,True)
def test_creation_of_bool():
context = mapnik.Context()
context.push('bool')
f = mapnik.Feature(context,0)
f["bool"] = True
eq_(f["bool"],True)
# TODO - will become int of 1 do to built in boost python conversion
# https://github.com/mapnik/mapnik/issues/1873
eq_(isinstance(f["bool"],bool) or isinstance(f["bool"],long),True)
f["bool"] = False
eq_(f["bool"],False)
eq_(isinstance(f["bool"],bool) or isinstance(f["bool"],long),True)
# test NoneType
f["bool"] = None
eq_(f["bool"],None)
eq_(isinstance(f["bool"],bool) or isinstance(f["bool"],long),False)
# test integer
f["bool"] = 0
eq_(f["bool"],0)
# https://github.com/mapnik/mapnik/issues/1873
# ugh, boost_python's built into converter does not work right
#eq_(isinstance(f["bool"],bool),False)
null_equality = [
['hello',False,unicode],
[u'',False,unicode],
[0,False,long],
[123,False,long],
[0.0,False,float],
[123.123,False,float],
[.1,False,float],
[False,False,long], # TODO - should become bool: https://github.com/mapnik/mapnik/issues/1873
[True,False,long], # TODO - should become bool: https://github.com/mapnik/mapnik/issues/1873
[None,True,None],
[2147483648,False,long],
[922337203685477580,False,long]
]
def test_expressions_with_null_equality():
for eq in null_equality:
context = mapnik.Context()
f = mapnik.Feature(context,0)
f["prop"] = eq[0]
eq_(f["prop"],eq[0])
if eq[0] is None:
eq_(f["prop"] is None, True)
else:
eq_(isinstance(f['prop'],eq[2]),True,'%s is not an instance of %s' % (f['prop'],eq[2]))
expr = mapnik.Expression("[prop] = null")
eq_(expr.evaluate(f),eq[1])
expr = mapnik.Expression("[prop] is null")
eq_(expr.evaluate(f),eq[1])
def test_expressions_with_null_equality2():
for eq in null_equality:
context = mapnik.Context()
f = mapnik.Feature(context,0)
f["prop"] = eq[0]
eq_(f["prop"],eq[0])
if eq[0] is None:
eq_(f["prop"] is None, True)
else:
eq_(isinstance(f['prop'],eq[2]),True,'%s is not an instance of %s' % (f['prop'],eq[2]))
# TODO - support `is not` syntax:
# https://github.com/mapnik/mapnik/issues/796
expr = mapnik.Expression("not [prop] is null")
eq_(expr.evaluate(f),not eq[1])
# https://github.com/mapnik/mapnik/issues/1642
expr = mapnik.Expression("[prop] != null")
eq_(expr.evaluate(f),not eq[1])
truthyness = [
[u'hello',True,unicode],
[u'',False,unicode],
[0,False,long],
[123,True,long],
[0.0,False,float],
[123.123,True,float],
[.1,True,float],
[False,False,long], # TODO - should become bool: https://github.com/mapnik/mapnik/issues/1873
[True,True,long], # TODO - should become bool: https://github.com/mapnik/mapnik/issues/1873
[None,False,None],
[2147483648,True,long],
[922337203685477580,True,long]
]
def test_expressions_for_thruthyness():
context = mapnik.Context()
for eq in truthyness:
f = mapnik.Feature(context,0)
f["prop"] = eq[0]
eq_(f["prop"],eq[0])
if eq[0] is None:
eq_(f["prop"] is None, True)
else:
eq_(isinstance(f['prop'],eq[2]),True,'%s is not an instance of %s' % (f['prop'],eq[2]))
expr = mapnik.Expression("[prop]")
eq_(expr.to_bool(f),eq[1])
expr = mapnik.Expression("not [prop]")
eq_(expr.to_bool(f),not eq[1])
expr = mapnik.Expression("! [prop]")
eq_(expr.to_bool(f),not eq[1])
# also test if feature does not have property at all
f2 = mapnik.Feature(context,1)
# no property existing will return value_null since
# https://github.com/mapnik/mapnik/commit/562fada9d0f680f59b2d9f396c95320a0d753479#include/mapnik/feature.hpp
eq_(f2["prop"] is None,True)
expr = mapnik.Expression("[prop]")
eq_(expr.evaluate(f2),None)
eq_(expr.to_bool(f2),False)
# https://github.com/mapnik/mapnik/issues/1859
def test_if_null_and_empty_string_are_equal():
context = mapnik.Context()
f = mapnik.Feature(context,0)
f["empty"] = u""
f["null"] = None
# ensure base assumptions are good
eq_(mapnik.Expression("[empty] = ''").to_bool(f),True)
eq_(mapnik.Expression("[null] = null").to_bool(f),True)
eq_(mapnik.Expression("[empty] != ''").to_bool(f),False)
eq_(mapnik.Expression("[null] != null").to_bool(f),False)
# now test expected behavior
eq_(mapnik.Expression("[null] = ''").to_bool(f),False)
eq_(mapnik.Expression("[empty] = null").to_bool(f),False)
eq_(mapnik.Expression("[empty] != null").to_bool(f),True)
# this one is the back compatibility shim
eq_(mapnik.Expression("[null] != ''").to_bool(f),False)
def test_filtering_nulls_and_empty_strings():
context = mapnik.Context()
f = mapnik.Feature(context,0)
f["prop"] = u"hello"
eq_(f["prop"],u"hello")
eq_(mapnik.Expression("[prop]").to_bool(f),True)
eq_(mapnik.Expression("! [prop]").to_bool(f),False)
eq_(mapnik.Expression("[prop] != null").to_bool(f),True)
eq_(mapnik.Expression("[prop] != ''").to_bool(f),True)
eq_(mapnik.Expression("[prop] != null and [prop] != ''").to_bool(f),True)
eq_(mapnik.Expression("[prop] != null or [prop] != ''").to_bool(f),True)
f["prop2"] = u""
eq_(f["prop2"],u"")
eq_(mapnik.Expression("[prop2]").to_bool(f),False)
eq_(mapnik.Expression("! [prop2]").to_bool(f),True)
eq_(mapnik.Expression("[prop2] != null").to_bool(f),True)
eq_(mapnik.Expression("[prop2] != ''").to_bool(f),False)
eq_(mapnik.Expression("[prop2] = ''").to_bool(f),True)
eq_(mapnik.Expression("[prop2] != null or [prop2] != ''").to_bool(f),True)
eq_(mapnik.Expression("[prop2] != null and [prop2] != ''").to_bool(f),False)
f["prop3"] = None
eq_(f["prop3"],None)
eq_(mapnik.Expression("[prop3]").to_bool(f),False)
eq_(mapnik.Expression("! [prop3]").to_bool(f),True)
eq_(mapnik.Expression("[prop3] != null").to_bool(f),False)
eq_(mapnik.Expression("[prop3] = null").to_bool(f),True)
# https://github.com/mapnik/mapnik/issues/1859
#eq_(mapnik.Expression("[prop3] != ''").to_bool(f),True)
eq_(mapnik.Expression("[prop3] != ''").to_bool(f),False)
eq_(mapnik.Expression("[prop3] = ''").to_bool(f),False)
# https://github.com/mapnik/mapnik/issues/1859
#eq_(mapnik.Expression("[prop3] != null or [prop3] != ''").to_bool(f),True)
eq_(mapnik.Expression("[prop3] != null or [prop3] != ''").to_bool(f),False)
eq_(mapnik.Expression("[prop3] != null and [prop3] != ''").to_bool(f),False)
# attr not existing should behave the same as prop3
eq_(mapnik.Expression("[prop4]").to_bool(f),False)
eq_(mapnik.Expression("! [prop4]").to_bool(f),True)
eq_(mapnik.Expression("[prop4] != null").to_bool(f),False)
eq_(mapnik.Expression("[prop4] = null").to_bool(f),True)
# https://github.com/mapnik/mapnik/issues/1859
##eq_(mapnik.Expression("[prop4] != ''").to_bool(f),True)
eq_(mapnik.Expression("[prop4] != ''").to_bool(f),False)
eq_(mapnik.Expression("[prop4] = ''").to_bool(f),False)
# https://github.com/mapnik/mapnik/issues/1859
##eq_(mapnik.Expression("[prop4] != null or [prop4] != ''").to_bool(f),True)
eq_(mapnik.Expression("[prop4] != null or [prop4] != ''").to_bool(f),False)
eq_(mapnik.Expression("[prop4] != null and [prop4] != ''").to_bool(f),False)
f["prop5"] = False
eq_(f["prop5"],False)
eq_(mapnik.Expression("[prop5]").to_bool(f),False)
eq_(mapnik.Expression("! [prop5]").to_bool(f),True)
eq_(mapnik.Expression("[prop5] != null").to_bool(f),True)
eq_(mapnik.Expression("[prop5] = null").to_bool(f),False)
eq_(mapnik.Expression("[prop5] != ''").to_bool(f),True)
eq_(mapnik.Expression("[prop5] = ''").to_bool(f),False)
eq_(mapnik.Expression("[prop5] != null or [prop5] != ''").to_bool(f),True)
eq_(mapnik.Expression("[prop5] != null and [prop5] != ''").to_bool(f),True)
# note, we need to do [prop5] != 0 here instead of false due to this bug:
# https://github.com/mapnik/mapnik/issues/1873
eq_(mapnik.Expression("[prop5] != null and [prop5] != '' and [prop5] != 0").to_bool(f),False)
# https://github.com/mapnik/mapnik/issues/1872
def test_falseyness_comparision():
context = mapnik.Context()
f = mapnik.Feature(context,0)
f["prop"] = 0
eq_(mapnik.Expression("[prop]").to_bool(f),False)
eq_(mapnik.Expression("[prop] = false").to_bool(f),True)
eq_(mapnik.Expression("not [prop] != false").to_bool(f),True)
eq_(mapnik.Expression("not [prop] = true").to_bool(f),True)
eq_(mapnik.Expression("[prop] = true").to_bool(f),False)
eq_(mapnik.Expression("[prop] != true").to_bool(f),True)
# https://github.com/mapnik/mapnik/issues/1806, fixed by https://github.com/mapnik/mapnik/issues/1872
def test_truthyness_comparision():
context = mapnik.Context()
f = mapnik.Feature(context,0)
f["prop"] = 1
eq_(mapnik.Expression("[prop]").to_bool(f),True)
eq_(mapnik.Expression("[prop] = false").to_bool(f),False)
eq_(mapnik.Expression("not [prop] != false").to_bool(f),False)
eq_(mapnik.Expression("not [prop] = true").to_bool(f),False)
eq_(mapnik.Expression("[prop] = true").to_bool(f),True)
eq_(mapnik.Expression("[prop] != true").to_bool(f),False)
def test_division_by_zero():
expr = mapnik.Expression('[a]/[b]')
c = mapnik.Context()
c.push('a')
c.push('b')
f = mapnik.Feature(c,0);
f['a'] = 1
f['b'] = 0
eq_(expr.evaluate(f),None)
@raises(RuntimeError)
def test_invalid_syntax1():
mapnik.Expression('abs()')
if __name__ == "__main__":
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,41 +0,0 @@
#!/usr/bin/env python
from nose.tools import eq_
from utilities import execution_path, run_all
import os, mapnik
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_loading_fontset_from_map():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/fontset.xml',True)
fs = m.find_fontset('book-fonts')
eq_(len(fs.names),2)
eq_(list(fs.names),['DejaVu Sans Book','DejaVu Sans Oblique'])
# def test_loading_fontset_from_python():
# m = mapnik.Map(256,256)
# fset = mapnik.FontSet('foo')
# fset.add_face_name('Comic Sans')
# fset.add_face_name('Papyrus')
# eq_(fset.name,'foo')
# fset.name = 'my-set'
# eq_(fset.name,'my-set')
# m.append_fontset('my-set', fset)
# sty = mapnik.Style()
# rule = mapnik.Rule()
# tsym = mapnik.TextSymbolizer()
# eq_(tsym.fontset,None)
# tsym.fontset = fset
# rule.symbols.append(tsym)
# sty.rules.append(rule)
# m.append_style('Style',sty)
# serialized_map = mapnik.save_map_to_string(m)
# eq_('fontset-name="my-set"' in serialized_map,True)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,151 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from nose.tools import eq_,assert_almost_equal
from utilities import execution_path, run_all
import os, mapnik
try:
import json
except ImportError:
import simplejson as json
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
if 'geojson' in mapnik.DatasourceCache.plugin_names():
def test_geojson_init():
ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson')
e = ds.envelope()
assert_almost_equal(e.minx, -81.705583, places=7)
assert_almost_equal(e.miny, 41.480573, places=6)
assert_almost_equal(e.maxx, -81.705583, places=5)
assert_almost_equal(e.maxy, 41.480573, places=3)
def test_geojson_properties():
ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson')
f = ds.features_at_point(ds.envelope().center()).features[0]
eq_(len(ds.fields()),9)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(f['name'], u'Test')
eq_(f['int'], 1)
eq_(f['description'], u'Test: \u005C')
eq_(f['spaces'], u'this has spaces')
eq_(f['double'], 1.1)
eq_(f['boolean'], True)
eq_(f['NOM_FR'], u'Qu\xe9bec')
eq_(f['NOM_FR'], u'Québec')
eq_(f['array'], u'[[[1],["deux"]],[["\\u0442\\u0440\\u0438","four","\\u4e94"]]]')
array = json.loads(f['array'])
eq_(array,[[[1], [u'deux']], [[u'\u0442\u0440\u0438', u'four', u'\u4e94']]])
eq_(f['object'], u'{"value":{"type":"\\u041c\\u0430pni\\u043a","array":[3,0,"x"]}}')
object = json.loads(f['object'])
eq_(object,{u'value': {u'array': [3, 0, u'x'], u'type': u'\u041c\u0430pni\u043a'}})
ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson')
f = ds.all_features()[0]
eq_(len(ds.fields()),9)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(f['name'], u'Test')
eq_(f['int'], 1)
eq_(f['description'], u'Test: \u005C')
eq_(f['spaces'], u'this has spaces')
eq_(f['double'], 1.1)
eq_(f['boolean'], True)
eq_(f['NOM_FR'], u'Qu\xe9bec')
eq_(f['NOM_FR'], u'Québec')
eq_(f['array'], u'[[[1],["deux"]],[["\\u0442\\u0440\\u0438","four","\\u4e94"]]]')
array = json.loads(f['array'])
eq_(array,[[[1], [u'deux']], [[u'\u0442\u0440\u0438', u'four', u'\u4e94']]])
eq_(f['object'], u'{"value":{"type":"\\u041c\\u0430pni\\u043a","array":[3,0,"x"]}}')
object = json.loads(f['object'])
eq_(object,{u'value': {u'array': [3, 0, u'x'], u'type': u'\u041c\u0430pni\u043a'}})
def test_large_geojson_properties():
ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson',cache_features = False)
f = ds.features_at_point(ds.envelope().center()).features[0]
eq_(len(ds.fields()),9)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(f['name'], u'Test')
eq_(f['int'], 1)
eq_(f['description'], u'Test: \u005C')
eq_(f['spaces'], u'this has spaces')
eq_(f['double'], 1.1)
eq_(f['boolean'], True)
eq_(f['NOM_FR'], u'Qu\xe9bec')
eq_(f['NOM_FR'], u'Québec')
eq_(f['array'], u'[[[1],["deux"]],[["\\u0442\\u0440\\u0438","four","\\u4e94"]]]')
array = json.loads(f['array'])
eq_(array,[[[1], [u'deux']], [[u'\u0442\u0440\u0438', u'four', u'\u4e94']]])
eq_(f['object'], u'{"value":{"type":"\\u041c\\u0430pni\\u043a","array":[3,0,"x"]}}')
object = json.loads(f['object'])
eq_(object,{u'value': {u'array': [3, 0, u'x'], u'type': u'\u041c\u0430pni\u043a'}})
ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson')
f = ds.all_features()[0]
eq_(len(ds.fields()),9)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(f['name'], u'Test')
eq_(f['int'], 1)
eq_(f['description'], u'Test: \u005C')
eq_(f['spaces'], u'this has spaces')
eq_(f['double'], 1.1)
eq_(f['boolean'], True)
eq_(f['NOM_FR'], u'Qu\xe9bec')
eq_(f['NOM_FR'], u'Québec')
eq_(f['array'], u'[[[1],["deux"]],[["\\u0442\\u0440\\u0438","four","\\u4e94"]]]')
array = json.loads(f['array'])
eq_(array,[[[1], [u'deux']], [[u'\u0442\u0440\u0438', u'four', u'\u4e94']]])
eq_(f['object'], u'{"value":{"type":"\\u041c\\u0430pni\\u043a","array":[3,0,"x"]}}')
object = json.loads(f['object'])
eq_(object,{u'value': {u'array': [3, 0, u'x'], u'type': u'\u041c\u0430pni\u043a'}})
def test_geojson_from_in_memory_string():
# will silently fail since it is a geometry and needs to be a featurecollection.
#ds = mapnik.Datasource(type='geojson',inline='{"type":"LineString","coordinates":[[0,0],[10,10]]}')
# works since it is a featurecollection
ds = mapnik.Datasource(type='geojson',inline='{ "type":"FeatureCollection", "features": [ { "type":"Feature", "properties":{"name":"test"}, "geometry": { "type":"LineString","coordinates":[[0,0],[10,10]] } } ]}')
eq_(len(ds.fields()),1)
f = ds.all_features()[0]
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.LineString)
eq_(f['name'], u'test')
# @raises(RuntimeError)
def test_that_nonexistant_query_field_throws(**kwargs):
ds = mapnik.Datasource(type='geojson',file='../data/json/escaped.geojson')
eq_(len(ds.fields()),9)
# TODO - this sorting is messed up
#eq_(ds.fields(),['name', 'int', 'double', 'description', 'boolean', 'NOM_FR'])
#eq_(ds.field_types(),['str', 'int', 'float', 'str', 'bool', 'str'])
# TODO - should geojson plugin throw like others?
# query = mapnik.Query(ds.envelope())
# for fld in ds.fields():
# query.add_property_name(fld)
# # also add an invalid one, triggering throw
# query.add_property_name('bogus')
# fs = ds.features(query)
def test_parsing_feature_collection_with_top_level_properties():
ds = mapnik.Datasource(type='geojson',file='../data/json/feature_collection_level_properties.json')
f = ds.all_features()[0]
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
eq_(f['feat_name'], u'feat_value')
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

File diff suppressed because one or more lines are too long

View file

@ -1,13 +0,0 @@
import mapnik
from nose.tools import eq_
from utilities import run_all
def test_grayscale_conversion():
im = mapnik.Image(2,2)
im.fill(mapnik.Color('white'))
im.set_grayscale_to_alpha()
pixel = im.get_pixel(0,0)
eq_((pixel >> 24) & 0xff,255);
if __name__ == "__main__":
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,124 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, mapnik
from timeit import Timer, time
from utilities import execution_path, run_all
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
combinations = ['png',
'png8',
'png8:m=o',
'png8:m=h',
'png8:m=o:t=0',
'png8:m=o:t=1',
'png8:m=o:t=2',
'png8:m=h:t=0',
'png8:m=h:t=1',
'png8:m=h:t=2',
'png:z=1',
'png:z=1:t=0', # forces rbg, no a
'png8:z=1',
'png8:z=1:m=o',
'png8:z=1:m=h',
'png8:z=1:c=1',
'png8:z=1:c=24',
'png8:z=1:c=64',
'png8:z=1:c=128',
'png8:z=1:c=200',
'png8:z=1:c=255',
'png8:z=9:c=64',
'png8:z=9:c=128',
'png8:z=9:c=200',
'png8:z=1:c=50:m=h',
'png8:z=1:c=1:m=o',
'png8:z=1:c=1:m=o:s=filtered',
'png:z=1:s=filtered',
'png:z=1:s=huff',
'png:z=1:s=rle',
'png8:m=h:g=2.0',
'png8:m=h:g=1.0',
'png:e=miniz',
'png8:e=miniz'
]
tiles = [
'blank',
'solid',
'many_colors',
'aerial_24'
]
iterations = 10
def do_encoding():
global image
results = {}
sortable = {}
def run(func, im, format, t):
global image
image = im
start = time.time()
set = t.repeat(iterations,1)
elapsed = (time.time() - start)
min_ = min(set)*1000
avg = (sum(set)/len(set))*1000
name = func.__name__ + ' ' + format
results[name] = [min_,avg,elapsed*1000,name,len(func())]
sortable[name] = [min_]
if 'blank' in tiles:
def blank():
return eval('image.tostring("%s")' % c)
blank_im = mapnik.Image(512,512)
for c in combinations:
t = Timer(blank)
run(blank,blank_im,c,t)
if 'solid' in tiles:
def solid():
return eval('image.tostring("%s")' % c)
solid_im = mapnik.Image(512,512)
solid_im.fill(mapnik.Color("#f2efe9"))
for c in combinations:
t = Timer(solid)
run(solid,solid_im,c,t)
if 'many_colors' in tiles:
def many_colors():
return eval('image.tostring("%s")' % c)
# lots of colors: http://tile.osm.org/13/4194/2747.png
many_colors_im = mapnik.Image.open('../data/images/13_4194_2747.png')
for c in combinations:
t = Timer(many_colors)
run(many_colors,many_colors_im,c,t)
if 'aerial_24' in tiles:
def aerial_24():
return eval('image.tostring("%s")' % c)
aerial_24_im = mapnik.Image.open('../data/images/12_654_1580.png')
for c in combinations:
t = Timer(aerial_24)
run(aerial_24,aerial_24_im,c,t)
for key, value in sorted(sortable.iteritems(), key=lambda (k,v): (v,k)):
s = results[key]
min_ = str(s[0])[:6]
avg = str(s[1])[:6]
elapsed = str(s[2])[:6]
name = s[3]
size = s[4]
print 'min: %sms | avg: %sms | total: %sms | len: %s <-- %s' % (min_,avg,elapsed,size,name)
if __name__ == "__main__":
setup()
do_encoding()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,68 +0,0 @@
#!/usr/bin/env python
from nose.tools import eq_
from utilities import execution_path, run_all
from utilities import side_by_side_image
import os, mapnik
import re
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def replace_style(m, name, style):
m.remove_style(name)
m.append_style(name, style)
def test_append():
s = mapnik.Style()
eq_(s.image_filters,'')
s.image_filters = 'gray'
eq_(s.image_filters,'gray')
s.image_filters = 'sharpen'
eq_(s.image_filters,'sharpen')
if 'shape' in mapnik.DatasourceCache.plugin_names():
def test_style_level_image_filter():
m = mapnik.Map(256, 256)
mapnik.load_map(m, '../data/good_maps/style_level_image_filter.xml')
m.zoom_all()
successes = []
fails = []
for name in ("", "agg-stack-blur(2,2)", "blur",
"edge-detect", "emboss", "gray", "invert",
"sharpen", "sobel", "x-gradient", "y-gradient"):
if name == "":
filename = "none"
else:
filename = re.sub(r"[^-_a-z.0-9]", "", name)
# find_style returns a copy of the style object
style_markers = m.find_style("markers")
style_markers.image_filters = name
style_labels = m.find_style("labels")
style_labels.image_filters = name
# replace the original style with the modified one
replace_style(m, "markers", style_markers)
replace_style(m, "labels", style_labels)
im = mapnik.Image(m.width, m.height)
mapnik.render(m, im)
actual = '/tmp/mapnik-style-image-filter-' + filename + '.png'
expected = 'images/style-image-filter/' + filename + '.png'
im.save(actual,"png32")
if not os.path.exists(expected) or os.environ.get('UPDATE'):
print 'generating expected test image: %s' % expected
im.save(expected,'png32')
expected_im = mapnik.Image.open(expected)
# compare them
if im.tostring('png32') == expected_im.tostring('png32'):
successes.append(name)
else:
fails.append('failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
fail_im = side_by_side_image(expected_im, im)
fail_im.save('/tmp/mapnik-style-image-filter-' + filename + '.fail.png','png32')
eq_(len(fails), 0, '\n'+'\n'.join(fails))
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,336 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, mapnik
from nose.tools import eq_,raises, assert_almost_equal
from utilities import execution_path, run_all, get_unique_colors
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_type():
im = mapnik.Image(256, 256)
eq_(im.get_type(), mapnik.ImageType.rgba8)
im = mapnik.Image(256, 256, mapnik.ImageType.gray8)
eq_(im.get_type(), mapnik.ImageType.gray8)
def test_image_premultiply():
im = mapnik.Image(256,256)
eq_(im.premultiplied(),False)
# Premultiply should return true that it worked
eq_(im.premultiply(), True)
eq_(im.premultiplied(),True)
# Premultipling again should return false as nothing should happen
eq_(im.premultiply(), False)
eq_(im.premultiplied(),True)
# Demultiply should return true that it worked
eq_(im.demultiply(), True)
eq_(im.premultiplied(),False)
# Demultiply again should not work and return false as it did nothing
eq_(im.demultiply(), False)
eq_(im.premultiplied(),False)
def test_image_premultiply_values():
im = mapnik.Image(256,256)
im.fill(mapnik.Color(16, 33, 255, 128))
im.premultiply()
c = im.get_pixel(0,0, True)
eq_(c.r, 8)
eq_(c.g, 17)
eq_(c.b, 128)
eq_(c.a, 128)
im.demultiply()
# Do to the nature of this operation the result will not be exactly the same
c = im.get_pixel(0,0,True)
eq_(c.r,15)
eq_(c.g,33)
eq_(c.b,255)
eq_(c.a,128)
def test_background():
im = mapnik.Image(256,256)
eq_(im.premultiplied(), False)
im.fill(mapnik.Color(32,64,125,128))
eq_(im.premultiplied(), False)
c = im.get_pixel(0,0,True)
eq_(c.get_premultiplied(), False)
eq_(c.r,32)
eq_(c.g,64)
eq_(c.b,125)
eq_(c.a,128)
# Now again with a premultiplied alpha
im.fill(mapnik.Color(32,64,125,128,True))
eq_(im.premultiplied(), True)
c = im.get_pixel(0,0,True)
eq_(c.get_premultiplied(), True)
eq_(c.r,32)
eq_(c.g,64)
eq_(c.b,125)
eq_(c.a,128)
def test_set_and_get_pixel():
# Create an image that is not premultiplied
im = mapnik.Image(256,256)
c0 = mapnik.Color(16,33,255,128)
c0_pre = mapnik.Color(16,33,255,128, True)
im.set_pixel(0,0,c0)
im.set_pixel(1,1,c0_pre)
# No differences for non premultiplied pixels
c1_int = mapnik.Color(im.get_pixel(0,0))
eq_(c0.r, c1_int.r)
eq_(c0.g, c1_int.g)
eq_(c0.b, c1_int.b)
eq_(c0.a, c1_int.a)
c1 = im.get_pixel(0,0,True)
eq_(c0.r, c1.r)
eq_(c0.g, c1.g)
eq_(c0.b, c1.b)
eq_(c0.a, c1.a)
# The premultiplied Color should be demultiplied before being applied.
c0_pre.demultiply()
c1_int = mapnik.Color(im.get_pixel(1,1))
eq_(c0_pre.r, c1_int.r)
eq_(c0_pre.g, c1_int.g)
eq_(c0_pre.b, c1_int.b)
eq_(c0_pre.a, c1_int.a)
c1 = im.get_pixel(1,1,True)
eq_(c0_pre.r, c1.r)
eq_(c0_pre.g, c1.g)
eq_(c0_pre.b, c1.b)
eq_(c0_pre.a, c1.a)
# Now create a new image that is premultiplied
im = mapnik.Image(256,256, mapnik.ImageType.rgba8, True, True)
c0 = mapnik.Color(16,33,255,128)
c0_pre = mapnik.Color(16,33,255,128, True)
im.set_pixel(0,0,c0)
im.set_pixel(1,1,c0_pre)
# It should have put pixels that are the same as premultiplied so premultiply c0
c0.premultiply()
c1_int = mapnik.Color(im.get_pixel(0,0))
eq_(c0.r, c1_int.r)
eq_(c0.g, c1_int.g)
eq_(c0.b, c1_int.b)
eq_(c0.a, c1_int.a)
c1 = im.get_pixel(0,0,True)
eq_(c0.r, c1.r)
eq_(c0.g, c1.g)
eq_(c0.b, c1.b)
eq_(c0.a, c1.a)
# The premultiplied Color should be the same though
c1_int = mapnik.Color(im.get_pixel(1,1))
eq_(c0_pre.r, c1_int.r)
eq_(c0_pre.g, c1_int.g)
eq_(c0_pre.b, c1_int.b)
eq_(c0_pre.a, c1_int.a)
c1 = im.get_pixel(1,1,True)
eq_(c0_pre.r, c1.r)
eq_(c0_pre.g, c1.g)
eq_(c0_pre.b, c1.b)
eq_(c0_pre.a, c1.a)
def test_pixel_gray8():
im = mapnik.Image(4,4,mapnik.ImageType.gray8)
val_list = range(20)
for v in val_list:
im.set_pixel(0,0, v)
eq_(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
eq_(im.get_pixel(0,0), 0)
def test_pixel_gray8s():
im = mapnik.Image(4,4,mapnik.ImageType.gray8s)
val_list = range(20)
for v in val_list:
im.set_pixel(0,0, v)
eq_(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
eq_(im.get_pixel(0,0), -v)
def test_pixel_gray16():
im = mapnik.Image(4,4,mapnik.ImageType.gray16)
val_list = range(20)
for v in val_list:
im.set_pixel(0,0, v)
eq_(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
eq_(im.get_pixel(0,0), 0)
def test_pixel_gray16s():
im = mapnik.Image(4,4,mapnik.ImageType.gray16s)
val_list = range(20)
for v in val_list:
im.set_pixel(0,0, v)
eq_(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
eq_(im.get_pixel(0,0), -v)
def test_pixel_gray32():
im = mapnik.Image(4,4,mapnik.ImageType.gray32)
val_list = range(20)
for v in val_list:
im.set_pixel(0,0, v)
eq_(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
eq_(im.get_pixel(0,0), 0)
def test_pixel_gray32s():
im = mapnik.Image(4,4,mapnik.ImageType.gray32s)
val_list = range(20)
for v in val_list:
im.set_pixel(0,0, v)
eq_(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
eq_(im.get_pixel(0,0), -v)
def test_pixel_gray64():
im = mapnik.Image(4,4,mapnik.ImageType.gray64)
val_list = range(20)
for v in val_list:
im.set_pixel(0,0, v)
eq_(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
eq_(im.get_pixel(0,0), 0)
def test_pixel_gray64s():
im = mapnik.Image(4,4,mapnik.ImageType.gray64s)
val_list = range(20)
for v in val_list:
im.set_pixel(0,0, v)
eq_(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
eq_(im.get_pixel(0,0), -v)
def test_pixel_floats():
im = mapnik.Image(4,4,mapnik.ImageType.gray32f)
val_list = [0.9, 0.99, 0.999, 0.9999, 0.99999, 1, 1.0001, 1.001, 1.01, 1.1]
for v in val_list:
im.set_pixel(0,0, v)
assert_almost_equal(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
assert_almost_equal(im.get_pixel(0,0), -v)
def test_pixel_doubles():
im = mapnik.Image(4,4,mapnik.ImageType.gray64f)
val_list = [0.9, 0.99, 0.999, 0.9999, 0.99999, 1, 1.0001, 1.001, 1.01, 1.1]
for v in val_list:
im.set_pixel(0,0, v)
assert_almost_equal(im.get_pixel(0,0), v)
im.set_pixel(0,0, -v)
assert_almost_equal(im.get_pixel(0,0), -v)
def test_pixel_overflow():
im = mapnik.Image(4,4,mapnik.ImageType.gray8)
im.set_pixel(0,0,256)
eq_(im.get_pixel(0,0),255)
def test_pixel_underflow():
im = mapnik.Image(4,4,mapnik.ImageType.gray8)
im.set_pixel(0,0,-1)
eq_(im.get_pixel(0,0),0)
im = mapnik.Image(4,4,mapnik.ImageType.gray16)
im.set_pixel(0,0,-1)
eq_(im.get_pixel(0,0),0)
@raises(IndexError)
def test_set_pixel_out_of_range_1():
im = mapnik.Image(4,4)
c = mapnik.Color('blue')
im.set_pixel(5,5,c)
@raises(OverflowError)
def test_set_pixel_out_of_range_2():
im = mapnik.Image(4,4)
c = mapnik.Color('blue')
im.set_pixel(-1,1,c)
@raises(IndexError)
def test_get_pixel_out_of_range_1():
im = mapnik.Image(4,4)
c = im.get_pixel(5,5)
@raises(OverflowError)
def test_get_pixel_out_of_range_2():
im = mapnik.Image(4,4)
c = im.get_pixel(-1,1)
@raises(IndexError)
def test_get_pixel_color_out_of_range_1():
im = mapnik.Image(4,4)
c = im.get_pixel(5,5,True)
@raises(OverflowError)
def test_get_pixel_color_out_of_range_2():
im = mapnik.Image(4,4)
c = im.get_pixel(-1,1,True)
def test_set_color_to_alpha():
im = mapnik.Image(256,256)
im.fill(mapnik.Color('rgba(12,12,12,255)'))
eq_(get_unique_colors(im), ['rgba(12,12,12,255)'])
im.set_color_to_alpha(mapnik.Color('rgba(12,12,12,0)'))
eq_(get_unique_colors(im), ['rgba(0,0,0,0)'])
@raises(RuntimeError)
def test_negative_image_dimensions():
# TODO - this may have regressed in https://github.com/mapnik/mapnik/commit/4f3521ac24b61fc8ae8fd344a16dc3a5fdf15af7
im = mapnik.Image(-40,40)
# should not get here
eq_(im.width(),0)
eq_(im.height(),0)
def test_jpeg_round_trip():
filepath = '/tmp/mapnik-jpeg-io.jpeg'
im = mapnik.Image(255,267)
im.fill(mapnik.Color('rgba(1,2,3,.5)'))
im.save(filepath,'jpeg')
im2 = mapnik.Image.open(filepath)
im3 = mapnik.Image.fromstring(open(filepath,'r').read())
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(im.width(),im3.width())
eq_(im.height(),im3.height())
eq_(len(im.tostring()),len(im2.tostring()))
eq_(len(im.tostring('jpeg')),len(im2.tostring('jpeg')))
eq_(len(im.tostring()),len(im3.tostring()))
eq_(len(im.tostring('jpeg')),len(im3.tostring('jpeg')))
def test_png_round_trip():
filepath = '/tmp/mapnik-png-io.png'
im = mapnik.Image(255,267)
im.fill(mapnik.Color('rgba(1,2,3,.5)'))
im.save(filepath,'png')
im2 = mapnik.Image.open(filepath)
im3 = mapnik.Image.fromstring(open(filepath,'r').read())
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(im.width(),im3.width())
eq_(im.height(),im3.height())
eq_(len(im.tostring()),len(im2.tostring()))
eq_(len(im.tostring('png')),len(im2.tostring('png')))
eq_(len(im.tostring('png8')),len(im2.tostring('png8')))
eq_(len(im.tostring()),len(im3.tostring()))
eq_(len(im.tostring('png')),len(im3.tostring('png')))
eq_(len(im.tostring('png8')),len(im3.tostring('png8')))
def test_image_open_from_string():
filepath = '../data/images/dummy.png'
im1 = mapnik.Image.open(filepath)
im2 = mapnik.Image.fromstring(open(filepath,'rb').read())
eq_(im1.width(),im2.width())
length = len(im1.tostring())
eq_(length,len(im2.tostring()))
eq_(len(mapnik.Image.fromstring(im1.tostring('png')).tostring()),length)
eq_(len(mapnik.Image.fromstring(im1.tostring('jpeg')).tostring()),length)
eq_(len(mapnik.Image.frombuffer(buffer(im1.tostring('png'))).tostring()),length)
eq_(len(mapnik.Image.frombuffer(buffer(im1.tostring('jpeg'))).tostring()),length)
# TODO - https://github.com/mapnik/mapnik/issues/1831
eq_(len(mapnik.Image.fromstring(im1.tostring('tiff')).tostring()),length)
eq_(len(mapnik.Image.frombuffer(buffer(im1.tostring('tiff'))).tostring()),length)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

View file

@ -1,335 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, mapnik
import hashlib
from nose.tools import eq_, assert_not_equal
from utilities import execution_path, run_all
def hashstr(var):
return hashlib.md5(var).hexdigest()
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_tiff_round_trip_scanline():
filepath = '/tmp/mapnik-tiff-io-scanline.tiff'
im = mapnik.Image(255,267)
im.fill(mapnik.Color('rgba(12,255,128,.5)'))
org_str = hashstr(im.tostring())
im.save(filepath,'tiff:method=scanline')
im2 = mapnik.Image.open(filepath)
im3 = mapnik.Image.fromstring(open(filepath,'r').read())
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(im.width(),im3.width())
eq_(im.height(),im3.height())
eq_(hashstr(im.tostring()), org_str)
# This won't be the same the first time around because the im is not premultiplied and im2 is
assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring()))
assert_not_equal(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline')))
# Now premultiply
im.premultiply()
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline')))
eq_(hashstr(im2.tostring()),hashstr(im3.tostring()))
eq_(hashstr(im2.tostring('tiff:method=scanline')),hashstr(im3.tostring('tiff:method=scanline')))
def test_tiff_round_trip_stripped():
filepath = '/tmp/mapnik-tiff-io-stripped.tiff'
im = mapnik.Image(255,267)
im.fill(mapnik.Color('rgba(12,255,128,.5)'))
org_str = hashstr(im.tostring())
im.save(filepath,'tiff:method=stripped')
im2 = mapnik.Image.open(filepath)
im2.save('/tmp/mapnik-tiff-io-stripped2.tiff','tiff:method=stripped')
im3 = mapnik.Image.fromstring(open(filepath,'r').read())
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(im.width(),im3.width())
eq_(im.height(),im3.height())
# Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the
# difference in tags.
assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring()))
assert_not_equal(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped')))
# Now if we premultiply they will be exactly the same
im.premultiply()
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped')))
eq_(hashstr(im2.tostring()),hashstr(im3.tostring()))
# Both of these started out premultiplied, so this round trip should be exactly the same!
eq_(hashstr(im2.tostring('tiff:method=stripped')),hashstr(im3.tostring('tiff:method=stripped')))
def test_tiff_round_trip_rows_stripped():
filepath = '/tmp/mapnik-tiff-io-rows_stripped.tiff'
filepath2 = '/tmp/mapnik-tiff-io-rows_stripped2.tiff'
im = mapnik.Image(255,267)
im.fill(mapnik.Color('rgba(12,255,128,.5)'))
c = im.get_pixel(0,0,True)
eq_(c.r, 12)
eq_(c.g, 255)
eq_(c.b, 128)
eq_(c.a, 128)
eq_(c.get_premultiplied(), False)
im.save(filepath,'tiff:method=stripped:rows_per_strip=8')
im2 = mapnik.Image.open(filepath)
c2 = im2.get_pixel(0,0,True)
eq_(c2.r, 6)
eq_(c2.g, 128)
eq_(c2.b, 64)
eq_(c2.a, 128)
eq_(c2.get_premultiplied(), True)
im2.save(filepath2,'tiff:method=stripped:rows_per_strip=8')
im3 = mapnik.Image.fromstring(open(filepath,'r').read())
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(im.width(),im3.width())
eq_(im.height(),im3.height())
# Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the
# difference in tags.
assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring()))
assert_not_equal(hashstr(im.tostring('tiff:method=stripped:rows_per_strip=8')),hashstr(im2.tostring('tiff:method=stripped:rows_per_strip=8')))
# Now premultiply the first image and they will be the same!
im.premultiply()
eq_(hashstr(im.tostring('tiff:method=stripped:rows_per_strip=8')),hashstr(im2.tostring('tiff:method=stripped:rows_per_strip=8')))
eq_(hashstr(im2.tostring()),hashstr(im3.tostring()))
# Both of these started out premultiplied, so this round trip should be exactly the same!
eq_(hashstr(im2.tostring('tiff:method=stripped:rows_per_strip=8')),hashstr(im3.tostring('tiff:method=stripped:rows_per_strip=8')))
def test_tiff_round_trip_buffered_tiled():
filepath = '/tmp/mapnik-tiff-io-buffered-tiled.tiff'
filepath2 = '/tmp/mapnik-tiff-io-buffered-tiled2.tiff'
filepath3 = '/tmp/mapnik-tiff-io-buffered-tiled3.tiff'
im = mapnik.Image(255,267)
im.fill(mapnik.Color('rgba(33,255,128,.5)'))
c = im.get_pixel(0,0,True)
eq_(c.r, 33)
eq_(c.g, 255)
eq_(c.b, 128)
eq_(c.a, 128)
eq_(c.get_premultiplied(), False)
im.save(filepath,'tiff:method=tiled:tile_width=32:tile_height=32')
im2 = mapnik.Image.open(filepath)
c2 = im2.get_pixel(0,0,True)
eq_(c2.r, 17)
eq_(c2.g, 128)
eq_(c2.b, 64)
eq_(c2.a, 128)
eq_(c2.get_premultiplied(), True)
im3 = mapnik.Image.fromstring(open(filepath,'r').read())
im2.save(filepath2, 'tiff:method=tiled:tile_width=32:tile_height=32')
im3.save(filepath3, 'tiff:method=tiled:tile_width=32:tile_height=32')
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(im.width(),im3.width())
eq_(im.height(),im3.height())
# Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the
# difference in tags.
assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring()))
assert_not_equal(hashstr(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),hashstr(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32')))
# Now premultiply the first image and they should be the same
im.premultiply()
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),hashstr(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32')))
eq_(hashstr(im2.tostring()),hashstr(im3.tostring()))
# Both of these started out premultiplied, so this round trip should be exactly the same!
eq_(hashstr(im2.tostring('tiff:method=tiled:tile_width=32:tile_height=32')),hashstr(im3.tostring('tiff:method=tiled:tile_width=32:tile_height=32')))
def test_tiff_round_trip_tiled():
filepath = '/tmp/mapnik-tiff-io-tiled.tiff'
im = mapnik.Image(256,256)
im.fill(mapnik.Color('rgba(1,255,128,.5)'))
im.save(filepath,'tiff:method=tiled')
im2 = mapnik.Image.open(filepath)
im3 = mapnik.Image.fromstring(open(filepath,'r').read())
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(im.width(),im3.width())
eq_(im.height(),im3.height())
# Because one will end up with UNASSOC alpha tag which internally the TIFF reader will premultiply, the first to string will not be the same due to the
# difference in tags.
assert_not_equal(hashstr(im.tostring()),hashstr(im2.tostring()))
assert_not_equal(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled')))
# Now premultiply the first image and they will be exactly the same.
im.premultiply()
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled')))
eq_(hashstr(im2.tostring()),hashstr(im3.tostring()))
# Both of these started out premultiplied, so this round trip should be exactly the same!
eq_(hashstr(im2.tostring('tiff:method=tiled')),hashstr(im3.tostring('tiff:method=tiled')))
def test_tiff_rgb8_compare():
filepath1 = '../data/tiff/ndvi_256x256_rgb8_striped.tif'
filepath2 = '/tmp/mapnik-tiff-rgb8.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff')),hashstr(im2.tostring('tiff')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True)
def test_tiff_rgba8_compare_scanline():
filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif'
filepath2 = '/tmp/mapnik-tiff-rgba8-scanline.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=scanline')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True)
def test_tiff_rgba8_compare_stripped():
filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif'
filepath2 = '/tmp/mapnik-tiff-rgba8-stripped.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=stripped')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True)
def test_tiff_rgba8_compare_tiled():
filepath1 = '../data/tiff/ndvi_256x256_rgba8_striped.tif'
filepath2 = '/tmp/mapnik-tiff-rgba8-stripped.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=tiled')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.rgba8).tostring("tiff")),True)
def test_tiff_gray8_compare_scanline():
filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif'
filepath2 = '/tmp/mapnik-tiff-gray8-scanline.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=scanline')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True)
def test_tiff_gray8_compare_stripped():
filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif'
filepath2 = '/tmp/mapnik-tiff-gray8-stripped.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=stripped')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True)
def test_tiff_gray8_compare_tiled():
filepath1 = '../data/tiff/ndvi_256x256_gray8_striped.tif'
filepath2 = '/tmp/mapnik-tiff-gray8-tiled.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=tiled')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray8).tostring("tiff")),True)
def test_tiff_gray16_compare_scanline():
filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif'
filepath2 = '/tmp/mapnik-tiff-gray16-scanline.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=scanline')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True)
def test_tiff_gray16_compare_stripped():
filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif'
filepath2 = '/tmp/mapnik-tiff-gray16-stripped.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=stripped')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True)
def test_tiff_gray16_compare_tiled():
filepath1 = '../data/tiff/ndvi_256x256_gray16_striped.tif'
filepath2 = '/tmp/mapnik-tiff-gray16-tiled.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=tiled')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray16).tostring("tiff")),True)
def test_tiff_gray32f_compare_scanline():
filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif'
filepath2 = '/tmp/mapnik-tiff-gray32f-scanline.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=scanline')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=scanline')),hashstr(im2.tostring('tiff:method=scanline')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True)
def test_tiff_gray32f_compare_stripped():
filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif'
filepath2 = '/tmp/mapnik-tiff-gray32f-stripped.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=stripped')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=stripped')),hashstr(im2.tostring('tiff:method=stripped')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True)
def test_tiff_gray32f_compare_tiled():
filepath1 = '../data/tiff/ndvi_256x256_gray32f_striped.tif'
filepath2 = '/tmp/mapnik-tiff-gray32f-tiled.tiff'
im = mapnik.Image.open(filepath1)
im.save(filepath2,'tiff:method=tiled')
im2 = mapnik.Image.open(filepath2)
eq_(im.width(),im2.width())
eq_(im.height(),im2.height())
eq_(hashstr(im.tostring()),hashstr(im2.tostring()))
eq_(hashstr(im.tostring('tiff:method=tiled')),hashstr(im2.tostring('tiff:method=tiled')))
# should not be a blank image
eq_(hashstr(im.tostring("tiff")) != hashstr(mapnik.Image(im.width(),im.height(),mapnik.ImageType.gray32f).tostring("tiff")),True)
if __name__ == "__main__":
setup()
exit(run_all(eval(x) for x in dir() if x.startswith("test_")))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 899 B

Some files were not shown because too many files have changed in this diff Show more