Merge branch 'master' of github.com:mapnik/mapnik into geobuf

Conflicts:
	SConstruct
This commit is contained in:
Dane Springmeyer 2015-07-01 22:06:46 -07:00
commit 8f5e3c02f4
3636 changed files with 28114 additions and 123557 deletions

12
.gitignore vendored
View file

@ -1,10 +1,15 @@
.DS_Store .DS_Store
*.gcov
*.gcda
*.gcno
*~ *~
*.o *.o
*.pyc *.pyc
*.os *.os
*.so *.so
*.so.*
*.a *.a
*.swp
*.dylib *.dylib
plugins/input/*.input plugins/input/*.input
plugins/input/templates/*.input plugins/input/templates/*.input
@ -13,6 +18,9 @@ bindings/python/mapnik/paths.py
config.cache config.cache
config.log config.log
config.py config.py
mapnik-settings.env
mason_packages/
.mason/
.sconf_temp/ .sconf_temp/
.sconsign.dblite .sconsign.dblite
demo/viewer/viewer.ini demo/viewer/viewer.ini
@ -43,4 +51,6 @@ demo/viewer/release/
demo/viewer/ui_about.h demo/viewer/ui_about.h
demo/viewer/ui_info.h demo/viewer/ui_info.h
demo/viewer/ui_layer_info.h demo/viewer/ui_layer_info.h
tests/cpp_tests/*-bin test/standalone/*-bin
test/unit/run
test/visual/run

6
.gitmodules vendored Normal file
View file

@ -0,0 +1,6 @@
[submodule "test/data"]
path = test/data
url = https://github.com/mapnik/test-data.git
[submodule "test/data-visual"]
path = test/data-visual
url = https://github.com/mapnik/test-data-visual.git

View file

@ -2,30 +2,85 @@ language: cpp
sudo: false sudo: false
git:
depth: 10
submodules: true
env:
global:
- secure: "N3a5nzzsgpuu45k8qWdYsHNxrSnqeAGLTOYpfYoAH7B94vuf7pa7XV1tQjXbxrnx2D6ryTdtUtyRKwy7zXbwXxGt4DpczWEo8f6DUd6+obAp3kdnXABg2Sj4oA7KMs0F0CmoADy0jdUZD5YyOJHu64LCIIgzEQ9q49PFMNbU3IE="
- secure: "iQYPNpMtejcgYeUkWZGIWz1msIco5qydJrhZTSCQOYahAQerdT7q5WZEpEo3G6IWOGgO1eo7GFuY8DvqQjw1+jC9b9mhkRNdo3LhGTKS9Gsbl5Q27k0rjlaFZmmQHrfPlQJwhfAIp+KLugHtQw5bCoLh+95E3j0F0DayF1tuJ3s="
addons: addons:
postgresql: "9.3" postgresql: "9.4"
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.5
packages:
- clang-3.5
cache:
directories:
- $HOME/.ccache
matrix: matrix:
include: include:
- os: osx
compiler: clang
env: JOBS=12
- os: linux - os: linux
compiler: clang compiler: clang
env: JOBS=12 env: JOBS=8 MASON_PUBLISH=true
- os: linux - os: linux
compiler: gcc compiler: gcc
env: JOBS=6 env: JOBS=6
- os: osx
compiler: clang
env: JOBS=8 MASON_PUBLISH=true
- os: osx
compiler: clang
env: JOBS=8 COVERAGE=true
before_install:
- export COVERAGE=${COVERAGE:-false}
- export MASON_PUBLISH=${MASON_PUBLISH:-false}
- if [[ ${TRAVIS_BRANCH} != 'master' ]]; then export MASON_PUBLISH=false; fi
- if [[ ${TRAVIS_PULL_REQUEST} != 'false' ]]; then export MASON_PUBLISH=false; fi
install: install:
- if [[ $(uname -s) == 'Linux' ]]; then psql -U postgres -c 'create database template_postgis;' -U postgres; psql -U postgres -c 'create extension postgis;' -d template_postgis -U postgres; fi; - if [[ $(uname -s) == 'Linux' ]]; then
psql -U postgres -c 'create database template_postgis;' -U postgres;
psql -U postgres -c 'create extension postgis;' -d template_postgis -U postgres;
export CXX="ccache clang++-3.5 -Qunused-arguments";
export CC="ccache clang-3.5 -Qunused-arguments";
export PYTHONPATH=$(pwd)/mason_packages/.link/lib/python2.7/site-packages;
else
export PYTHONPATH=$(pwd)/mason_packages/.link/lib/python/site-packages;
fi
- if [[ ${COVERAGE} == true ]]; then
PYTHONUSERBASE=$(pwd)/mason_packages/.link pip install --user cpp-coveralls;
fi
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 - if [[ ${COVERAGE} == true ]]; then
- export PYTHONPATH=$(pwd)/mason_packages/.link/lib/python2.7/site-packages:${PYTHONPATH} ./configure CUSTOM_LDFLAGS='--coverage' CUSTOM_CXXFLAGS='--coverage' CUSTOM_CFLAGS='--coverage' DEBUG=True;
- ./configure elif [[ ${MASON_PUBLISH} == true ]]; then
export MASON_NAME=mapnik;
export MASON_VERSION=latest;
export MASON_LIB_FILE=lib/libmapnik-wkt.a;
source ./.mason/mason.sh;
./configure PREFIX=${MASON_PREFIX} PATH_REPLACE='' MAPNIK_BUNDLED_SHARE_DIRECTORY=True RUNTIME_LINK='static';
else
./configure;
fi
- make - make
- git clone --depth=1 https://github.com/mapbox/mapnik-test-data tests/data/mapnik-test-data
- make test - make test
- make bench - if [[ ${COVERAGE} == true ]]; then
./mason_packages/.link/bin/cpp-coveralls --build-root . --gcov-options '\-lp' --exclude mason_packages --exclude .sconf_temp --exclude benchmark --exclude deps --exclude scons --exclude test --exclude demo --exclude docs --exclude fonts --exclude utils > /dev/null;
fi
- if [[ ${COVERAGE} != true ]]; then
make bench;
fi
- if [[ ${MASON_PUBLISH} == true ]]; then
./mason_latest.sh build;
./mason_latest.sh link;
./mason_latest.sh publish;
fi

View file

@ -52,6 +52,7 @@ Mapnik is written by Artem Pavlenko with contributions from:
* Igor Podolskiy * Igor Podolskiy
* Reid Priedhorsky * Reid Priedhorsky
* Brian Quinion * Brian Quinion
* Even Rouault
* Marcin Rudowski * Marcin Rudowski
* Sandro Santilli * Sandro Santilli
* Christopher Schmidt * Christopher Schmidt

View file

@ -8,42 +8,112 @@ For a complete change history, see the git log.
## 3.0.0 ## 3.0.0
- Added new and experimental `dot` symbolizer for fast rendering of points Released: June 30th, 2015
- Improved support for International Text (now uses harfbuzz library for text shaping)
- Uses latest c++11 features for better performance (especially map loading)
- Expressions everywhere: all symbolizer properties can now be data driven expressions (with the exception of `face-name` and `fontset-name` on the `TextSymbolizer`).
- New functions supported in expressions: `exp`, `sin`, `cos`, `tan`, `atan`, `abs`.
- New constants supported in expressions: `PI`, `DEG_TO_RAD`, `RAD_TO_DEG`
- Pattern symbolizers now support SVG input and applying transformations on them dynamically
- Experimental / interface may change: `@variables` can be passed to renderer and evaluated in expressions
- Supports being built with clang++ using `-fvisibility=hidden -flto` for smaller binaries
- Supports being built with Visual Studio 2014 CTP #3
- Shield icons are now pixel snapped for crisp rendering
- `MarkersSymbolizer` now supports `avoid-edges`, `offset`, `geometry-transform`, `simplify` for `line` placement and two new `placement` options called `vertex-last` and `vertex-first` to place a single marker at the end or beginning of a path. Also `clip` is now respected when rendering markers on a LineString
geometry.
- `TextSymbolizer` now supports `smooth`, `simplify`, `halo-opacity`, `halo-comp-op`, and `halo-transform`
- `ShieldSymbolizer` now supports `smooth`, `simplify`, `halo-opacity`, `halo-comp-op`, and `halo-transform`
- New GroupSymbolizer for applying multiple symbolizers in a single layout
Released ...
(Packaged from ...) (Packaged from ...)
Summary: TODO #### Summary
- PostGIS: Added support for rendering 3D and 4D geometries (previously silently skipped) (#44) The 3.0 release is a major milestone for Mapnik and includes many performance and design improvements. The is the first release to provide text shaping using the harfbuzz library. This harfbuzz support unlocks improved rendering and layer for many new languages, particularly SE Asian scripts. The internal storage for working with images and geometries has been made more flexible, faster, and strongly typed. The python bindings that were previously bundled with Mapnik have now been moved to <https://github.com/mapnik/python-mapnik> and are versioned independently.
#### Notice
- Mapnik 3.0.0 requires a compiler capable of `std=c++11`.
- It is highly recommended you use the `clang++` compiler on both OS X and Linux since it has robust c++11 support lower memory requirements.
##### Major Changes
- Improved support for International Text (now uses harfbuzz library for text shaping)
- Uses latest C++11 features for better performance (especially map loading)
- Expressions everywhere: all symbolizer properties can now be data driven expressions (with the exception of `face-name` and `fontset-name` on the `TextSymbolizer`).
- Rewritten geometry storage based on `std::vector` (#2739)
- Separate storage of polygon exterior rings and interior rings to allow for more robust clipping of parts.
- Enforces consistent winding order per OGC spec (exterior rings are CCW, interior CW)
- Reduced memory consumption for layers with many points
- Ability to adapt Mapnik geometries to boost::geometry operations (in a zero-copy way)
- Ability to have i/o grammars for json/wkt work on geometries rather than paths for better efficiency and simpler code
- Added new and experimental `dot` symbolizer for fast rendering of points
- New functions supported in expressions: `exp`, `sin`, `cos`, `tan`, `atan`, `abs`.
- New constants supported in expressions: `PI`, `DEG_TO_RAD`, `RAD_TO_DEG`
- Added support for a variety of different grayscale images:
- `mapnik.imageType.null`
- `mapnik.imageType.rgba8`
- `mapnik.imageType.gray8`
- `mapnik.imageType.gray8s`
- `mapnik.imageType.gray16`
- `mapnik.imageType.gray16s`
- `mapnik.imageType.gray32`
- `mapnik.imageType.gray32s`
- `mapnik.imageType.gray32f`
- `mapnik.imageType.gray64`
- `mapnik.imageType.gray64s`
- `mapnik.imageType.gray64f`
- Pattern symbolizers now support SVG input and applying transformations on them dynamically
- Experimental / interface may change: `@variables` can be passed to renderer and evaluated in expressions
- Supports being built with clang++ using `-fvisibility=hidden -flto` for smaller binaries
- Supports being built with Visual Studio 2014 CTP #3
- Shield icons are now pixel snapped for crisp rendering
- `MarkersSymbolizer` now supports `avoid-edges`, `offset`, `geometry-transform`, `simplify` for `line` placement and two new `placement` options called `vertex-last` and `vertex-first` to place a single marker at the end or beginning of a path. Also `clip` is now respected when rendering markers on a LineString
geometry.
- `TextSymbolizer` now supports `smooth`, `simplify`, `halo-opacity`, `halo-comp-op`, and `halo-transform`
- `ShieldSymbolizer` now supports `smooth`, `simplify`, `halo-opacity`, `halo-comp-op`, and `halo-transform`
- The `text-transform` property of `TextSymbolizer` now supports `reverse` value to flip direction of text.
- The `TextSymbolizer` now supports `font-feature-settings` for advanced control over Opentype font rendering (https://developer.mozilla.org/en-US/docs/Web/CSS/font-feature-settings)
- New GroupSymbolizer for applying multiple symbolizers in a single layout
- AGG renderer: fixed geometry offsetting to work after smoothing to produce more consistent results (#2202) - AGG renderer: fixed geometry offsetting to work after smoothing to produce more consistent results (#2202)
- AGG renderer: increased `vertex_dist_epsilon` to ensure nearly coincident points are discarded more readily (#2196) - AGG renderer: increased `vertex_dist_epsilon` to ensure nearly coincident points are discarded more readily (#2196)
- GDAL plugin: Added back support for user driven `nodata` on rgb(a) images (#2023) - GDAL plugin
- Now keeps datasets open for the lifetime of the datasource (rather than per featureset)
- Added back support for user driven `nodata` on rgb(a) images (#2023)
- Allowed nodata to override alpha band if set on rgba images (#2023)
- Added `nodata_tolerance` option to set nearby pixels transparent (has similar effect to the `nearblack` program) (#2023)
- At process exit Mapnik core no longer calls `dlclose` on gdal.input (#2716)
- GDAL plugin: Allowed nodata to override alpha band if set on rgba images (#2023) - TopoJSON plugin
- Now supporting optional `bbox` property on layer
- Fixed support for reporting correct `feature.id()`
- Now supports `inline` string for passing data from memory
- Faster parsing via static initialization of grammars
- Fix crash on invalid arc index
- GDAL plugin: Added `nodata_tolerance` option to set nearby pixels transparent (has similar effect to the `nearblack` program) (#2023) - GeoJSON plugin
- Now supporting optional `bbox` property on layer
- Fixed support for reporting correct `feature.id()`
- Now supports `inline` string for passing data from memory
- Faster parsing via static initialization of grammars
- Added support for web fonts: .woff format (#2113) - SQLite plugin
- Fixed support for handling all column types
- CSV Plugin
- Added the ability to pass an `extent` in options
- PostGIS plugin
- Added Async support to - https://github.com/mapnik/mapnik/wiki/PostGIS-Async
- Added support for rendering 3D and 4D geometries (previously silently skipped) (#44)
- Added support for web fonts: `.woff` format (#2113)
- Added missing support for `geometry-transform` in `line-pattern` and `polygon-pattern` symbolizers (#2065) - Added missing support for `geometry-transform` in `line-pattern` and `polygon-pattern` symbolizers (#2065)
@ -51,11 +121,9 @@ Summary: TODO
- Upgraded unifont to `unifont-6.3.20131020` - Upgraded unifont to `unifont-6.3.20131020`
- CSV Plugin: added the ability to pass an `extent` in options
- Fixed crash when rendering to cairo context from python (#2031) - Fixed crash when rendering to cairo context from python (#2031)
- Moved `label-position-tolerance` from unsigned type to double - Moved `label-position-tolerance` from `unsigned` type to `double`
- Added support for more seamless blurring by rendering to a larger internal image to avoid edge effects (#1478) - Added support for more seamless blurring by rendering to a larger internal image to avoid edge effects (#1478)
@ -67,8 +135,6 @@ Summary: TODO
- Added `color-to-alpha` `image-filter` to allow for applying alpha in proportion to color similiarity (#2023) - Added `color-to-alpha` `image-filter` to allow for applying alpha in proportion to color similiarity (#2023)
- Added Async support to PostGIS plugin - https://github.com/mapnik/mapnik/wiki/PostGIS-Async
- Fixed alpha handling bug with `comp-op:dst-over` (#1995) - Fixed alpha handling bug with `comp-op:dst-over` (#1995)
- Fixed alpha handling bug with building-fill-opacity (#2011) - Fixed alpha handling bug with building-fill-opacity (#2011)
@ -133,6 +199,9 @@ are not set. (#1966)
- Added `scale-hsla` image-filter that allows scaling colors in HSL color space. RGB is converted to HSL (hue-saturation-lightness) and then each value (and the original alpha value) is stretched based on the specified scaling values. An example syntax is `scale-hsla(0,1,0,1,0,1,0,1)` which means no change because the full range will be kept (0 for lowest, 1 for highest). Other examples are: 1) `scale-hsla(0,0,0,1,0,1,0,1)` which would force all colors to be red in hue in the same way `scale-hsla(1,1,0,1,0,1,0,1)` would, 2) `scale-hsla(0,1,1,1,0,1,0,1)` which would cause all colors to become fully saturated, 3) `scale-hsla(0,1,1,1,0,1,.5,1)` which would force no colors to be any more transparent than half, and 4) `scale-hsla(0,1,1,1,0,1,0,.5)` which would force all colors to be at least half transparent. (#1954) - Added `scale-hsla` image-filter that allows scaling colors in HSL color space. RGB is converted to HSL (hue-saturation-lightness) and then each value (and the original alpha value) is stretched based on the specified scaling values. An example syntax is `scale-hsla(0,1,0,1,0,1,0,1)` which means no change because the full range will be kept (0 for lowest, 1 for highest). Other examples are: 1) `scale-hsla(0,0,0,1,0,1,0,1)` which would force all colors to be red in hue in the same way `scale-hsla(1,1,0,1,0,1,0,1)` would, 2) `scale-hsla(0,1,1,1,0,1,0,1)` which would cause all colors to become fully saturated, 3) `scale-hsla(0,1,1,1,0,1,.5,1)` which would force no colors to be any more transparent than half, and 4) `scale-hsla(0,1,1,1,0,1,0,.5)` which would force all colors to be at least half transparent. (#1954)
- The `shapeindex` tool now works correctly with point 3d geometry types
## 2.2.0 ## 2.2.0
Released June 3rd, 2013 Released June 3rd, 2013

View file

@ -1,21 +1,27 @@
# Mapnik Installation # Mapnik Installation
Mapnik is cross platform and runs on Linux, Mac OSX, Solaris, *BSD, and Windows. Mapnik runs on Linux, OS X, Windows, and BSD systems.
To configure and build Mapnik do: To configure and build Mapnik do:
```bash ```bash
$ ./configure ./configure
$ make make
``` ```
To trigger parallel compilation you can pass a JOBS value to make: To trigger parallel compilation you can pass a JOBS value to make:
```bash ```bash
$ JOBS=4 make JOBS=4 make
``` ```
(Note that compiling Mapnik needs several GBytes of RAM. If you use parallel compiliation it needs more.) Mapnik needs > 2 GB of RAM to build. If you use parallel compilation it needs more.
If you are on a system with less memory make sure you only build with one JOB:
```bash
JOBS=1 make
```
To use a Python interpreter that is not named `python` for your build, do To use a Python interpreter that is not named `python` for your build, do
something like the following instead: something like the following instead:
@ -29,15 +35,16 @@ NOTE: the above will not work on windows, rather see https://github.com/mapnik/m
Then to run the tests locally (without needing to install): Then to run the tests locally (without needing to install):
make test-local git submodule update --init
make test
Install like: Install like:
sudo make install make install
If you need to uninstall do: If you need to uninstall do:
sudo make uninstall make uninstall
For more details see the `Building` Section below. For more details see the `Building` Section below.
@ -62,7 +69,6 @@ Mapnik Core depends on:
- These libraries are used: - These libraries are used:
- filesystem - filesystem
- system - system
- thread (for python bindings only)
- regex (optionally built with icu regex support) - regex (optionally built with icu regex support)
- program_options (optionally for mapnik command line programs) - program_options (optionally for mapnik command line programs)
* libicuuc >= 4.0 (ideally >= 4.2) - International Components for Unicode * libicuuc >= 4.0 (ideally >= 4.2) - International Components for Unicode
@ -79,19 +85,10 @@ Mapnik Core optionally depends on:
* libwebp - WEBP graphics (Default enabled, if found) * libwebp - WEBP graphics (Default enabled, if found)
* libproj - PROJ.4 projection library (Default enabled, if found) * libproj - PROJ.4 projection library (Default enabled, if found)
Mapnik Python bindings depend on:
* Python 2.5-2.7 or >= 3.2
* Boost python
* simplejson module if using <= 2.5
Note: Python 3.x is supported, see: https://github.com/mapnik/mapnik/wiki/Python3k
Additional optional dependencies: Additional optional dependencies:
* Cairo >= 1.6.0 - Graphics library for output formats like PDF, PS, and SVG * Cairo >= 1.6.0 - Graphics library for output formats like PDF, PS, and SVG
- pkg-config - Required for building with cairo support - pkg-config - Required for building with cairo support
- pycairo - Python bindings for cairo
* PostgreSQL (for PostGIS plugin support) * PostgreSQL (for PostGIS plugin support)
- libpq - PostreSQL libraries - libpq - PostreSQL libraries
- pg_config - PostgreSQL installation capabilities - pg_config - PostgreSQL installation capabilities
@ -160,17 +157,7 @@ For more details on usage see:
You can run the Mapnik tests locally (without installing) like: You can run the Mapnik tests locally (without installing) like:
make test-local # see the Makefile for how this works make test
Or you can install and test like:
make install && make test
Many of the tests are written in python and you can run them individually like:
make install
python tests/python_tests/shapefile_test.py
## Learning Mapnik ## Learning Mapnik
@ -197,4 +184,4 @@ tutorials on how to programmatically use Mapnik.
### Contributers ### Contributers
Read docs/contributing.markdown for resources for getting involved with Mapnik development. Read docs/contributing.md for resources for getting involved with Mapnik development.

View file

@ -12,23 +12,30 @@ all: mapnik
install: install:
$(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1 install $(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1 install
mapnik: python:
# we first build memory intensive files with -j2 if [ ! -d ./bindings/python ]; then git clone git@github.com:mapnik/python-mapnik.git --recursive ./bindings/python; else (cd bindings/python && git pull && git submodule update --init); fi;
$(PYTHON) scons/scons.py -j2 \ make
python bindings/python/test/visual.py -q
src/json/libmapnik-json.a:
# we first build memory intensive files with -j1
$(PYTHON) scons/scons.py -j1 \
--config=cache --implicit-cache --max-drift=1 \ --config=cache --implicit-cache --max-drift=1 \
src/renderer_common/process_group_symbolizer.os \
src/json/libmapnik-json.a \ src/json/libmapnik-json.a \
src/wkt/libmapnik-wkt.a \ src/wkt/libmapnik-wkt.a \
src/css_color_grammar.os \ src/css_color_grammar.os \
src/expression_grammar.os \ src/expression_grammar.os \
src/transform_expression_grammar.os \ src/transform_expression_grammar.os \
src/image_filter_types.os \ src/image_filter_types.os \
src/renderer_common/process_group_symbolizer.os \
src/agg/process_markers_symbolizer.os \ src/agg/process_markers_symbolizer.os \
src/agg/process_group_symbolizer.os \ src/agg/process_group_symbolizer.os \
src/grid/process_markers_symbolizer.os \ src/grid/process_markers_symbolizer.os \
src/grid/process_group_symbolizer.os \ src/grid/process_group_symbolizer.os \
src/cairo/process_markers_symbolizer.os \ src/cairo/process_markers_symbolizer.os \
src/cairo/process_group_symbolizer.os \ src/cairo/process_group_symbolizer.os \
mapnik: src/json/libmapnik-json.a
# then install the rest with -j$(JOBS) # then install the rest with -j$(JOBS)
$(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1 $(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1
@ -40,12 +47,10 @@ clean:
@if test -e ".sconf_temp/"; then rm -r ".sconf_temp/"; fi @if test -e ".sconf_temp/"; then rm -r ".sconf_temp/"; fi
@find ./ -name "*.pyc" -exec rm {} \; @find ./ -name "*.pyc" -exec rm {} \;
@find ./ -name "*.os" -exec rm {} \; @find ./ -name "*.os" -exec rm {} \;
@find ./ -name "*.dylib" -exec rm {} \; @find ./src/ -name "*.dylib" -exec rm {} \;
@find ./ -name "*.so" -exec rm {} \; @find ./src/ -name "*.so" -exec rm {} \;
@find ./ -name "*.o" -exec rm {} \; @find ./ -name "*.o" -exec rm {} \;
@find ./ -name "*.a" -exec rm {} \; @find ./src/ -name "*.a" -exec rm {} \;
@find ./ -name "*.pyc" -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
@ -58,22 +63,13 @@ rebuild:
uninstall: uninstall:
@$(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1 uninstall @$(PYTHON) scons/scons.py -j$(JOBS) --config=cache --implicit-cache --max-drift=1 uninstall
test: test/data:
./run_tests git submodule update --init
test-local: test: ./test/data
make test @./test/run
test-visual: check: test
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:
./tests/cpp_tests/run
check: test-local
bench: bench:
./benchmark/run ./benchmark/run
@ -88,10 +84,16 @@ pep8:
@pep8 -r --select=W391 -q --filename=*.py `pwd`/tests/ | xargs gsed -i -e :a -e '/^\n*$$/{$$d;N;ba' -e '}' @pep8 -r --select=W391 -q --filename=*.py `pwd`/tests/ | xargs gsed -i -e :a -e '/^\n*$$/{$$d;N;ba' -e '}'
@pep8 -r --select=W391 -q --filename=*.py `pwd`/tests/ | xargs ged -i '/./,/^$$/!d' @pep8 -r --select=W391 -q --filename=*.py `pwd`/tests/ | xargs ged -i '/./,/^$$/!d'
# note: pass --gen-suppressions=yes to create new suppression entries
grind: grind:
@for FILE in tests/cpp_tests/*-bin; do \ @source localize.sh && \
valgrind --leak-check=full --log-fd=1 $${FILE} | grep definitely; \ valgrind --suppressions=./test/unit/valgrind.supp --leak-check=full --log-fd=1 ./test/visual/run | grep definitely;
@source localize.sh && \
for FILE in test/standalone/*-bin; do \
valgrind --suppressions=./test/unit/valgrind.supp --leak-check=full --log-fd=1 $${FILE} | grep definitely; \
done done
@source localize.sh && \
valgrind --suppressions=./test/unit/valgrind.supp --leak-check=full --log-fd=1 ./test/unit/run | grep definitely;
render: render:
@for FILE in tests/data/good_maps/*xml; do \ @for FILE in tests/data/good_maps/*xml; do \

View file

@ -39,13 +39,11 @@ severities = ['debug', 'warn', 'error', 'none']
ICU_INCLUDES_DEFAULT='/usr/include' ICU_INCLUDES_DEFAULT='/usr/include'
ICU_LIBS_DEFAULT='/usr/' ICU_LIBS_DEFAULT='/usr/'
DEFAULT_CC = "gcc" DEFAULT_CC = "cc"
DEFAULT_CXX = "g++" DEFAULT_CXX = "c++"
DEFAULT_CXX11_CXXFLAGS = " -std=c++11" DEFAULT_CXX11_CXXFLAGS = " -std=c++11"
DEFAULT_CXX11_LINKFLAGS = "" DEFAULT_CXX11_LINKFLAGS = ""
if sys.platform == 'darwin': if sys.platform == 'darwin':
DEFAULT_CC = "clang"
DEFAULT_CXX = "clang++"
# homebrew default # homebrew default
ICU_INCLUDES_DEFAULT='/usr/local/opt/icu4c/include/' ICU_INCLUDES_DEFAULT='/usr/local/opt/icu4c/include/'
ICU_LIBS_DEFAULT='/usr/local/opt/icu4c/' ICU_LIBS_DEFAULT='/usr/local/opt/icu4c/'
@ -66,17 +64,20 @@ BOOST_SEARCH_PREFIXES = ['/usr/local','/opt/local','/sw','/usr',]
BOOST_MIN_VERSION = '1.47' BOOST_MIN_VERSION = '1.47'
#CAIRO_MIN_VERSION = '1.8.0' #CAIRO_MIN_VERSION = '1.8.0'
HARFBUZZ_MIN_VERSION = (0, 9, 34)
HARFBUZZ_MIN_VERSION_STRING = "%s.%s.%s" % HARFBUZZ_MIN_VERSION
DEFAULT_LINK_PRIORITY = ['internal','other','frameworks','user','system'] DEFAULT_LINK_PRIORITY = ['internal','other','frameworks','user','system']
pretty_dep_names = { pretty_dep_names = {
'ociei':'Oracle database library | configure with OCCI_LIBS & OCCI_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/OCCI', 'clntsh':'Oracle database library | configure with OCCI_LIBS & OCCI_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/OCCI',
'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 | more info: https://github.com/mapnik/mapnik/wiki/PostGIS', 'pg':'Postgres C Library required for PostGIS plugin | configure with pg_config program or configure with PG_LIBS & PG_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/PostGIS',
'sqlite3':'SQLite3 C Library | configure with SQLITE_LIBS & SQLITE_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/SQLite', 'sqlite3':'SQLite3 C Library | configure with SQLITE_LIBS & SQLITE_INCLUDES | more info: https://github.com/mapnik/mapnik/wiki/SQLite',
'jpeg':'JPEG C library | configure with JPEG_LIBS & JPEG_INCLUDES', 'jpeg':'JPEG C library | configure with JPEG_LIBS & JPEG_INCLUDES',
'tiff':'TIFF C library | configure with TIFF_LIBS & TIFF_INCLUDES', 'tiff':'TIFF C library | configure with TIFF_LIBS & TIFF_INCLUDES',
@ -84,10 +85,12 @@ pretty_dep_names = {
'webp':'WEBP C library | configure with WEBP_LIBS & WEBP_INCLUDES', 'webp':'WEBP C library | configure with WEBP_LIBS & WEBP_INCLUDES',
'icuuc':'ICU C++ library | configure with ICU_LIBS & ICU_INCLUDES or use ICU_LIB_NAME to specify custom lib name | more info: http://site.icu-project.org/', 'icuuc':'ICU C++ library | configure with ICU_LIBS & ICU_INCLUDES or use ICU_LIB_NAME to specify custom lib name | more info: http://site.icu-project.org/',
'harfbuzz':'HarfBuzz text shaping library | configure with HB_LIBS & HB_INCLUDES', 'harfbuzz':'HarfBuzz text shaping library | configure with HB_LIBS & HB_INCLUDES',
'harfbuzz-min-version':'HarfBuzz >= %s (required for font-feature-settings support)' % HARFBUZZ_MIN_VERSION_STRING,
'z':'Z compression library | more info: http://www.zlib.net/', 'z':'Z compression library | more info: http://www.zlib.net/',
'm':'Basic math library, part of C++ stlib', 'm':'Basic math library, part of C++ stlib',
'pkg-config':'pkg-config tool | more info: http://pkg-config.freedesktop.org', 'pkg-config':'pkg-config tool | more info: http://pkg-config.freedesktop.org',
'pg_config':'pg_config program | try setting PG_CONFIG SCons option', 'pg_config':'pg_config program | try setting PG_CONFIG SCons option',
'pq':'libpq library (postgres client) | try setting PG_CONFIG SCons option or configure with PG_LIBS & PG_INCLUDES',
'xml2-config':'xml2-config program | try setting XML2_CONFIG SCons option or avoid the need for xml2-config command by configuring with XML2_LIBS & XML2_INCLUDES', 'xml2-config':'xml2-config program | try setting XML2_CONFIG SCons option or avoid the need for xml2-config command by configuring with XML2_LIBS & XML2_INCLUDES',
'libxml2':'libxml2 library | try setting XML2_CONFIG SCons option to point to location of xml2-config program or configure with XML2_LIBS & XML2_INCLUDES', 'libxml2':'libxml2 library | try setting XML2_CONFIG SCons option to point to location of xml2-config program or configure with XML2_LIBS & XML2_INCLUDES',
'gdal-config':'gdal-config program | try setting GDAL_CONFIG SCons option', 'gdal-config':'gdal-config program | try setting GDAL_CONFIG SCons option',
@ -108,7 +111,7 @@ PLUGINS = { # plugins with external dependencies
'gdal': {'default':True,'path':None,'inc':'gdal_priv.h','lib':'gdal','lang':'C++'}, 'gdal': {'default':True,'path':None,'inc':'gdal_priv.h','lib':'gdal','lang':'C++'},
'ogr': {'default':True,'path':None,'inc':'ogrsf_frmts.h','lib':'gdal','lang':'C++'}, 'ogr': {'default':True,'path':None,'inc':'ogrsf_frmts.h','lib':'gdal','lang':'C++'},
# configured with custom paths, hence 'path': PREFIX/INCLUDES/LIBS # configured with custom paths, hence 'path': PREFIX/INCLUDES/LIBS
'occi': {'default':False,'path':'OCCI','inc':'occi.h','lib':'ociei','lang':'C++'}, 'occi': {'default':False,'path':'OCCI','inc':'occi.h','lib':'clntsh','lang':'C++'},
'sqlite': {'default':True,'path':'SQLITE','inc':'sqlite3.h','lib':'sqlite3','lang':'C'}, 'sqlite': {'default':True,'path':'SQLITE','inc':'sqlite3.h','lib':'sqlite3','lang':'C'},
'rasterlite': {'default':False,'path':'RASTERLITE','inc':['sqlite3.h','rasterlite.h'],'lib':'rasterlite','lang':'C'}, 'rasterlite': {'default':False,'path':'RASTERLITE','inc':['sqlite3.h','rasterlite.h'],'lib':'rasterlite','lang':'C'},
@ -121,8 +124,7 @@ PLUGINS = { # plugins with external dependencies
'raster': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'raster': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
'geojson': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'geojson': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
'geobuf': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'geobuf': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
'topojson':{'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'topojson':{'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}
'python': {'default':False,'path':None,'inc':None,'lib':None,'lang':'C++'},
} }
@ -138,6 +140,9 @@ def init_environment(env):
env = Environment(ENV=os.environ) env = Environment(ENV=os.environ)
init_environment(env) init_environment(env)
def fix_path(path):
return os.path.abspath(path)
def color_print(color,text,newline=True): def color_print(color,text,newline=True):
# 1 - red # 1 - red
# 2 - green # 2 - green
@ -301,7 +306,7 @@ opts.AddVariables(
('WARNING_CXXFLAGS', 'Compiler flags you can set to reduce warning levels which are placed after -Wall.', ''), ('WARNING_CXXFLAGS', 'Compiler flags you can set to reduce warning levels which are placed after -Wall.', ''),
# SCons build behavior options # SCons build behavior options
('HOST', 'Set the target host for cross compiling"', ''), ('HOST', 'Set the target host for cross compiling', ''),
('CONFIG', "The path to the python file in which to save user configuration options. Currently : '%s'" % SCONS_LOCAL_CONFIG,SCONS_LOCAL_CONFIG), ('CONFIG', "The path to the python file in which to save user configuration options. Currently : '%s'" % SCONS_LOCAL_CONFIG,SCONS_LOCAL_CONFIG),
BoolVariable('USE_CONFIG', "Use SCons user '%s' file (will also write variables after successful configuration)", 'True'), BoolVariable('USE_CONFIG', "Use SCons user '%s' file (will also write variables after successful configuration)", 'True'),
# http://www.scons.org/wiki/GoFastButton # http://www.scons.org/wiki/GoFastButton
@ -313,12 +318,12 @@ 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 :)', ''),
('PATH_REPLACE', 'Two path prefixes (divided with a :) to search/replace from all known command and compile paths', ''), ('PATH_REPLACE', 'Two path prefixes (divided with a :) to search/replace from all known command and compile paths', ''),
('MAPNIK_NAME', 'Name of library', 'mapnik'), ('MAPNIK_NAME', 'Name of library', 'mapnik'),
BoolVariable('MAPNIK_BUNDLED_SHARE_DIRECTORY', 'For portable packaging: instruct mapnik-config to report relative paths to bundled GDAL_DATA, PROJ_LIB, and ICU_DATA','False'),
# Boost variables # Boost variables
# default is '/usr/include', see FindBoost method below # default is '/usr/include', see FindBoost method below
@ -328,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'),
@ -353,6 +357,8 @@ opts.AddVariables(
BoolVariable('PROJ', 'Build Mapnik with proj4 support to enable transformations between many different projections', 'True'), BoolVariable('PROJ', 'Build Mapnik with proj4 support to enable transformations between many different projections', 'True'),
PathVariable('PROJ_INCLUDES', 'Search path for PROJ.4 include files', '/usr/include', PathVariable.PathAccept), PathVariable('PROJ_INCLUDES', 'Search path for PROJ.4 include files', '/usr/include', PathVariable.PathAccept),
PathVariable('PROJ_LIBS', 'Search path for PROJ.4 library files', '/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept), PathVariable('PROJ_LIBS', 'Search path for PROJ.4 library files', '/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept),
('PG_INCLUDES', 'Search path for libpq (postgres client) include files', ''),
('PG_LIBS', 'Search path for libpq (postgres client) library files', ''),
('FREETYPE_INCLUDES', 'Search path for Freetype include files', ''), ('FREETYPE_INCLUDES', 'Search path for Freetype include files', ''),
('FREETYPE_LIBS', 'Search path for Freetype library files', ''), ('FREETYPE_LIBS', 'Search path for Freetype library files', ''),
('XML2_INCLUDES', 'Search path for libxml2 include files', ''), ('XML2_INCLUDES', 'Search path for libxml2 include files', ''),
@ -394,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'),
@ -408,7 +410,6 @@ opts.AddVariables(
BoolVariable('SVG2PNG', 'Compile and install a utility to generate render an svg file to a png on the command line', 'False'), BoolVariable('SVG2PNG', 'Compile and install a utility to generate render an svg file to a png on the command line', 'False'),
BoolVariable('NIK2IMG', 'Compile and install a utility to generate render a map to an image', 'True'), BoolVariable('NIK2IMG', 'Compile and install a utility to generate render a map to an image', 'True'),
BoolVariable('COLOR_PRINT', 'Print build status information in color', 'True'), BoolVariable('COLOR_PRINT', 'Print build status information in color', 'True'),
BoolVariable('SAMPLE_INPUT_PLUGINS', 'Compile and install sample plugins', 'False'),
BoolVariable('BIGINT', 'Compile support for 64-bit integers in mapnik::value', 'True'), BoolVariable('BIGINT', 'Compile support for 64-bit integers in mapnik::value', 'True'),
) )
@ -443,18 +444,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',
'PKG_CONFIG_PATH', 'PKG_CONFIG_PATH',
'PATH', 'PATH',
'PATH_REMOVE', 'PATH_REMOVE',
@ -466,6 +461,7 @@ pickle_store = [# Scons internal variables
'MAPNIK_INPUT_PLUGINS_DEST', 'MAPNIK_INPUT_PLUGINS_DEST',
'MAPNIK_FONTS', 'MAPNIK_FONTS',
'MAPNIK_FONTS_DEST', 'MAPNIK_FONTS_DEST',
'MAPNIK_BUNDLED_SHARE_DIRECTORY',
'MAPNIK_LIB_BASE', 'MAPNIK_LIB_BASE',
'MAPNIK_LIB_BASE_DEST', 'MAPNIK_LIB_BASE_DEST',
'EXTRA_FREETYPE_LIBS', 'EXTRA_FREETYPE_LIBS',
@ -674,8 +670,8 @@ def parse_pg_config(context, config):
if ret: if ret:
lib_path = call('%s --libdir' % env[config]) lib_path = call('%s --libdir' % env[config])
inc_path = call('%s --includedir' % env[config]) inc_path = call('%s --includedir' % env[config])
env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
lpq = env['PLUGINS']['postgis']['lib'] lpq = env['PLUGINS']['postgis']['lib']
env.Append(LIBS = lpq) env.Append(LIBS = lpq)
else: else:
@ -776,8 +772,8 @@ def FindBoost(context, prefixes, thread_flag):
env['BOOST_APPEND'] = '-'.join(append_params) env['BOOST_APPEND'] = '-'.join(append_params)
msg += '\nFound boost lib name extension: %s' % env['BOOST_APPEND'] msg += '\nFound boost lib name extension: %s' % env['BOOST_APPEND']
env.AppendUnique(CPPPATH = os.path.realpath(env['BOOST_INCLUDES'])) env.AppendUnique(CPPPATH = fix_path(env['BOOST_INCLUDES']))
env.AppendUnique(LIBPATH = os.path.realpath(env['BOOST_LIBS'])) env.AppendUnique(LIBPATH = fix_path(env['BOOST_LIBS']))
if env['COLOR_PRINT']: if env['COLOR_PRINT']:
msg = "\033[94m%s\033[0m" % (msg) msg = "\033[94m%s\033[0m" % (msg)
ret = context.Result(msg) ret = context.Result(msg)
@ -874,6 +870,24 @@ return 0;
context.Result(ret[0]) context.Result(ret[0])
return ret[1].strip() return ret[1].strip()
def CheckBoostScopedEnum(context, silent=False):
if not silent:
context.Message('Checking whether Boost was compiled with C++11 scoped enums ... ')
ret = context.TryLink("""
#include <boost/filesystem.hpp>
int main()
{
boost::filesystem::path a, b;
boost::filesystem::copy_file(a, b);
return 0;
}
""", '.cpp')
if silent:
context.did_show_result=1
context.Result(ret)
return ret
def icu_at_least_four_two(context): def icu_at_least_four_two(context):
ret = context.TryRun(""" ret = context.TryRun("""
@ -903,6 +917,35 @@ int main()
color_print(1,'\nFound insufficient icu version... %s' % result) color_print(1,'\nFound insufficient icu version... %s' % result)
return False return False
def harfbuzz_version(context):
ret = context.TryRun("""
#include "harfbuzz/hb.h"
#include <iostream>
int main()
{
std::cout << HB_VERSION_ATLEAST(%s, %s, %s) << ";" << HB_VERSION_STRING;
return 0;
}
""" % HARFBUZZ_MIN_VERSION, '.cpp')
# hack to avoid printed output
context.Message('Checking for HarfBuzz version >= %s... ' % HARFBUZZ_MIN_VERSION_STRING)
context.did_show_result=1
result = ret[1].strip()
if not result:
context.Result('error, could not get version from hb.h')
return False
items = result.split(';')
if items[0] == '1':
color_print(4,'found: HarfBuzz %s' % items[1])
return True
color_print(1,'\nHarfbuzz >= %s required but found ... %s' % (HARFBUZZ_MIN_VERSION_STRING,items[1]))
return False
def boost_regex_has_icu(context): def boost_regex_has_icu(context):
if env['RUNTIME_LINK'] == 'static': if env['RUNTIME_LINK'] == 'static':
# re-order icu libs to ensure linux linker is happy # re-order icu libs to ensure linux linker is happy
@ -1023,9 +1066,11 @@ conf_tests = { 'prioritize_paths' : prioritize_paths,
'get_pkg_lib' : get_pkg_lib, 'get_pkg_lib' : get_pkg_lib,
'rollback_option' : rollback_option, 'rollback_option' : rollback_option,
'icu_at_least_four_two' : icu_at_least_four_two, 'icu_at_least_four_two' : icu_at_least_four_two,
'harfbuzz_version' : harfbuzz_version,
'boost_regex_has_icu' : boost_regex_has_icu, 'boost_regex_has_icu' : boost_regex_has_icu,
'sqlite_has_rtree' : sqlite_has_rtree, 'sqlite_has_rtree' : sqlite_has_rtree,
'supports_cxx11' : supports_cxx11, 'supports_cxx11' : supports_cxx11,
'CheckBoostScopedEnum' : CheckBoostScopedEnum,
} }
def GetMapnikLibVersion(): def GetMapnikLibVersion():
@ -1106,7 +1151,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):
@ -1127,7 +1171,7 @@ if not preconfigured:
# install prefix is a pre-pended base location to # install prefix is a pre-pended base location to
# re-route the install and only intended for package building # re-route the install and only intended for package building
# we normalize to ensure no trailing slash and proper pre-pending to the absolute prefix # we normalize to ensure no trailing slash and proper pre-pending to the absolute prefix
install_prefix = os.path.normpath(os.path.realpath(env['DESTDIR'])) + os.path.realpath(env['PREFIX']) install_prefix = os.path.normpath(fix_path(env['DESTDIR'])) + fix_path(env['PREFIX'])
env['INSTALL_PREFIX'] = strip_first(install_prefix,'//','/') env['INSTALL_PREFIX'] = strip_first(install_prefix,'//','/')
# all values from above based on install_prefix # all values from above based on install_prefix
# if env['DESTDIR'] == '/' these should be unchanged # if env['DESTDIR'] == '/' these should be unchanged
@ -1145,11 +1189,11 @@ if not preconfigured:
env['MAPNIK_LIB_NAME'] = '${SHLIBPREFIX}${MAPNIK_NAME}${SHLIBSUFFIX}' env['MAPNIK_LIB_NAME'] = '${SHLIBPREFIX}${MAPNIK_NAME}${SHLIBSUFFIX}'
if env['PKG_CONFIG_PATH']: if env['PKG_CONFIG_PATH']:
env['ENV']['PKG_CONFIG_PATH'] = os.path.realpath(env['PKG_CONFIG_PATH']) env['ENV']['PKG_CONFIG_PATH'] = fix_path(env['PKG_CONFIG_PATH'])
# otherwise this variable == os.environ["PKG_CONFIG_PATH"] # otherwise this variable == os.environ["PKG_CONFIG_PATH"]
if env['PATH']: if env['PATH']:
env['ENV']['PATH'] = os.path.realpath(env['PATH']) + ':' + env['ENV']['PATH'] env['ENV']['PATH'] = fix_path(env['PATH']) + ':' + env['ENV']['PATH']
if env['SYSTEM_FONTS']: if env['SYSTEM_FONTS']:
if not os.path.isdir(env['SYSTEM_FONTS']): if not os.path.isdir(env['SYSTEM_FONTS']):
@ -1198,8 +1242,8 @@ if not preconfigured:
for required in ('ICU', 'SQLITE', 'HB'): for required in ('ICU', 'SQLITE', 'HB'):
inc_path = env['%s_INCLUDES' % required] inc_path = env['%s_INCLUDES' % required]
lib_path = env['%s_LIBS' % required] lib_path = env['%s_LIBS' % required]
env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
REQUIRED_LIBSHEADERS = [ REQUIRED_LIBSHEADERS = [
['z', 'zlib.h', True,'C'], ['z', 'zlib.h', True,'C'],
@ -1208,13 +1252,13 @@ if not preconfigured:
] ]
if env.get('FREETYPE_LIBS') or env.get('FREETYPE_INCLUDES'): if env.get('FREETYPE_LIBS') or env.get('FREETYPE_INCLUDES'):
REQUIRED_LIBSHEADERS.append(['freetype','ft2build.h',True,'C']) REQUIRED_LIBSHEADERS.insert(0,['freetype','ft2build.h',True,'C'])
if env.get('FREETYPE_INCLUDES'): if env.get('FREETYPE_INCLUDES'):
inc_path = env['FREETYPE_INCLUDES'] inc_path = env['FREETYPE_INCLUDES']
env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
if env.get('FREETYPE_LIBS'): if env.get('FREETYPE_LIBS'):
lib_path = env['FREETYPE_LIBS'] lib_path = env['FREETYPE_LIBS']
env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
elif conf.parse_config('FREETYPE_CONFIG'): elif conf.parse_config('FREETYPE_CONFIG'):
# check if freetype links to bz2 # check if freetype links to bz2
if env['RUNTIME_LINK'] == 'static': if env['RUNTIME_LINK'] == 'static':
@ -1231,22 +1275,23 @@ if not preconfigured:
# libxml2 should be optional but is currently not # libxml2 should be optional but is currently not
# https://github.com/mapnik/mapnik/issues/913 # https://github.com/mapnik/mapnik/issues/913
if env.get('XML2_LIBS') or env.get('XML2_INCLUDES'): if env.get('XML2_LIBS') or env.get('XML2_INCLUDES'):
REQUIRED_LIBSHEADERS.append(['libxml2','libxml/parser.h',True,'C']) REQUIRED_LIBSHEADERS.insert(0,['libxml2','libxml/parser.h',True,'C'])
if env.get('XML2_INCLUDES'): if env.get('XML2_INCLUDES'):
inc_path = env['XML2_INCLUDES'] inc_path = env['XML2_INCLUDES']
env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
if env.get('XML2_LIBS'): if env.get('XML2_LIBS'):
lib_path = env['XML2_LIBS'] lib_path = env['XML2_LIBS']
env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
elif conf.parse_config('XML2_CONFIG',checks='--cflags'): elif conf.parse_config('XML2_CONFIG',checks='--cflags'):
env['HAS_LIBXML2'] = True env['HAS_LIBXML2'] = True
else: else:
env['MISSING_DEPS'].append('libxml2') env['MISSING_DEPS'].append('libxml2')
if conf.CheckHasDlfcn(): if not env['HOST']:
env.Append(CPPDEFINES = '-DMAPNIK_HAS_DLCFN') if conf.CheckHasDlfcn():
else: env.Append(CPPDEFINES = '-DMAPNIK_HAS_DLCFN')
env['SKIPPED_DEPS'].extend(['dlfcn']) else:
env['SKIPPED_DEPS'].extend(['dlfcn'])
OPTIONAL_LIBSHEADERS = [] OPTIONAL_LIBSHEADERS = []
@ -1254,8 +1299,8 @@ if not preconfigured:
OPTIONAL_LIBSHEADERS.append(['jpeg', ['stdio.h', 'jpeglib.h'], False,'C','-DHAVE_JPEG']) OPTIONAL_LIBSHEADERS.append(['jpeg', ['stdio.h', 'jpeglib.h'], False,'C','-DHAVE_JPEG'])
inc_path = env['%s_INCLUDES' % 'JPEG'] inc_path = env['%s_INCLUDES' % 'JPEG']
lib_path = env['%s_LIBS' % 'JPEG'] lib_path = env['%s_LIBS' % 'JPEG']
env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
else: else:
env['SKIPPED_DEPS'].extend(['jpeg']) env['SKIPPED_DEPS'].extend(['jpeg'])
@ -1263,8 +1308,8 @@ if not preconfigured:
OPTIONAL_LIBSHEADERS.append(['proj', 'proj_api.h', False,'C','-DMAPNIK_USE_PROJ4']) OPTIONAL_LIBSHEADERS.append(['proj', 'proj_api.h', False,'C','-DMAPNIK_USE_PROJ4'])
inc_path = env['%s_INCLUDES' % 'PROJ'] inc_path = env['%s_INCLUDES' % 'PROJ']
lib_path = env['%s_LIBS' % 'PROJ'] lib_path = env['%s_LIBS' % 'PROJ']
env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
else: else:
env['SKIPPED_DEPS'].extend(['proj']) env['SKIPPED_DEPS'].extend(['proj'])
@ -1272,8 +1317,8 @@ if not preconfigured:
OPTIONAL_LIBSHEADERS.append(['png', 'png.h', False,'C','-DHAVE_PNG']) OPTIONAL_LIBSHEADERS.append(['png', 'png.h', False,'C','-DHAVE_PNG'])
inc_path = env['%s_INCLUDES' % 'PNG'] inc_path = env['%s_INCLUDES' % 'PNG']
lib_path = env['%s_LIBS' % 'PNG'] lib_path = env['%s_LIBS' % 'PNG']
env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
else: else:
env['SKIPPED_DEPS'].extend(['png']) env['SKIPPED_DEPS'].extend(['png'])
@ -1281,8 +1326,8 @@ if not preconfigured:
OPTIONAL_LIBSHEADERS.append(['webp', 'webp/decode.h', False,'C','-DHAVE_WEBP']) OPTIONAL_LIBSHEADERS.append(['webp', 'webp/decode.h', False,'C','-DHAVE_WEBP'])
inc_path = env['%s_INCLUDES' % 'WEBP'] inc_path = env['%s_INCLUDES' % 'WEBP']
lib_path = env['%s_LIBS' % 'WEBP'] lib_path = env['%s_LIBS' % 'WEBP']
env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
else: else:
env['SKIPPED_DEPS'].extend(['webp']) env['SKIPPED_DEPS'].extend(['webp'])
@ -1290,8 +1335,8 @@ if not preconfigured:
OPTIONAL_LIBSHEADERS.append(['tiff', 'tiff.h', False,'C','-DHAVE_TIFF']) OPTIONAL_LIBSHEADERS.append(['tiff', 'tiff.h', False,'C','-DHAVE_TIFF'])
inc_path = env['%s_INCLUDES' % 'TIFF'] inc_path = env['%s_INCLUDES' % 'TIFF']
lib_path = env['%s_LIBS' % 'TIFF'] lib_path = env['%s_LIBS' % 'TIFF']
env.AppendUnique(CPPPATH = os.path.realpath(inc_path)) env.AppendUnique(CPPPATH = fix_path(inc_path))
env.AppendUnique(LIBPATH = os.path.realpath(lib_path)) env.AppendUnique(LIBPATH = fix_path(lib_path))
else: else:
env['SKIPPED_DEPS'].extend(['tiff']) env['SKIPPED_DEPS'].extend(['tiff'])
@ -1300,7 +1345,7 @@ if not preconfigured:
conf.prioritize_paths(silent=True) conf.prioritize_paths(silent=True)
# test for C++11 support, which is required # test for C++11 support, which is required
if not conf.supports_cxx11(): if not env['HOST'] and not conf.supports_cxx11():
color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler to at least g++ 4.7 (ideally 4.8)") color_print(1,"C++ compiler does not support C++11 standard (-std=c++11), which is required. Please upgrade your compiler to at least g++ 4.7 (ideally 4.8)")
Exit(1) Exit(1)
@ -1313,12 +1358,15 @@ if not preconfigured:
else: else:
color_print(4, 'Could not find optional header or shared library for %s' % libname) color_print(4, 'Could not find optional header or shared library for %s' % libname)
env['SKIPPED_DEPS'].append(libname) env['SKIPPED_DEPS'].append(libname)
else:
if not env['HOST']: if libname == env['ICU_LIB_NAME']:
if env['ICU_LIB_NAME'] not in env['MISSING_DEPS']: if env['ICU_LIB_NAME'] not in env['MISSING_DEPS']:
if not conf.icu_at_least_four_two(): if not conf.icu_at_least_four_two():
# expression_string.cpp and map.cpp use fromUTF* function only available in >= ICU 4.2 # expression_string.cpp and map.cpp use fromUTF* function only available in >= ICU 4.2
env['MISSING_DEPS'].append(env['ICU_LIB_NAME']) env['MISSING_DEPS'].append(env['ICU_LIB_NAME'])
elif libname == 'harfbuzz':
if not conf.harfbuzz_version():
env['SKIPPED_DEPS'].append('harfbuzz-min-version')
if env['BIGINT']: if env['BIGINT']:
env.Append(CPPDEFINES = '-DBIGINT') env.Append(CPPDEFINES = '-DBIGINT')
@ -1382,6 +1430,19 @@ if not preconfigured:
color_print(4,'Could not find optional header or shared library for boost %s' % libinfo[0]) color_print(4,'Could not find optional header or shared library for boost %s' % libinfo[0])
env['SKIPPED_DEPS'].append('boost ' + libinfo[0]) env['SKIPPED_DEPS'].append('boost ' + libinfo[0])
# Boost versions before 1.57 are broken when the system package and
# Mapnik are compiled against different standards. On Ubuntu 14.04
# using boost 1.54, it breaks scoped enums. It's a bit of a hack to
# just turn it off like this, but seems the only available work-
# around. See https://svn.boost.org/trac/boost/ticket/6779 for more
# details.
boost_version = [int(x) for x in env.get('BOOST_LIB_VERSION_FROM_HEADER').split('_')]
if not conf.CheckBoostScopedEnum():
if boost_version < [1, 51]:
env.Append(CXXFLAGS = '-DBOOST_NO_SCOPED_ENUMS')
elif boost_version < [1, 57]:
env.Append(CXXFLAGS = '-DBOOST_NO_CXX11_SCOPED_ENUMS')
if not env['HOST'] and env['ICU_LIB_NAME'] not in env['MISSING_DEPS']: if not env['HOST'] and env['ICU_LIB_NAME'] not in env['MISSING_DEPS']:
# http://lists.boost.org/Archives/boost/2009/03/150076.php # http://lists.boost.org/Archives/boost/2009/03/150076.php
# we need libicui18n if using static boost libraries, so it is # we need libicui18n if using static boost libraries, so it is
@ -1436,7 +1497,22 @@ if not preconfigured:
else: else:
details['lib'] = libname details['lib'] = libname
elif plugin == 'postgis' or plugin == 'pgraster': elif plugin == 'postgis' or plugin == 'pgraster':
conf.parse_pg_config('PG_CONFIG') if env.get('PG_LIBS') or env.get('PG_INCLUDES'):
libname = details['lib']
if env.get('PG_INCLUDES'):
inc_path = env['PG_INCLUDES']
env.AppendUnique(CPPPATH = fix_path(inc_path))
if env.get('PG_LIBS'):
lib_path = env['PG_LIBS']
env.AppendUnique(LIBPATH = fix_path(lib_path))
if not conf.CheckLibWithHeader(libname, details['inc'], details['lang']):
env['SKIPPED_DEPS'].append(libname)
if libname in env['LIBS']:
env['LIBS'].remove(libname)
else:
details['lib'] = libname
else:
conf.parse_pg_config('PG_CONFIG')
elif plugin == 'ogr': elif plugin == 'ogr':
if conf.ogr_enabled(): if conf.ogr_enabled():
if conf.parse_config('GDAL_CONFIG',checks='--libs'): if conf.parse_config('GDAL_CONFIG',checks='--libs'):
@ -1456,8 +1532,8 @@ if not preconfigured:
# to the beginning of the path list even if they already exist # to the beginning of the path list even if they already exist
incpath = env['%s_INCLUDES' % details['path']] incpath = env['%s_INCLUDES' % details['path']]
libpath = env['%s_LIBS' % details['path']] libpath = env['%s_LIBS' % details['path']]
env.PrependUnique(CPPPATH = os.path.realpath(incpath),delete_existing=True) env.PrependUnique(CPPPATH = fix_path(incpath),delete_existing=True)
env.PrependUnique(LIBPATH = os.path.realpath(libpath),delete_existing=True) env.PrependUnique(LIBPATH = fix_path(libpath),delete_existing=True)
if not conf.CheckLibWithHeader(details['lib'], details['inc'], details['lang']): if not conf.CheckLibWithHeader(details['lib'], details['inc'], details['lang']):
env.Replace(**backup) env.Replace(**backup)
env['SKIPPED_DEPS'].append(details['lib']) env['SKIPPED_DEPS'].append(details['lib'])
@ -1505,8 +1581,8 @@ if not preconfigured:
if env['PGSQL2SQLITE']: if env['PGSQL2SQLITE']:
if 'sqlite3' not in env['LIBS']: if 'sqlite3' not in env['LIBS']:
env.AppendUnique(LIBS='sqlite3') env.AppendUnique(LIBS='sqlite3')
env.AppendUnique(CPPPATH = os.path.realpath(env['SQLITE_INCLUDES'])) env.AppendUnique(CPPPATH = fix_path(env['SQLITE_INCLUDES']))
env.AppendUnique(LIBPATH = os.path.realpath(env['SQLITE_LIBS'])) env.AppendUnique(LIBPATH = fix_path(env['SQLITE_LIBS']))
if 'pq' not in env['LIBS']: if 'pq' not in env['LIBS']:
if not conf.parse_pg_config('PG_CONFIG'): if not conf.parse_pg_config('PG_CONFIG'):
env['PGSQL2SQLITE'] = False env['PGSQL2SQLITE'] = False
@ -1518,7 +1594,6 @@ if not preconfigured:
# prepend to make sure we link locally # prepend to make sure we link locally
env.Prepend(CPPPATH = '#deps/agg/include') env.Prepend(CPPPATH = '#deps/agg/include')
env.Prepend(LIBPATH = '#deps/agg') env.Prepend(LIBPATH = '#deps/agg')
env.Prepend(CPPPATH = '#deps/clipper/include')
# prepend deps dir for auxillary headers # prepend deps dir for auxillary headers
env.Prepend(CPPPATH = '#deps') env.Prepend(CPPPATH = '#deps')
@ -1526,11 +1601,11 @@ if not preconfigured:
if env['CAIRO_LIBS'] or env['CAIRO_INCLUDES']: if env['CAIRO_LIBS'] or env['CAIRO_INCLUDES']:
c_inc = env['CAIRO_INCLUDES'] c_inc = env['CAIRO_INCLUDES']
if env['CAIRO_LIBS']: if env['CAIRO_LIBS']:
env["CAIRO_LIBPATHS"].append(os.path.realpath(env['CAIRO_LIBS'])) env["CAIRO_LIBPATHS"].append(fix_path(env['CAIRO_LIBS']))
if not env['CAIRO_INCLUDES']: if not env['CAIRO_INCLUDES']:
c_inc = env['CAIRO_LIBS'].replace('lib','',1) c_inc = env['CAIRO_LIBS'].replace('lib','',1)
if c_inc: if c_inc:
c_inc = os.path.normpath(os.path.realpath(env['CAIRO_INCLUDES'])) c_inc = os.path.normpath(fix_path(env['CAIRO_INCLUDES']))
if c_inc.endswith('include'): if c_inc.endswith('include'):
c_inc = os.path.dirname(c_inc) c_inc = os.path.dirname(c_inc)
env["CAIRO_CPPPATHS"].extend( env["CAIRO_CPPPATHS"].extend(
@ -1588,100 +1663,12 @@ 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'] or 'python' in env['REQUESTED_PLUGINS']:
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']:
# if required dependencies are missing, print warnings and then let SCons finish without building or saving local config # if required dependencies are missing, print warnings and then let SCons finish without building or saving local config
color_print(1,'\nExiting... the following required dependencies were not found:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['MISSING_DEPS']])) color_print(1,'\nExiting... the following required dependencies were not found:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['MISSING_DEPS']]))
color_print(1,"\nSee '%s' for details on possible problems." % (os.path.realpath(SCONS_LOCAL_LOG))) color_print(1,"\nSee '%s' for details on possible problems." % (fix_path(SCONS_LOCAL_LOG)))
if env['SKIPPED_DEPS']: if env['SKIPPED_DEPS']:
color_print(4,'\nAlso, these OPTIONAL dependencies were not found:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['SKIPPED_DEPS']])) color_print(4,'\nAlso, these OPTIONAL dependencies were not found:\n - %s' % '\n - '.join([pretty_dep(dep) for dep in env['SKIPPED_DEPS']]))
color_print(4,"\nSet custom paths to these libraries and header files on the command-line or in a file called '%s'" % SCONS_LOCAL_CONFIG) color_print(4,"\nSet custom paths to these libraries and header files on the command-line or in a file called '%s'" % SCONS_LOCAL_CONFIG)
@ -1745,11 +1732,6 @@ if not preconfigured:
# c++11 support / https://github.com/mapnik/mapnik/issues/1683 # c++11 support / https://github.com/mapnik/mapnik/issues/1683
# - upgrade to PHOENIX_V3 since that is needed for c++11 compile # - upgrade to PHOENIX_V3 since that is needed for c++11 compile
env.Append(CPPDEFINES = '-DBOOST_SPIRIT_USE_PHOENIX_V3=1') env.Append(CPPDEFINES = '-DBOOST_SPIRIT_USE_PHOENIX_V3=1')
if 'clang++' in env['CXX']:
# - workaround boost gil channel_algorithm.hpp narrowing error
# TODO - remove when building against >= 1.55
# https://github.com/mapnik/mapnik/issues/1970
env.Append(CXXFLAGS = '-Wno-c++11-narrowing')
# Enable logging in debug mode (always) and release mode (when specified) # Enable logging in debug mode (always) and release mode (when specified)
if env['DEFAULT_LOG_SEVERITY']: if env['DEFAULT_LOG_SEVERITY']:
@ -1789,8 +1771,8 @@ if not preconfigured:
env.Append(CPPDEFINES = ndebug_defines) env.Append(CPPDEFINES = ndebug_defines)
# Common flags for g++/clang++ CXX compiler. # Common flags for g++/clang++ CXX compiler.
# TODO: clean up code more to make -Wextra -Wsign-compare -Wsign-conversion -Wconversion -Wshadow viable # TODO: clean up code more to make -Wextra -Wsign-compare -Wsign-conversion -Wconversion viable
common_cxx_flags = '-Wall %s %s -ftemplate-depth-300 ' % (env['WARNING_CXXFLAGS'], pthread) common_cxx_flags = '-Wall %s %s -ftemplate-depth-300 -Wsign-compare -Wshadow ' % (env['WARNING_CXXFLAGS'], pthread)
if 'clang++' in env['CXX']: if 'clang++' in env['CXX']:
common_cxx_flags += ' -Wno-unknown-pragmas -Wno-unsequenced ' common_cxx_flags += ' -Wno-unknown-pragmas -Wno-unsequenced '
@ -1806,29 +1788,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'] or 'python' in env['REQUESTED_PLUGINS']:
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 = os.path.realpath(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)
@ -1879,11 +1838,11 @@ if not HELP_REQUESTED:
env['create_uninstall_target'] = create_uninstall_target env['create_uninstall_target'] = create_uninstall_target
if env['PKG_CONFIG_PATH']: if env['PKG_CONFIG_PATH']:
env['ENV']['PKG_CONFIG_PATH'] = os.path.realpath(env['PKG_CONFIG_PATH']) env['ENV']['PKG_CONFIG_PATH'] = fix_path(env['PKG_CONFIG_PATH'])
# otherwise this variable == os.environ["PKG_CONFIG_PATH"] # otherwise this variable == os.environ["PKG_CONFIG_PATH"]
if env['PATH']: if env['PATH']:
env['ENV']['PATH'] = os.path.realpath(env['PATH']) + ':' + env['ENV']['PATH'] env['ENV']['PATH'] = fix_path(env['PATH']) + ':' + env['ENV']['PATH']
if env['PATH_REMOVE']: if env['PATH_REMOVE']:
for p in env['PATH_REMOVE'].split(':'): for p in env['PATH_REMOVE'].split(':'):
@ -2012,40 +1971,20 @@ 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')
# build C++ tests # build C++ tests
SConscript('tests/cpp_tests/build.py') SConscript('test/build.py')
SConscript('tests/cxx/build.py')
if env['BENCHMARK']: if env['BENCHMARK']:
SConscript('benchmark/build.py') SConscript('benchmark/build.py')
if os.path.exists('./bindings/python/build.py'):
SConscript('./bindings/python/build.py')
# install mapnik-config script # install mapnik-config script
SConscript('utils/mapnik-config/build.py') SConscript('utils/mapnik-config/build.py')
# write the viewer.ini file # write the viewer.ini file
SConscript('demo/viewer/build.py') SConscript('demo/viewer/build.py')
# if requested, build the sample input plugins
if env['SAMPLE_INPUT_PLUGINS']:
SConscript('plugins/input/templates/helloworld/build.py')
else:
if 'install' in COMMAND_LINE_TARGETS:
plugin_path = os.path.join(env['MAPNIK_INPUT_PLUGINS_DEST'],'hello.input')
if os.path.exists(plugin_path):
color_print(4,"Notice: removing out of date plugin: '%s'" % plugin_path)
os.unlink(plugin_path)
if os.path.exists('plugins/input/templates/hello.input'):
os.unlink('plugins/input/templates/hello.input')

View file

@ -4,6 +4,8 @@
// mapnik // mapnik
#include <mapnik/params.hpp> #include <mapnik/params.hpp>
#include <mapnik/value_types.hpp> #include <mapnik/value_types.hpp>
#include <mapnik/safe_cast.hpp>
#include "../test/cleanup.hpp"
// stl // stl
#include <chrono> #include <chrono>
@ -25,8 +27,8 @@ protected:
public: public:
test_case(mapnik::parameters const& params) test_case(mapnik::parameters const& params)
: params_(params), : params_(params),
threads_(*params.get<mapnik::value_integer>("threads",0)), threads_(mapnik::safe_cast<std::size_t>(*params.get<mapnik::value_integer>("threads",0))),
iterations_(*params.get<mapnik::value_integer>("iterations",0)) iterations_(mapnik::safe_cast<std::size_t>(*params.get<mapnik::value_integer>("iterations",0)))
{} {}
std::size_t threads() const std::size_t threads() const
{ {
@ -66,11 +68,14 @@ void handle_args(int argc, char** argv, mapnik::parameters & params)
mapnik::parameters params; \ mapnik::parameters params; \
benchmark::handle_args(argc,argv,params); \ benchmark::handle_args(argc,argv,params); \
test_class test_runner(params); \ test_class test_runner(params); \
return run(test_runner,name); \ auto result = run(test_runner,name); \
testing::run_cleanup(); \
return result; \
} \ } \
catch (std::exception const& ex) \ catch (std::exception const& ex) \
{ \ { \
std::clog << ex.what() << "\n"; \ std::clog << ex.what() << "\n"; \
testing::run_cleanup(); \
return -1; \ return -1; \
} \ } \
} \ } \

View file

@ -8,6 +8,7 @@ test_env = env.Clone()
test_env['LIBS'] = [env['MAPNIK_NAME']] test_env['LIBS'] = [env['MAPNIK_NAME']]
test_env.AppendUnique(LIBS=copy(env['LIBMAPNIK_LIBS'])) test_env.AppendUnique(LIBS=copy(env['LIBMAPNIK_LIBS']))
test_env.AppendUnique(LIBS='mapnik-wkt')
if env['PLATFORM'] == 'Linux': if env['PLATFORM'] == 'Linux':
test_env.AppendUnique(LIBS='dl') test_env.AppendUnique(LIBS='dl')
test_env.AppendUnique(LIBS='rt') test_env.AppendUnique(LIBS='rt')
@ -34,7 +35,7 @@ benchmarks = [
#"test_to_double.cpp", #"test_to_double.cpp",
#"test_to_int.cpp", #"test_to_int.cpp",
#"test_utf_encoding.cpp" #"test_utf_encoding.cpp"
#"test_polygon_clipping.cpp", "test_polygon_clipping.cpp",
#"test_polygon_clipping_rendering.cpp", #"test_polygon_clipping_rendering.cpp",
"test_proj_transform1.cpp", "test_proj_transform1.cpp",
"test_expression_parse.cpp", "test_expression_parse.cpp",
@ -42,6 +43,10 @@ benchmarks = [
"test_font_registration.cpp", "test_font_registration.cpp",
"test_rendering.cpp", "test_rendering.cpp",
"test_rendering_shared_map.cpp", "test_rendering_shared_map.cpp",
"test_offset_converter.cpp",
"test_marker_cache.cpp",
"test_quad_tree.cpp",
# "test_numeric_cast_vs_static_cast.cpp",
] ]
for cpp_test in benchmarks: for cpp_test in benchmarks:
test_program = test_env_local.Program('out/'+cpp_test.replace('.cpp',''), source=[cpp_test]) test_program = test_env_local.Program('out/'+cpp_test.replace('.cpp',''), source=[cpp_test])

View file

@ -1,8 +1,7 @@
#ifndef __MAPNIK_COMPARE_IMAGES_HPP__ #ifndef __MAPNIK_COMPARE_IMAGES_HPP__
#define __MAPNIK_COMPARE_IMAGES_HPP__ #define __MAPNIK_COMPARE_IMAGES_HPP__
#include <mapnik/graphics.hpp> #include <mapnik/image.hpp>
#include <mapnik/image_data.hpp>
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/image_reader.hpp> #include <mapnik/image_reader.hpp>
@ -17,27 +16,26 @@ namespace benchmark {
{ {
throw mapnik::image_reader_exception("Failed to load: " + dest_fn); throw mapnik::image_reader_exception("Failed to load: " + dest_fn);
} }
std::shared_ptr<image_32> image_ptr1 = std::make_shared<image_32>(reader1->width(),reader1->height());
reader1->read(0,0,image_ptr1->data());
std::unique_ptr<mapnik::image_reader> reader2(mapnik::get_image_reader(src_fn,"png")); std::unique_ptr<mapnik::image_reader> reader2(mapnik::get_image_reader(src_fn,"png"));
if (!reader2.get()) if (!reader2.get())
{ {
throw mapnik::image_reader_exception("Failed to load: " + src_fn); throw mapnik::image_reader_exception("Failed to load: " + src_fn);
} }
std::shared_ptr<image_32> image_ptr2 = std::make_shared<image_32>(reader2->width(),reader2->height());
reader2->read(0,0,image_ptr2->data());
image_data_rgba8 const& dest = image_ptr1->data(); const image_any desc_any = reader1->read(0,0,reader1->width(), reader1->height());
image_data_rgba8 const& src = image_ptr2->data(); const image_any src_any = reader2->read(0,0,reader2->width(), reader2->height());
image_rgba8 const& dest = util::get<image_rgba8>(desc_any);
image_rgba8 const& src = util::get<image_rgba8>(src_any);
unsigned int width = src.width(); unsigned int width = src.width();
unsigned int height = src.height(); unsigned int height = src.height();
if ((width != dest.width()) || height != dest.height()) return false; if ((width != dest.width()) || height != dest.height()) return false;
for (unsigned int y = 0; y < height; ++y) for (unsigned int y = 0; y < height; ++y)
{ {
const unsigned int* row_from = src.getRow(y); const unsigned int* row_from = src.get_row(y);
const unsigned int* row_to = dest.getRow(y); const unsigned int* row_to = dest.get_row(y);
for (unsigned int x = 0; x < width; ++x) for (unsigned int x = 0; x < width; ++x)
{ {
if (row_from[x] != row_to[x]) return false; if (row_from[x] != row_to[x]) return false;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

View file

@ -18,9 +18,10 @@ function run {
#run test_polygon_clipping 10 1000 #run test_polygon_clipping 10 1000
#run test_polygon_clipping_rendering 10 100 #run test_polygon_clipping_rendering 10 100
run test_proj_transform1 10 100 run test_proj_transform1 10 100
run test_expression_parse 10 10000 run test_expression_parse 10 1000
run test_face_ptr_creation 10 10000 run test_face_ptr_creation 10 1000
run test_font_registration 10 1000 run test_font_registration 10 100
run test_offset_converter 10 1000
./benchmark/out/test_rendering \ ./benchmark/out/test_rendering \
--name "text rendering" \ --name "text rendering" \
@ -48,3 +49,11 @@ run test_font_registration 10 1000
--height 600 \ --height 600 \
--iterations 20 \ --iterations 20 \
--threads 10 --threads 10
./benchmark/out/test_quad_tree \
--iterations 10000 \
--threads 1
./benchmark/out/test_quad_tree \
--iterations 10000 \
--threads 10

View file

@ -24,4 +24,4 @@ public:
} }
}; };
BENCHMARK(test,"font registration") BENCHMARK(test,"font registration")

View file

@ -0,0 +1,42 @@
#include "bench_framework.hpp"
#include <mapnik/marker_cache.hpp>
class test : public benchmark::test_case
{
std::vector<std::string> images_;
public:
test(mapnik::parameters const& params)
: test_case(params),
images_{
"./test/data/images/dummy.jpg",
"./test/data/images/dummy.jpeg",
"./test/data/images/dummy.png",
"./test/data/images/dummy.tif",
"./test/data/images/dummy.tiff",
//"./test/data/images/landusepattern.jpeg", // will fail since it is a png
//"./test/data/images/xcode-CgBI.png", // will fail since its an invalid png
"./test/data/svg/octocat.svg",
"./test/data/svg/place-of-worship-24.svg",
"./test/data/svg/point_sm.svg",
"./test/data/svg/point.svg",
"./test/data/svg/airfield-12.svg"
} {}
bool validate() const
{
return true;
}
bool operator()() const
{
unsigned count = 0;
for (std::size_t i=0;i<iterations_;++i) {
for (auto filename : images_)
{
auto marker = mapnik::marker_cache::instance().find(filename,true);
}
++count;
}
return (count == iterations_);
}
};
BENCHMARK(test,"marker cache")

View file

@ -0,0 +1,87 @@
#include "bench_framework.hpp"
// boost
#include <boost/numeric/conversion/cast.hpp>
static double STEP_NUM = 0.0000000001;
static std::uint8_t START_NUM = 2;
class test_static : public benchmark::test_case
{
double step_;
std::uint8_t start_;
public:
test_static(mapnik::parameters const& params)
: test_case(params),
step_(STEP_NUM),
start_(START_NUM) {}
bool validate() const
{
return true;
}
bool operator()() const
{
double value_ = 0.0;
std::uint8_t x;
for (std::size_t i=0;i<iterations_;++i) {
double c = static_cast<double>(start_) * value_;
if (c >= 256.0) c = 255.0;
if (c < 0.0) c = 0.0;
x = static_cast<std::uint8_t>(c);
value_ += step_;
}
return static_cast<double>(x) < (static_cast<double>(start_) * value_);
}
};
using boost::numeric::positive_overflow;
using boost::numeric::negative_overflow;
class test_numeric : public benchmark::test_case
{
double step_;
std::uint8_t start_;
public:
test_numeric(mapnik::parameters const& params)
: test_case(params),
step_(STEP_NUM),
start_(START_NUM) {}
bool validate() const
{
return true;
}
bool operator()() const
{
double value_ = 0.0;
std::uint8_t x;
for (std::size_t i=0;i<iterations_;++i) {
try {
x = boost::numeric_cast<std::uint8_t>(start_ * value_);
}
catch(negative_overflow&)
{
x = std::numeric_limits<std::uint8_t>::min();
}
catch(positive_overflow&)
{
x = std::numeric_limits<std::uint8_t>::max();
}
value_ += step_;
}
return static_cast<double>(x) < (static_cast<double>(start_) * value_);
}
};
int main(int argc, char** argv)
{
mapnik::parameters params;
benchmark::handle_args(argc,argv,params);
{
test_static test_runner(params);
run(test_runner,"static_cast");
}
{
test_numeric test_runner(params);
run(test_runner,"numeric_cast");
}
return 0;
}

View file

@ -0,0 +1,101 @@
#include "bench_framework.hpp"
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/coord.hpp>
#include <mapnik/vertex.hpp>
#include <mapnik/offset_converter.hpp>
struct fake_path
{
using coord_type = std::tuple<double, double, unsigned>;
using cont_type = std::vector<coord_type>;
cont_type vertices_;
cont_type::iterator itr_;
fake_path(std::initializer_list<double> l)
: fake_path(l.begin(), l.size()) {
}
fake_path(std::vector<double> const &v)
: fake_path(v.begin(), v.size()) {
}
template <typename Itr>
fake_path(Itr itr, size_t sz) {
size_t num_coords = sz >> 1;
vertices_.reserve(num_coords);
for (size_t i = 0; i < num_coords; ++i) {
double x = *itr++;
double y = *itr++;
unsigned cmd = (i == 0) ? mapnik::SEG_MOVETO : mapnik::SEG_LINETO;
vertices_.push_back(std::make_tuple(x, y, cmd));
if (i == num_coords - 1) cmd = mapnik::SEG_END;
vertices_.push_back(std::make_tuple(x, y, cmd));
}
itr_ = vertices_.begin();
}
unsigned vertex(double *x, double *y) {
if (itr_ == vertices_.end()) {
return mapnik::SEG_END;
}
*x = std::get<0>(*itr_);
*y = std::get<1>(*itr_);
unsigned cmd = std::get<2>(*itr_);
++itr_;
return cmd;
}
void rewind(unsigned) {
itr_ = vertices_.begin();
}
};
class test_offset : public benchmark::test_case
{
public:
test_offset(mapnik::parameters const& params)
: test_case(params) {}
bool validate() const
{
return true;
}
bool operator()() const
{
std::vector<double> path;
int mysize = 2500;
int x1 = 0;
path.reserve(mysize*2);
for( int i = 0; i < mysize; i++ )
{
path.push_back( i );
path.push_back( 0 );
}
fake_path fpath(path);
for (std::size_t i=0;i<iterations_;++i) {
mapnik::offset_converter<fake_path> off_path(fpath);
off_path.set_offset(10);
unsigned cmd;
double x, y;
while ((cmd = off_path.vertex(&x, &y)) != mapnik::SEG_END)
{
x1++;
}
}
return x1 > 0;
}
};
int main(int argc, char** argv)
{
mapnik::parameters params;
benchmark::handle_args(argc,argv,params);
{
test_offset test_runner(params);
run(test_runner,"offset_test");
}
return 0;
}

View file

@ -1,10 +1,9 @@
#include "bench_framework.hpp" #include "bench_framework.hpp"
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/graphics.hpp>
class test : public benchmark::test_case class test : public benchmark::test_case
{ {
mapnik::image_data_rgba8 im_; mapnik::image_rgba8 im_;
public: public:
test(mapnik::parameters const& params) test(mapnik::parameters const& params)
: test_case(params), : test_case(params),

View file

@ -3,7 +3,7 @@
class test : public benchmark::test_case class test : public benchmark::test_case
{ {
std::shared_ptr<image_32> im_; std::shared_ptr<image_rgba8> im_;
public: public:
test(mapnik::parameters const& params) test(mapnik::parameters const& params)
: test_case(params) { : test_case(params) {
@ -13,14 +13,14 @@ public:
{ {
throw mapnik::image_reader_exception("Failed to load: " + filename); throw mapnik::image_reader_exception("Failed to load: " + filename);
} }
im_ = std::make_shared<image_32>(reader->width(),reader->height()); im_ = std::make_shared<image_rgba8>(reader->width(),reader->height());
reader->read(0,0,im_->data()); reader->read(0,0,*im_);
} }
bool validate() const bool validate() const
{ {
std::string expected("./benchmark/data/multicolor-hextree-expected.png"); std::string expected("./benchmark/data/multicolor-hextree-expected.png");
std::string actual("./benchmark/data/multicolor-hextree-actual.png"); std::string actual("./benchmark/data/multicolor-hextree-actual.png");
mapnik::save_to_file(im_->data(),actual, "png8:m=h:z=1"); mapnik::save_to_file(*im_,actual, "png8:m=h:z=1");
return benchmark::compare_images(actual,expected); return benchmark::compare_images(actual,expected);
} }
bool operator()() const bool operator()() const
@ -28,7 +28,7 @@ public:
std::string out; std::string out;
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i) {
out.clear(); out.clear();
out = mapnik::save_to_string(im_->data(),"png8:m=h:z=1"); out = mapnik::save_to_string(*im_,"png8:m=h:z=1");
} }
} }
return true; return true;

View file

@ -1,23 +1,24 @@
#include "bench_framework.hpp" #include "bench_framework.hpp"
#include "compare_images.hpp" #include "compare_images.hpp"
#include "agg_conv_clip_polygon.h"
#include <mapnik/geometry.hpp>
#include <mapnik/vertex.hpp> #include <mapnik/vertex.hpp>
#include <mapnik/transform_path_adapter.hpp> #include <mapnik/transform_path_adapter.hpp>
#include <mapnik/view_transform.hpp> #include <mapnik/view_transform.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/wkt/wkt_factory.hpp> #include <mapnik/wkt/wkt_factory.hpp>
#include <mapnik/wkt/wkt_grammar_impl.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/projection.hpp> #include <mapnik/projection.hpp>
#include <mapnik/proj_transform.hpp> #include <mapnik/proj_transform.hpp>
#include <mapnik/util/fs.hpp> #include <mapnik/util/fs.hpp>
#include <mapnik/polygon_clipper.hpp> #include <mapnik/geometry.hpp>
#include <mapnik/vertex_adapters.hpp>
#include <mapnik/geometry_adapters.hpp>
#include <mapnik/geometry_envelope.hpp>
#include <mapnik/geometry_correct.hpp>
#include <mapnik/geometry_is_empty.hpp>
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/color.hpp>
#include <boost/geometry.hpp>
// agg // agg
#include "agg_conv_clip_polygon.h" #include "agg_conv_clip_polygon.h"
// clipper // clipper
#include "agg_conv_clipper.h"
#include "agg_path_storage.h" #include "agg_path_storage.h"
// rendering // rendering
#include "agg_basics.h" #include "agg_basics.h"
@ -29,33 +30,37 @@
// stl // stl
#include <fstream> #include <fstream>
#include <iostream>
#include <cstdlib>
void render(mapnik::geometry_type & geom, void render(mapnik::geometry::multi_polygon<double> const& geom,
mapnik::box2d<double> const& extent, mapnik::box2d<double> const& extent,
std::string const& name) std::string const& name)
{ {
using path_type = mapnik::transform_path_adapter<mapnik::view_transform,mapnik::geometry_type>; using path_type = mapnik::transform_path_adapter<mapnik::view_transform,mapnik::geometry::polygon_vertex_adapter<double>>;
using ren_base = agg::renderer_base<agg::pixfmt_rgba32_plain>; using ren_base = agg::renderer_base<agg::pixfmt_rgba32_plain>;
using renderer = agg::renderer_scanline_aa_solid<ren_base>; using renderer = agg::renderer_scanline_aa_solid<ren_base>;
mapnik::image_32 im(256,256); mapnik::image_rgba8 im(256,256);
im.set_background(mapnik::color("white")); mapnik::fill(im, mapnik::color("white"));
mapnik::box2d<double> padded_extent = extent; mapnik::box2d<double> padded_extent(155,134,665,466);//extent;
padded_extent.pad(10); padded_extent.pad(10);
mapnik::view_transform tr(im.width(),im.height(),padded_extent,0,0); mapnik::view_transform tr(im.width(),im.height(),padded_extent,0,0);
agg::rendering_buffer buf(im.raw_data(),im.width(),im.height(), im.width() * 4); agg::rendering_buffer buf(im.bytes(),im.width(),im.height(), im.row_size());
agg::pixfmt_rgba32_plain pixf(buf); agg::pixfmt_rgba32_plain pixf(buf);
ren_base renb(pixf); ren_base renb(pixf);
renderer ren(renb); renderer ren(renb);
mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326"));
ren.color(agg::rgba8(127,127,127,255)); ren.color(agg::rgba8(127,127,127,255));
agg::rasterizer_scanline_aa<> ras; agg::rasterizer_scanline_aa<> ras;
mapnik::proj_transform prj_trans(mapnik::projection("+init=epsg:4326"),mapnik::projection("+init=epsg:4326")); for (auto const& poly : geom)
geom.rewind(0); {
path_type path(tr,geom,prj_trans); mapnik::geometry::polygon_vertex_adapter<double> va(poly);
ras.add_path(path); path_type path(tr,va,prj_trans);
ras.add_path(path);
}
agg::scanline_u8 sl; agg::scanline_u8 sl;
agg::render_scanlines(ras, sl, ren); agg::render_scanlines(ras, sl, ren);
mapnik::save_to_file(im.data(),name); mapnik::save_to_file(im,name);
geom.rewind(0);
} }
class test1 : public benchmark::test_case class test1 : public benchmark::test_case
@ -64,7 +69,7 @@ class test1 : public benchmark::test_case
mapnik::box2d<double> extent_; mapnik::box2d<double> extent_;
std::string expected_; std::string expected_;
public: public:
using conv_clip = agg::conv_clip_polygon<mapnik::geometry_type>; using conv_clip = agg::conv_clip_polygon<mapnik::geometry::polygon_vertex_adapter<double>>;
test1(mapnik::parameters const& params, test1(mapnik::parameters const& params,
std::string const& wkt_in, std::string const& wkt_in,
mapnik::box2d<double> const& extent) mapnik::box2d<double> const& extent)
@ -74,153 +79,133 @@ public:
expected_("./benchmark/data/polygon_clipping_agg") {} expected_("./benchmark/data/polygon_clipping_agg") {}
bool validate() const bool validate() const
{ {
std::string expected_wkt("Polygon((181 286.666667,233 454,315 340,421 446,463 324,559 466,631 321.320755,631 234.386861,528 178,394 229,329 138,212 134,183 228,200 264,181 238.244444),(313 190,440 256,470 248,510 305,533 237,613 263,553 397,455 262,405 378,343 287,249 334,229 191,313 190,313 190))"); mapnik::geometry::geometry<double> geom;
boost::ptr_vector<mapnik::geometry_type> paths; if (!mapnik::from_wkt(wkt_in_, geom))
if (!mapnik::from_wkt(wkt_in_, paths))
{ {
throw std::runtime_error("Failed to parse WKT"); throw std::runtime_error("Failed to parse WKT");
} }
if (paths.size() != 1) if (mapnik::geometry::is_empty(geom))
{ {
std::clog << "paths.size() != 1\n"; std::clog << "empty geom!\n";
return false; return false;
} }
mapnik::geometry_type & geom = paths[0]; if (!geom.is<mapnik::geometry::polygon<double>>())
conv_clip clipped(geom); {
std::clog << "not a polygon!\n";
return false;
}
mapnik::geometry::polygon<double> const& poly = mapnik::util::get<mapnik::geometry::polygon<double>>(geom);
mapnik::geometry::polygon_vertex_adapter<double> va(poly);
conv_clip clipped(va);
clipped.clip_box( clipped.clip_box(
extent_.minx(), extent_.minx(),
extent_.miny(), extent_.miny(),
extent_.maxx(), extent_.maxx(),
extent_.maxy()); extent_.maxy());
clipped.rewind(0);
mapnik::geometry::polygon<double> poly2;
mapnik::geometry::linear_ring<double> ring;
// exterior ring
unsigned cmd; unsigned cmd;
double x,y; double x, y, x0, y0;
mapnik::geometry_type geom2(mapnik::geometry_type::types::Polygon); while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END)
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) { {
geom2.push_vertex(x,y,(mapnik::CommandType)cmd); if (cmd == mapnik::SEG_MOVETO)
{
x0 = x; y0 = y;
}
if (cmd == mapnik::SEG_CLOSE)
{
ring.add_coord(x0, y0);
break;
}
ring.add_coord(x,y);
} }
poly2.set_exterior_ring(std::move(ring));
// interior rings
ring.clear();
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END)
{
if (cmd == mapnik::SEG_MOVETO)
{
x0 = x; y0 = y;
}
else if (cmd == mapnik::SEG_CLOSE)
{
ring.add_coord(x0,y0);
poly2.add_hole(std::move(ring));
ring.clear();
continue;
}
ring.add_coord(x,y);
}
std::string expect = expected_+".png"; std::string expect = expected_+".png";
std::string actual = expected_+"_actual.png"; std::string actual = expected_+"_actual.png";
if (!mapnik::util::exists(expect)) mapnik::geometry::multi_polygon<double> mp;
mp.emplace_back(poly2);
auto env = mapnik::geometry::envelope(mp);
if (!mapnik::util::exists(expect) || (std::getenv("UPDATE") != nullptr))
{ {
std::clog << "generating expected image: " << expect << "\n"; std::clog << "generating expected image: " << expect << "\n";
render(geom2,geom.envelope(),expect); render(mp,env,expect);
} }
render(geom2,geom.envelope(),actual); render(mp,env,actual);
return benchmark::compare_images(actual,expect); return benchmark::compare_images(actual,expect);
} }
bool operator()() const bool operator()() const
{ {
boost::ptr_vector<mapnik::geometry_type> paths; mapnik::geometry::geometry<double> geom;
if (!mapnik::from_wkt(wkt_in_, paths)) if (!mapnik::from_wkt(wkt_in_, geom))
{ {
throw std::runtime_error("Failed to parse WKT"); throw std::runtime_error("Failed to parse WKT");
} }
if (mapnik::geometry::is_empty(geom))
{
std::clog << "empty geom!\n";
return false;
}
if (!geom.is<mapnik::geometry::polygon<double>>())
{
std::clog << "not a polygon!\n";
return false;
}
bool valid = true;
for (unsigned i=0;i<iterations_;++i) for (unsigned i=0;i<iterations_;++i)
{ {
for (mapnik::geometry_type & geom : paths) unsigned count = 0;
{ mapnik::geometry::polygon<double> const& poly = mapnik::util::get<mapnik::geometry::polygon<double>>(geom);
conv_clip clipped(geom); mapnik::geometry::polygon_vertex_adapter<double> va(poly);
clipped.clip_box( conv_clip clipped(va);
extent_.minx(), clipped.clip_box(
extent_.miny(), extent_.minx(),
extent_.maxx(), extent_.miny(),
extent_.maxy()); extent_.maxx(),
unsigned cmd; extent_.maxy());
double x,y; unsigned cmd;
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {} double x,y;
// NOTE: this rewind is critical otherwise
// agg_conv_adapter_vpgen will give garbage
// values for the first vertex
clipped.rewind(0);
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {
count++;
}
unsigned expected_count = 30;
if (count != expected_count) {
std::clog << "test1: clipping failed: processed " << count << " verticies but expected " << expected_count << "\n";
valid = false;
} }
} }
return true; return valid;
} }
}; };
class test2 : public benchmark::test_case
{
std::string wkt_in_;
mapnik::box2d<double> extent_;
std::string expected_;
public:
using poly_clipper = agg::conv_clipper<mapnik::geometry_type, agg::path_storage>;
test2(mapnik::parameters const& params,
std::string const& wkt_in,
mapnik::box2d<double> const& extent)
: test_case(params),
wkt_in_(wkt_in),
extent_(extent),
expected_("./benchmark/data/polygon_clipping_clipper") {}
bool validate() const
{
std::string expected_wkt("Polygon((212 134,329 138,394 229,528 178,631 234.4,631 321.3,559 466,463 324,421 446,315 340,233 454,181 286.7,181 238.2,200 264,183 228),(313 190,229 191,249 334,343 287,405 378,455 262,553 397,613 263,533 237,510 305,470 248,440 256))");
boost::ptr_vector<mapnik::geometry_type> paths;
if (!mapnik::from_wkt(wkt_in_, paths))
{
throw std::runtime_error("Failed to parse WKT");
}
agg::path_storage ps;
ps.move_to(extent_.minx(), extent_.miny());
ps.line_to(extent_.minx(), extent_.maxy());
ps.line_to(extent_.maxx(), extent_.maxy());
ps.line_to(extent_.maxx(), extent_.miny());
ps.close_polygon();
if (paths.size() != 1)
{
std::clog << "paths.size() != 1\n";
return false;
}
mapnik::geometry_type & geom = paths[0];
poly_clipper clipped(geom,ps,
agg::clipper_and,
agg::clipper_non_zero,
agg::clipper_non_zero,
1);
clipped.rewind(0);
unsigned cmd;
double x,y;
mapnik::geometry_type geom2(mapnik::geometry_type::types::Polygon);
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {
geom2.push_vertex(x,y,(mapnik::CommandType)cmd);
}
std::string expect = expected_+".png";
std::string actual = expected_+"_actual.png";
if (!mapnik::util::exists(expect))
{
std::clog << "generating expected image: " << expect << "\n";
render(geom2,geom.envelope(),expect);
}
render(geom2,geom.envelope(),actual);
return benchmark::compare_images(actual,expect);
}
bool operator()() const
{
boost::ptr_vector<mapnik::geometry_type> paths;
if (!mapnik::from_wkt(wkt_in_, paths))
{
throw std::runtime_error("Failed to parse WKT");
}
agg::path_storage ps;
ps.move_to(extent_.minx(), extent_.miny());
ps.line_to(extent_.minx(), extent_.maxy());
ps.line_to(extent_.maxx(), extent_.maxy());
ps.line_to(extent_.maxx(), extent_.miny());
ps.close_polygon();
for (unsigned i=0;i<iterations_;++i)
{
for (mapnik::geometry_type & geom : paths)
{
poly_clipper clipped(geom,ps,
agg::clipper_and,
agg::clipper_non_zero,
agg::clipper_non_zero,
1);
clipped.rewind(0);
unsigned cmd;
double x,y;
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {}
}
}
return true;
}
};
class test3 : public benchmark::test_case class test3 : public benchmark::test_case
{ {
@ -228,7 +213,6 @@ class test3 : public benchmark::test_case
mapnik::box2d<double> extent_; mapnik::box2d<double> extent_;
std::string expected_; std::string expected_;
public: public:
using poly_clipper = mapnik::polygon_clipper<mapnik::geometry_type>;
test3(mapnik::parameters const& params, test3(mapnik::parameters const& params,
std::string const& wkt_in, std::string const& wkt_in,
mapnik::box2d<double> const& extent) mapnik::box2d<double> const& extent)
@ -238,56 +222,278 @@ public:
expected_("./benchmark/data/polygon_clipping_boost") {} expected_("./benchmark/data/polygon_clipping_boost") {}
bool validate() const bool validate() const
{ {
std::string expected_wkt("Polygon((181 286.666667,233 454,315 340,421 446,463 324,559 466,631 321.320755,631 234.386861,528 178,394 229,329 138,212 134,183 228,200 264,181 238.244444,181 286.666667),(313 190,440 256,470 248,510 305,533 237,613 263,553 397,455 262,405 378,343 287,249 334,229 191,313 190))"); mapnik::geometry::geometry<double> geom;
boost::ptr_vector<mapnik::geometry_type> paths; if (!mapnik::from_wkt(wkt_in_, geom))
if (!mapnik::from_wkt(wkt_in_, paths))
{ {
throw std::runtime_error("Failed to parse WKT"); throw std::runtime_error("Failed to parse WKT");
} }
if (paths.size() != 1) if (mapnik::geometry::is_empty(geom))
{ {
std::clog << "paths.size() != 1\n"; std::clog << "empty geom!\n";
return false; return false;
} }
mapnik::geometry_type & geom = paths[0]; if (!geom.is<mapnik::geometry::polygon<double> >())
poly_clipper clipped(extent_, geom); {
unsigned cmd; std::clog << "not a polygon!\n";
double x,y; return false;
mapnik::geometry_type geom2(mapnik::geometry_type::types::Polygon);
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {
geom2.push_vertex(x,y,(mapnik::CommandType)cmd);
} }
mapnik::geometry::polygon<double> & poly = mapnik::util::get<mapnik::geometry::polygon<double> >(geom);
mapnik::geometry::correct(poly);
std::deque<mapnik::geometry::polygon<double> > result;
boost::geometry::intersection(extent_,poly,result);
std::string expect = expected_+".png"; std::string expect = expected_+".png";
std::string actual = expected_+"_actual.png"; std::string actual = expected_+"_actual.png";
if (!mapnik::util::exists(expect)) mapnik::geometry::multi_polygon<double> mp;
for (auto const& _geom: result)
{
//std::clog << boost::geometry::dsv(geom) << "\n";
mp.emplace_back(_geom);
}
mapnik::geometry::geometry<double> geom2(mp);
auto env = mapnik::geometry::envelope(geom2);
if (!mapnik::util::exists(expect) || (std::getenv("UPDATE") != nullptr))
{ {
std::clog << "generating expected image: " << expect << "\n"; std::clog << "generating expected image: " << expect << "\n";
render(geom2,geom.envelope(),expect); render(mp,env,expect);
} }
render(geom2,geom.envelope(),actual); render(mp,env,actual);
return benchmark::compare_images(actual,expect); return benchmark::compare_images(actual,expect);
} }
bool operator()() const bool operator()() const
{ {
boost::ptr_vector<mapnik::geometry_type> paths; mapnik::geometry::geometry<double> geom;
if (!mapnik::from_wkt(wkt_in_, paths)) if (!mapnik::from_wkt(wkt_in_, geom))
{ {
throw std::runtime_error("Failed to parse WKT"); throw std::runtime_error("Failed to parse WKT");
} }
if (mapnik::geometry::is_empty(geom))
{
std::clog << "empty geom!\n";
return false;
}
if (!geom.is<mapnik::geometry::polygon<double> >())
{
std::clog << "not a polygon!\n";
return false;
}
mapnik::geometry::polygon<double> & poly = mapnik::util::get<mapnik::geometry::polygon<double> >(geom);
mapnik::geometry::correct(poly);
bool valid = true;
for (unsigned i=0;i<iterations_;++i) for (unsigned i=0;i<iterations_;++i)
{ {
for ( mapnik::geometry_type & geom : paths) std::deque<mapnik::geometry::polygon<double> > result;
boost::geometry::intersection(extent_,poly,result);
unsigned count = 0;
for (auto const& _geom : result)
{ {
poly_clipper clipped(extent_, geom); mapnik::geometry::polygon_vertex_adapter<double> va(_geom);
unsigned cmd; unsigned cmd;
double x,y; double x,y;
while ((cmd = clipped.vertex(&x, &y)) != mapnik::SEG_END) {} while ((cmd = va.vertex(&x, &y)) != mapnik::SEG_END) {
++count;
}
unsigned expected_count = 29;
if (count != expected_count) {
std::clog << "test3: clipping failed: processed " << count << " verticies but expected " << expected_count << "\n";
valid = false;
}
} }
} }
return true; return valid;
} }
}; };
/*
Commented out section because clipper moved out of mapnik core.
inline void process_polynode_branch(ClipperLib::PolyNode* polynode,
mapnik::geometry::multi_polygon<double> & mp)
{
mapnik::geometry::polygon<double> polygon;
mapnik::geometry::linear_ring<double> outer;
for (auto const& pt : polynode->Contour)
{
outer.emplace_back(static_cast<double>(pt.x),static_cast<double>(pt.y));
}
if (outer.front() != outer.back())
{
outer.emplace_back(outer.front().x, outer.front().y);
}
polygon.set_exterior_ring(std::move(outer));
for (auto * ring : polynode->Childs)
{
mapnik::geometry::linear_ring<double> inner;
for (auto const& pt : ring->Contour)
{
inner.emplace_back(static_cast<double>(pt.x),static_cast<double>(pt.y));
}
if (inner.front() != inner.back())
{
inner.emplace_back(inner.front().x, inner.front().y);
}
polygon.add_hole(std::move(inner));
}
mp.emplace_back(std::move(polygon));
for (auto * ring : polynode->Childs)
{
for (auto * sub_ring : ring->Childs)
{
process_polynode_branch(sub_ring, mp);
}
}
}
class test4 : public benchmark::test_case
{
std::string wkt_in_;
mapnik::box2d<double> extent_;
std::string expected_;
public:
test4(mapnik::parameters const& params,
std::string const& wkt_in,
mapnik::box2d<double> const& extent)
: test_case(params),
wkt_in_(wkt_in),
extent_(extent),
expected_("./benchmark/data/polygon_clipping_clipper") {}
bool validate() const
{
mapnik::geometry::geometry<double> geom;
if (!mapnik::from_wkt(wkt_in_, geom))
{
throw std::runtime_error("Failed to parse WKT");
}
if (mapnik::geometry::is_empty(geom))
{
std::clog << "empty geom!\n";
return false;
}
if (!geom.is<mapnik::geometry::polygon<double> >())
{
std::clog << "not a polygon!\n";
return false;
}
mapnik::geometry::polygon<double> & poly = mapnik::util::get<mapnik::geometry::polygon<double> >(geom);
mapnik::geometry::correct(poly);
ClipperLib::Clipper clipper;
mapnik::geometry::line_string<std::int64_t> path;
for (auto const& pt : poly.exterior_ring)
{
double x = pt.x;
double y = pt.y;
path.emplace_back(static_cast<ClipperLib::cInt>(x),static_cast<ClipperLib::cInt>(y));
}
double area = ClipperLib::Area(path);
if (area > 0)
{
std::reverse(path.begin(), path.end());
}
if (!clipper.AddPath(path, ClipperLib::ptSubject, true))
{
std::clog << "ptSubject ext failed!\n";
}
for (auto const& ring : poly.interior_rings)
{
path.clear();
for (auto const& pt : ring)
{
double x = pt.x;
double y = pt.y;
path.emplace_back(static_cast<ClipperLib::cInt>(x),static_cast<ClipperLib::cInt>(y));
}
area = ClipperLib::Area(path);
if (area < 0)
{
std::reverse(path.begin(), path.end());
}
if (!clipper.AddPath(path, ClipperLib::ptSubject, true))
{
std::clog << "ptSubject ext failed!\n";
}
}
std::cerr << "path size=" << path.size() << std::endl;
mapnik::geometry::line_string<std::int64_t> clip_box;
clip_box.emplace_back(static_cast<ClipperLib::cInt>(extent_.minx()),static_cast<ClipperLib::cInt>(extent_.miny()));
clip_box.emplace_back(static_cast<ClipperLib::cInt>(extent_.maxx()),static_cast<ClipperLib::cInt>(extent_.miny()));
clip_box.emplace_back(static_cast<ClipperLib::cInt>(extent_.maxx()),static_cast<ClipperLib::cInt>(extent_.maxy()));
clip_box.emplace_back(static_cast<ClipperLib::cInt>(extent_.minx()),static_cast<ClipperLib::cInt>(extent_.maxy()));
clip_box.emplace_back(static_cast<ClipperLib::cInt>(extent_.minx()),static_cast<ClipperLib::cInt>(extent_.miny()));
if (!clipper.AddPath( clip_box, ClipperLib::ptClip, true ))
{
std::clog << "ptClip failed!\n";
}
ClipperLib::PolyTree polygons;
clipper.Execute(ClipperLib::ctIntersection, polygons);// ClipperLib::pftNonZero);
clipper.Clear();
mapnik::geometry::multi_polygon<double> mp;
for (auto * polynode : polygons.Childs)
{
process_polynode_branch(polynode, mp);
}
std::string expect = expected_+".png";
std::string actual = expected_+"_actual.png";
//mapnik::geometry::geometry<double> geom2(mp);
auto env = mapnik::geometry::envelope(mp);
if (!mapnik::util::exists(expect) || (std::getenv("UPDATE") != nullptr))
{
std::clog << "generating expected image: " << expect << "\n";
render(mp,env,expect);
}
render(mp,env,actual);
return benchmark::compare_images(actual,expect);
}
bool operator()() const
{
mapnik::geometry::geometry<double> geom;
if (!mapnik::from_wkt(wkt_in_, geom))
{
throw std::runtime_error("Failed to parse WKT");
}
if (mapnik::geometry::is_empty(geom))
{
std::clog << "empty geom!\n";
return false;
}
if (!geom.is<mapnik::geometry::polygon<double> >())
{
std::clog << "not a polygon!\n";
return false;
}
mapnik::geometry::polygon<double> & poly = mapnik::util::get<mapnik::geometry::polygon<double> >(geom);
mapnik::geometry::correct(poly);
bool valid = true;
for (unsigned i=0;i<iterations_;++i)
{
std::deque<mapnik::geometry::polygon<double> > result;
boost::geometry::intersection(extent_,poly,result);
unsigned count = 0;
for (auto const& geom : result)
{
mapnik::geometry::polygon_vertex_adapter<double> va(geom);
unsigned cmd;
double x,y;
while ((cmd = va.vertex(&x, &y)) != mapnik::SEG_END) {
++count;
}
unsigned expected_count = 29;
if (count != expected_count) {
std::clog << "test3: clipping failed: processed " << count << " verticies but expected " << expected_count << "\n";
valid = false;
}
}
}
return valid;
}
};
*/
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
mapnik::parameters params; mapnik::parameters params;
@ -310,14 +516,15 @@ int main(int argc, char** argv)
test1 test_runner(params,wkt_in,clipping_box); test1 test_runner(params,wkt_in,clipping_box);
run(test_runner,"clipping polygon with agg"); run(test_runner,"clipping polygon with agg");
} }
{
test2 test_runner(params,wkt_in,clipping_box);
run(test_runner,"clipping polygon with clipper");
}
{ {
test3 test_runner(params,wkt_in,clipping_box); test3 test_runner(params,wkt_in,clipping_box);
run(test_runner,"clipping polygon with boost"); run(test_runner,"clipping polygon with boost");
} }
/*
{
test4 test_runner(params,wkt_in,clipping_box);
run(test_runner,"clipping polygon with clipper_tree");
}
*/
return 0; return 0;
} }

View file

@ -1,7 +1,6 @@
#include "bench_framework.hpp" #include "bench_framework.hpp"
#include <mapnik/map.hpp> #include <mapnik/map.hpp>
#include <mapnik/load_map.hpp> #include <mapnik/load_map.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/agg_renderer.hpp> #include <mapnik/agg_renderer.hpp>
#include <mapnik/datasource_cache.hpp> #include <mapnik/datasource_cache.hpp>
@ -22,8 +21,8 @@ public:
mapnik::Map m(256,256); mapnik::Map m(256,256);
mapnik::load_map(m,xml_); mapnik::load_map(m,xml_);
m.zoom_to_box(extent_); m.zoom_to_box(extent_);
mapnik::image_32 im(m.width(),m.height()); mapnik::image_rgba8 im(m.width(),m.height());
mapnik::agg_renderer<mapnik::image_32> ren(m,im); mapnik::agg_renderer<mapnik::image_rgba8> ren(m,im);
ren.apply(); ren.apply();
//mapnik::save_to_file(im.data(),"test.png"); //mapnik::save_to_file(im.data(),"test.png");
return true; return true;
@ -35,8 +34,8 @@ public:
m.zoom_to_box(extent_); m.zoom_to_box(extent_);
for (unsigned i=0;i<iterations_;++i) for (unsigned i=0;i<iterations_;++i)
{ {
mapnik::image_32 im(m.width(),m.height()); mapnik::image_rgba8 im(m.width(),m.height());
mapnik::agg_renderer<mapnik::image_32> ren(m,im); mapnik::agg_renderer<mapnik::image_rgba8> ren(m,im);
ren.apply(); ren.apply();
} }
return true; return true;

View file

@ -38,15 +38,16 @@ public:
} }
bool operator()() const bool operator()() const
{ {
for (std::size_t i=0;i<iterations_;++i) { for (std::size_t i=0;i<iterations_;++i)
for (int i=-180;i<180;i=i+5) {
for (int j=-180;j<180;j=j+5)
{ {
for (int j=-85;j<85;j=j+5) for (int k=-85;k<85;k=k+5)
{ {
mapnik::projection src(src_,defer_proj4_init_); mapnik::projection src(src_,defer_proj4_init_);
mapnik::projection dest(dest_,defer_proj4_init_); mapnik::projection dest(dest_,defer_proj4_init_);
mapnik::proj_transform tr(src,dest); mapnik::proj_transform tr(src,dest);
mapnik::box2d<double> box(i,j,i,j); mapnik::box2d<double> box(j,k,j,k);
if (!tr.forward(box)) throw std::runtime_error("could not transform coords"); if (!tr.forward(box)) throw std::runtime_error("could not transform coords");
} }
} }

View file

@ -0,0 +1,54 @@
#include "bench_framework.hpp"
#include <mapnik/quad_tree.hpp>
#include <random>
using quad_tree_type = mapnik::quad_tree<std::size_t>;
class test : public benchmark::test_case
{
public:
test(mapnik::parameters const& params)
: test_case(params) {}
bool validate() const
{
return true;
}
bool operator()() const
{
std::random_device rd;
std::default_random_engine engine(rd());
std::uniform_int_distribution<int> uniform_dist(0, 2048);
quad_tree_type tree(mapnik::box2d<double>(0,0,2048,2048));
//populate
for (size_t i = 0; i < iterations_; ++i)
{
int cx = uniform_dist(engine);
int cy = uniform_dist(engine);
int sx = 0.2 * uniform_dist(engine);
int sy = 0.2 * uniform_dist(engine);
mapnik::box2d<double> box(cx - sx,cy - sy, cx + sx, cy + sy);
tree.insert(i, box);
}
// bounding box query
std::size_t count=0;
for (size_t i = 0; i < iterations_; ++i)
{
int cx = uniform_dist(engine);
int cy = uniform_dist(engine);
int sx = 0.4 * uniform_dist(engine);
int sy = 0.4 * uniform_dist(engine);
mapnik::box2d<double> box(cx - sx,cy - sy, cx + sx, cy + sy);
auto itr = tree.query_in_box(box);
auto end = tree.query_end();
for ( ;itr != end; ++itr)
{
++count;
}
}
return true;
}
};
BENCHMARK(test,"quad_tree creation")

View file

@ -2,7 +2,6 @@
#include <mapnik/map.hpp> #include <mapnik/map.hpp>
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/load_map.hpp> #include <mapnik/load_map.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/agg_renderer.hpp> #include <mapnik/agg_renderer.hpp>
#include <mapnik/datasource_cache.hpp> #include <mapnik/datasource_cache.hpp>
#include <mapnik/font_engine_freetype.hpp> #include <mapnik/font_engine_freetype.hpp>
@ -55,12 +54,12 @@ public:
} else { } else {
m.zoom_all(); m.zoom_all();
} }
mapnik::image_32 im(m.width(),m.height()); mapnik::image_rgba8 im(m.width(),m.height());
mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_); mapnik::agg_renderer<mapnik::image_rgba8> ren(m,im,scale_factor_);
ren.apply(); ren.apply();
if (!preview_.empty()) { if (!preview_.empty()) {
std::clog << "preview available at " << preview_ << "\n"; std::clog << "preview available at " << preview_ << "\n";
mapnik::save_to_file(im.data(),preview_); mapnik::save_to_file(im,preview_);
} }
return true; return true;
} }
@ -78,8 +77,8 @@ public:
} }
for (unsigned i=0;i<iterations_;++i) for (unsigned i=0;i<iterations_;++i)
{ {
mapnik::image_32 im(m.width(),m.height()); mapnik::image_rgba8 im(m.width(),m.height());
mapnik::agg_renderer<mapnik::image_32> ren(m,im,scale_factor_); mapnik::agg_renderer<mapnik::image_rgba8> ren(m,im,scale_factor_);
ren.apply(); ren.apply();
} }
return true; return true;

View file

@ -2,7 +2,6 @@
#include <mapnik/map.hpp> #include <mapnik/map.hpp>
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/load_map.hpp> #include <mapnik/load_map.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/agg_renderer.hpp> #include <mapnik/agg_renderer.hpp>
#include <mapnik/datasource_cache.hpp> #include <mapnik/datasource_cache.hpp>
#include <mapnik/font_engine_freetype.hpp> #include <mapnik/font_engine_freetype.hpp>
@ -50,7 +49,7 @@ class test : public benchmark::test_case
std::shared_ptr<mapnik::Map> m_; std::shared_ptr<mapnik::Map> m_;
double scale_factor_; double scale_factor_;
std::string preview_; std::string preview_;
mutable mapnik::image_32 im_; mutable mapnik::image_rgba8 im_;
public: public:
test(mapnik::parameters const& params) test(mapnik::parameters const& params)
: test_case(params), : test_case(params),
@ -94,14 +93,14 @@ public:
mapnik::projection map_proj(m_->srs(),true); mapnik::projection map_proj(m_->srs(),true);
double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic()); double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic());
scale_denom *= scale_factor_; scale_denom *= scale_factor_;
mapnik::agg_renderer<mapnik::image_32> ren(*m_,m_req,variables,im_,scale_factor_); mapnik::agg_renderer<mapnik::image_rgba8> ren(*m_,m_req,variables,im_,scale_factor_);
ren.start_map_processing(*m_); ren.start_map_processing(*m_);
std::vector<mapnik::layer> const& layers = m_->layers(); std::vector<mapnik::layer> const& layers = m_->layers();
process_layers(ren,m_req,map_proj,layers,scale_denom); process_layers(ren,m_req,map_proj,layers,scale_denom);
ren.end_map_processing(*m_); ren.end_map_processing(*m_);
if (!preview_.empty()) { if (!preview_.empty()) {
std::clog << "preview available at " << preview_ << "\n"; std::clog << "preview available at " << preview_ << "\n";
mapnik::save_to_file(im_.data(),preview_); mapnik::save_to_file(im_,preview_);
} }
return true; return true;
} }
@ -114,24 +113,24 @@ public:
for (unsigned i=0;i<iterations_;++i) for (unsigned i=0;i<iterations_;++i)
{ {
mapnik::request m_req(width_,height_,extent_); mapnik::request m_req(width_,height_,extent_);
mapnik::image_32 im(m_->width(),m_->height()); mapnik::image_rgba8 im(m_->width(),m_->height());
mapnik::attributes variables; mapnik::attributes variables;
m_req.set_buffer_size(m_->buffer_size()); m_req.set_buffer_size(m_->buffer_size());
mapnik::projection map_proj(m_->srs(),true); mapnik::projection map_proj(m_->srs(),true);
double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic()); double scale_denom = mapnik::scale_denominator(m_req.scale(),map_proj.is_geographic());
scale_denom *= scale_factor_; scale_denom *= scale_factor_;
mapnik::agg_renderer<mapnik::image_32> ren(*m_,m_req,variables,im,scale_factor_); mapnik::agg_renderer<mapnik::image_rgba8> ren(*m_,m_req,variables,im,scale_factor_);
ren.start_map_processing(*m_); ren.start_map_processing(*m_);
std::vector<mapnik::layer> const& layers = m_->layers(); std::vector<mapnik::layer> const& layers = m_->layers();
process_layers(ren,m_req,map_proj,layers,scale_denom); process_layers(ren,m_req,map_proj,layers,scale_denom);
ren.end_map_processing(*m_); ren.end_map_processing(*m_);
bool diff = false; bool diff = false;
mapnik::image_data_rgba8 const& dest = im.data(); mapnik::image_rgba8 const& dest = im;
mapnik::image_data_rgba8 const& src = im_.data(); mapnik::image_rgba8 const& src = im_;
for (unsigned int y = 0; y < height_; ++y) for (unsigned int y = 0; y < height_; ++y)
{ {
const unsigned int* row_from = src.getRow(y); const unsigned int* row_from = src.get_row(y);
const unsigned int* row_to = dest.getRow(y); const unsigned int* row_to = dest.get_row(y);
for (unsigned int x = 0; x < width_; ++x) for (unsigned int x = 0; x < width_; ++x)
{ {
if (row_from[x] != row_to[x]) diff = true; if (row_from[x] != row_to[x]) diff = true;
@ -160,7 +159,7 @@ int main(int argc, char** argv)
mapnik::datasource_cache::instance().register_datasources("./plugins/input/"); mapnik::datasource_cache::instance().register_datasources("./plugins/input/");
{ {
test test_runner(params); test test_runner(params);
run(test_runner,*name); run(test_runner,*name);
} }
} }
catch (std::exception const& ex) catch (std::exception const& ex)

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,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>
#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>(
( arg("r"), arg("g"), arg("b") ),
"Creates a new color from its RGB components.\n"
"All values between 0 and 255.\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")
)
.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("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,216 +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::Point)
.value("LineString",mapnik::datasource::LineString)
.value("Polygon",mapnik::datasource::Polygon)
.value("Collection",mapnik::datasource::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,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,255 +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::geometry_type const& (mapnik::feature_impl::*get_geometry_by_const_ref)(std::size_t) const = &mapnik::feature_impl::get_geometry;
mapnik::geometry_container const& (mapnik::feature_impl::*get_paths_by_const_ref)() const = &mapnik::feature_impl::paths;
void feature_add_geometries_from_wkb(mapnik::feature_impl & feature, std::string wkb)
{
bool result = geometry_utils::from_wkb(feature.paths(), wkb.c_str(), wkb.size());
if (!result) throw std::runtime_error("Failed to parse WKB");
}
void feature_add_geometries_from_wkt(mapnik::feature_impl & feature, std::string const& wkt)
{
bool result = mapnik::from_wkt(wkt, feature.paths());
if (!result) throw std::runtime_error("Failed to parse WKT");
}
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)
.def("add_geometries_from_wkb", &feature_add_geometries_from_wkb)
.def("add_geometries_from_wkt", &feature_add_geometries_from_wkt)
.def("add_geometry", &mapnik::feature_impl::add_geometry)
.def("num_geometries",&mapnik::feature_impl::num_geometries)
.def("get_geometry", make_function(get_geometry_by_const_ref,return_value_policy<reference_existing_object>()))
.def("geometries",make_function(get_paths_by_const_ref,return_value_policy<reference_existing_object>()))
.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,281 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* 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_container.hpp>
#include <mapnik/wkt/wkt_factory.hpp> // from_wkt
#include <mapnik/util/geometry_to_wkt.hpp>
#include <mapnik/json/geometry_parser.hpp> // from_geojson
#include <mapnik/util/geometry_to_geojson.hpp>
#include <mapnik/util/geometry_to_svg.hpp>
#include <mapnik/wkb.hpp>
#include <mapnik/util/geometry_to_wkb.hpp>
// stl
#include <stdexcept>
namespace {
mapnik::geometry_type const& getitem_impl(mapnik::geometry_container & p, int key)
{
if (key >=0 && key < static_cast<int>(p.size()))
return p[key];
PyErr_SetString(PyExc_IndexError, "Index is out of range");
throw boost::python::error_already_set();
}
void add_wkt_impl(mapnik::geometry_container& p, std::string const& wkt)
{
if (!mapnik::from_wkt(wkt , p))
throw std::runtime_error("Failed to parse WKT");
}
void add_wkb_impl(mapnik::geometry_container& p, std::string const& wkb)
{
if (!mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size()))
throw std::runtime_error("Failed to parse WKB");
}
void add_geojson_impl(mapnik::geometry_container& paths, std::string const& json)
{
if (!mapnik::json::from_geojson(json, paths))
throw std::runtime_error("Failed to parse geojson geometry");
}
std::shared_ptr<mapnik::geometry_container> from_wkt_impl(std::string const& wkt)
{
std::shared_ptr<mapnik::geometry_container> paths = std::make_shared<mapnik::geometry_container>();
if (!mapnik::from_wkt(wkt, *paths))
throw std::runtime_error("Failed to parse WKT");
return paths;
}
std::shared_ptr<mapnik::geometry_container> from_wkb_impl(std::string const& wkb)
{
std::shared_ptr<mapnik::geometry_container> paths = std::make_shared<mapnik::geometry_container>();
if (!mapnik::geometry_utils::from_wkb(*paths, wkb.c_str(), wkb.size()))
throw std::runtime_error("Failed to parse WKB");
return paths;
}
std::shared_ptr<mapnik::geometry_container> from_geojson_impl(std::string const& json)
{
std::shared_ptr<mapnik::geometry_container> paths = std::make_shared<mapnik::geometry_container>();
if (!mapnik::json::from_geojson(json, *paths))
throw std::runtime_error("Failed to parse geojson geometry");
return paths;
}
mapnik::box2d<double> envelope_impl(mapnik::geometry_container & p)
{
mapnik::box2d<double> b;
bool first = true;
for (mapnik::geometry_type const& geom : p)
{
if (first)
{
b = geom.envelope();
first=false;
}
else
{
b.expand_to_include(geom.envelope());
}
}
return b;
}
}
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(mapnik::geometry_type const& geom, mapnik::util::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;
}
}
PyObject* to_wkb2( mapnik::geometry_container const& p, mapnik::util::wkbByteOrder byte_order)
{
mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(p,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_wkt(mapnik::geometry_type const& geom)
{
std::string wkt;
if (!mapnik::util::to_wkt(wkt,geom))
{
throw std::runtime_error("Generate WKT failed");
}
return wkt;
}
std::string to_wkt2(mapnik::geometry_container const& geom)
{
std::string wkt;
if (!mapnik::util::to_wkt(wkt,geom))
{
throw std::runtime_error("Generate WKT failed");
}
return wkt;
}
std::string to_geojson(mapnik::geometry_type const& geom)
{
std::string wkt;
if (!mapnik::util::to_geojson(wkt,geom))
{
throw std::runtime_error("Generate JSON failed");
}
return wkt;
}
std::string to_geojson2(mapnik::geometry_container const& geom)
{
std::string wkt;
if (!mapnik::util::to_geojson(wkt,geom))
{
throw std::runtime_error("Generate JSON failed");
}
return wkt;
}
std::string to_svg(mapnik::geometry_type const& geom)
{
std::string svg;
if (!mapnik::util::to_svg(svg,geom))
{
throw std::runtime_error("Generate SVG failed");
}
return svg;
}
/*
// https://github.com/mapnik/mapnik/issues/1437
std::string to_svg2( mapnik::geometry_container const& geom)
{
std::string svg; // Use Python String directly ?
bool result = mapnik::util::to_svg(svg,geom);
if (!result)
{
throw std::runtime_error("Generate WKT failed");
}
return svg;
}*/
void export_geometry()
{
using namespace boost::python;
enum_<mapnik::geometry_type::types>("GeometryType")
.value("Point",mapnik::geometry_type::types::Point)
.value("LineString",mapnik::geometry_type::types::LineString)
.value("Polygon",mapnik::geometry_type::types::Polygon)
;
enum_<mapnik::util::wkbByteOrder>("wkbByteOrder")
.value("XDR",mapnik::util::wkbXDR)
.value("NDR",mapnik::util::wkbNDR)
;
using mapnik::geometry_type;
class_<mapnik::geometry_type, std::shared_ptr<mapnik::geometry_type>, boost::noncopyable>("Geometry2d",no_init)
.def("envelope",&mapnik::geometry_type::envelope)
// .def("__str__",&mapnik::geometry_type::to_string)
.def("type",&mapnik::geometry_type::type)
.def("to_wkb",&to_wkb)
.def("to_wkt",&to_wkt)
.def("to_geojson",&to_geojson)
.def("to_svg",&to_svg)
// TODO add other geometry_type methods
;
class_<mapnik::geometry_container, std::shared_ptr<mapnik::geometry_container>, boost::noncopyable>("Path")
.def("__getitem__", getitem_impl,return_value_policy<reference_existing_object>())
.def("__len__", &mapnik::geometry_container::size)
.def("envelope",envelope_impl)
.def("add_wkt",add_wkt_impl)
.def("add_wkb",add_wkb_impl)
.def("add_geojson",add_geojson_impl)
.def("to_wkt",&to_wkt2)
//.def("to_svg",&to_svg2)
.def("to_wkb",&to_wkb2)
.def("from_wkt",from_wkt_impl)
.def("from_wkb",from_wkb_impl)
.def("from_geojson",from_geojson_impl)
.def("to_geojson",&to_geojson2)
.staticmethod("from_wkt")
.staticmethod("from_wkb")
.staticmethod("from_geojson")
;
}

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,unsigned>(
( boost::python::arg("width"), boost::python::arg("height"),boost::python::arg("key")="__id__", boost::python::arg("resolution")=1 ),
"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,314 +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/graphics.hpp>
#include <mapnik/palette.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/image_reader.hpp>
#include <mapnik/image_compositing.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_32;
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_32 const& im)
{
int size = im.width() * im.height() * 4;
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
((const char*)im.raw_data(),size);
}
// encode (png,jpeg)
PyObject* tostring2(image_32 const & im, std::string const& format)
{
std::string s = mapnik::save_to_string(im.data(), format);
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
(s.data(),s.size());
}
PyObject* tostring3(image_32 const & im, std::string const& format, mapnik::rgba_palette const& pal)
{
std::string s = mapnik::save_to_string(im.data(), format, pal);
return
#if PY_VERSION_HEX >= 0x03000000
::PyBytes_FromStringAndSize
#else
::PyString_FromStringAndSize
#endif
(s.data(),s.size());
}
void save_to_file1(mapnik::image_32 const& im, std::string const& filename)
{
save_to_file(im.data(),filename);
}
void save_to_file2(mapnik::image_32 const& im, std::string const& filename, std::string const& type)
{
save_to_file(im.data(),filename,type);
}
void save_to_file3(mapnik::image_32 const& im, std::string const& filename, std::string const& type, mapnik::rgba_palette const& pal)
{
save_to_file(im.data(),filename,type,pal);
}
bool painted(mapnik::image_32 const& im)
{
return im.painted();
}
bool is_solid(mapnik::image_32 const& im)
{
if (im.width() > 0 && im.height() > 0)
{
mapnik::image_data_rgba8 const & data = im.data();
mapnik::image_data_rgba8::pixel_type const* first_row = data.getRow(0);
mapnik::image_data_rgba8::pixel_type const first_pixel = first_row[0];
for (unsigned y = 0; y < im.height(); ++y)
{
mapnik::image_data_rgba8::pixel_type const * row = data.getRow(y);
for (unsigned x = 0; x < im.width(); ++x)
{
if (first_pixel != row[x])
{
return false;
}
}
}
}
return true;
}
unsigned get_pixel(mapnik::image_32 const& im, int x, int y)
{
if (x < static_cast<int>(im.width()) && y < static_cast<int>(im.height()))
{
mapnik::image_data_rgba8 const & data = im.data();
return data(x,y);
}
PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions");
boost::python::throw_error_already_set();
return 0;
}
void set_pixel(mapnik::image_32 & im, unsigned x, unsigned y, mapnik::color const& c)
{
im.setPixel(x, y, c.rgba());
}
std::shared_ptr<image_32> 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())
{
std::shared_ptr<image_32> image_ptr = std::make_shared<image_32>(reader->width(),reader->height());
reader->read(0,0,image_ptr->data());
return image_ptr;
}
throw mapnik::image_reader_exception("Failed to load: " + filename);
}
throw mapnik::image_reader_exception("Unsupported image format:" + filename);
}
std::shared_ptr<image_32> fromstring(std::string const& str)
{
std::unique_ptr<image_reader> reader(get_image_reader(str.c_str(),str.size()));
if (reader.get())
{
std::shared_ptr<image_32> image_ptr = std::make_shared<image_32>(reader->width(),reader->height());
reader->read(0,0,image_ptr->data());
return image_ptr;
}
throw mapnik::image_reader_exception("Failed to load image from buffer" );
}
std::shared_ptr<image_32> 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())
{
std::shared_ptr<image_32> image_ptr = std::make_shared<image_32>(reader->width(),reader->height());
reader->read(0,0,image_ptr->data());
return image_ptr;
}
}
throw mapnik::image_reader_exception("Failed to load image from buffer" );
}
void blend (image_32 & im, unsigned x, unsigned y, image_32 const& im2, float opacity)
{
im.set_rectangle_alpha2(im2.data(),x,y,opacity);
}
void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity)
{
mapnik::composite(dst.data(),src.data(),mode,opacity,0,0,false);
}
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
std::shared_ptr<image_32> from_cairo(PycairoSurface* py_surface)
{
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
std::shared_ptr<image_32> image_ptr = std::make_shared<image_32>(cairo_image_surface_get_width(&*surface), cairo_image_surface_get_height(&*surface));
cairo_image_to_rgba8(image_ptr->data(), surface);
return image_ptr;
}
#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)
;
class_<image_32,std::shared_ptr<image_32> >("Image","This class represents a 32 bit RGBA image.",init<int,int>())
.def("width",&image_32::width)
.def("height",&image_32::height)
.def("view",&image_32::get_view)
.def("painted",&painted)
.def("is_solid",&is_solid)
.add_property("background",make_function
(&image_32::get_background,return_value_policy<copy_const_reference>()),
&image_32::set_background, "The background color of the image.")
.def("set_grayscale_to_alpha",&image_32::set_grayscale_to_alpha, "Set the grayscale values to the alpha channel of the Image")
.def("set_color_to_alpha",&image_32::set_color_to_alpha, "Set a given color to the alpha channel of the Image")
.def("set_alpha",&image_32::set_alpha, "Set the overall alpha channel of the Image")
.def("blend",&blend)
.def("composite",&composite,
( arg("self"),
arg("image"),
arg("mode")=mapnik::src_over,
arg("opacity")=1.0f
))
.def("premultiplied",&image_32::premultiplied)
.def("premultiply",&image_32::premultiply)
.def("demultiply",&image_32::demultiply)
.def("set_pixel",&set_pixel)
.def("get_pixel",&get_pixel)
.def("clear",&image_32::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,149 +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_data.hpp>
#include <mapnik/image_view.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/palette.hpp>
#include <mapnik/image_view.hpp>
#include <sstream>
using mapnik::image_data_rgba8;
using mapnik::image_view;
using mapnik::save_to_file;
// output 'raw' pixels
PyObject* view_tostring1(image_view<image_data_rgba8> const& view)
{
std::ostringstream ss(std::ios::out|std::ios::binary);
for (unsigned i=0;i<view.height();i++)
{
ss.write(reinterpret_cast<const char*>(view.getRow(i)),
view.width() * sizeof(image_view<image_data_rgba8>::pixel_type));
}
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<image_data_rgba8> 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<image_data_rgba8> 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<image_data_rgba8> const& view)
{
if (view.width() > 0 && view.height() > 0)
{
mapnik::image_view<image_data_rgba8>::pixel_type const* first_row = view.getRow(0);
mapnik::image_view<image_data_rgba8>::pixel_type const first_pixel = first_row[0];
for (unsigned y = 0; y < view.height(); ++y)
{
mapnik::image_view<image_data_rgba8>::pixel_type const * row = view.getRow(y);
for (unsigned x = 0; x < view.width(); ++x)
{
if (first_pixel != row[x])
{
return false;
}
}
}
}
return true;
}
void save_view1(image_view<image_data_rgba8> const& view,
std::string const& filename)
{
save_to_file(view,filename);
}
void save_view2(image_view<image_data_rgba8> const& view,
std::string const& filename,
std::string const& type)
{
save_to_file(view,filename,type);
}
void save_view3(image_view<image_data_rgba8> 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<image_data_rgba8> >("ImageView","A view into an image.",no_init)
.def("width",&image_view<image_data_rgba8>::width)
.def("height",&image_view<image_data_rgba8>::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);
}

View file

@ -1,961 +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/args.hpp> // for keywords, arg, etc
#include <boost/python/converter/from_python.hpp>
#include <boost/python/def.hpp> // for def
#include <boost/python/detail/defaults_gen.hpp>
#include <boost/python/detail/none.hpp> // for none
#include <boost/python/dict.hpp> // for dict
#include <boost/python/exception_translator.hpp>
#include <boost/python/list.hpp> // for list
#include <boost/python/module.hpp> // for BOOST_PYTHON_MODULE
#include <boost/python/object_core.hpp> // for get_managed_object
#include <boost/python/register_ptr_to_python.hpp>
#include <boost/python/to_python_converter.hpp>
#pragma GCC diagnostic pop
// stl
#include <stdexcept>
#include <fstream>
void export_color();
void export_coord();
void export_layer();
void export_parameters();
void export_envelope();
void export_query();
void export_geometry();
void export_palette();
void export_image();
void export_image_view();
void export_gamma_method();
void export_scaling_method();
#if defined(GRID_RENDERER)
void export_grid();
void export_grid_view();
#endif
void export_map();
void export_python();
void export_expression();
void export_rule();
void export_style();
void export_feature();
void export_featureset();
void export_fontset();
void export_datasource();
void export_datasource_cache();
void export_symbolizer();
void export_markers_symbolizer();
void export_point_symbolizer();
void export_line_symbolizer();
void export_line_pattern_symbolizer();
void export_polygon_symbolizer();
void export_building_symbolizer();
void export_polygon_pattern_symbolizer();
void export_raster_symbolizer();
void export_text_placement();
void export_shield_symbolizer();
void export_debug_symbolizer();
void export_group_symbolizer();
void export_font_engine();
void export_projection();
void export_proj_transform();
void export_view_transform();
void export_raster_colorizer();
void export_label_collision_detector();
void export_logger();
#include <mapnik/version.hpp>
#include <mapnik/map.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/rule.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/load_map.hpp>
#include <mapnik/value_error.hpp>
#include <mapnik/save_map.hpp>
#include <mapnik/scale_denominator.hpp>
#if defined(GRID_RENDERER)
#include "python_grid_utils.hpp"
#endif
#include "mapnik_value_converter.hpp"
#include "mapnik_enumeration_wrapper_converter.hpp"
#include "mapnik_threads.hpp"
#include "python_optional.hpp"
#include <mapnik/marker_cache.hpp>
#if defined(SHAPE_MEMORY_MAPPED_FILE)
#include <mapnik/mapped_memory_cache.hpp>
#endif
#if defined(SVG_RENDERER)
#include <mapnik/svg/output/svg_renderer.hpp>
#endif
namespace mapnik {
class font_set;
class layer;
class color;
class label_collision_detector4;
}
void clear_cache()
{
mapnik::marker_cache::instance().clear();
#if defined(SHAPE_MEMORY_MAPPED_FILE)
mapnik::mapped_memory_cache::instance().clear();
#endif
}
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#include <mapnik/cairo/cairo_renderer.hpp>
#include <boost/python/type_id.hpp>
#include <boost/python/converter/registry.hpp>
#include <pycairo.h>
#include <cairo.h>
static Pycairo_CAPI_t *Pycairo_CAPI;
static void *extract_surface(PyObject* op)
{
if (PyObject_TypeCheck(op, const_cast<PyTypeObject*>(Pycairo_CAPI->Surface_Type)))
{
return op;
}
else
{
return 0;
}
}
static void *extract_context(PyObject* op)
{
if (PyObject_TypeCheck(op, const_cast<PyTypeObject*>(Pycairo_CAPI->Context_Type)))
{
return op;
}
else
{
return 0;
}
}
void register_cairo()
{
#if PY_MAJOR_VERSION >= 3
Pycairo_CAPI = (Pycairo_CAPI_t*) PyCapsule_Import(const_cast<char *>("cairo.CAPI"), 0);
#else
Pycairo_CAPI = (Pycairo_CAPI_t*) PyCObject_Import(const_cast<char *>("cairo"), const_cast<char *>("CAPI"));
#endif
if (Pycairo_CAPI == nullptr) return;
boost::python::converter::registry::insert(&extract_surface, boost::python::type_id<PycairoSurface>());
boost::python::converter::registry::insert(&extract_context, boost::python::type_id<PycairoContext>());
}
#endif
using mapnik::python_thread;
using mapnik::python_unblock_auto_block;
#ifdef MAPNIK_DEBUG
bool python_thread::thread_support = true;
#endif
boost::thread_specific_ptr<PyThreadState> python_thread::state;
void render(mapnik::Map const& map,
mapnik::image_32& image,
double scale_factor = 1.0,
unsigned offset_x = 0u,
unsigned offset_y = 0u)
{
python_unblock_auto_block b;
mapnik::agg_renderer<mapnik::image_32> ren(map,image,scale_factor,offset_x, offset_y);
ren.apply();
}
void render_with_vars(mapnik::Map const& map,
mapnik::image_32& image,
boost::python::dict const& d,
double scale_factor = 1.0,
unsigned offset_x = 0u,
unsigned offset_y = 0u)
{
mapnik::attributes vars = mapnik::dict2attr(d);
mapnik::request req(map.width(),map.height(),map.get_current_extent());
req.set_buffer_size(map.buffer_size());
python_unblock_auto_block b;
mapnik::agg_renderer<mapnik::image_32> ren(map,req,vars,image,scale_factor,offset_x,offset_y);
ren.apply();
}
void render_with_detector(
mapnik::Map const& map,
mapnik::image_32 &image,
std::shared_ptr<mapnik::label_collision_detector4> detector,
double scale_factor = 1.0,
unsigned offset_x = 0u,
unsigned offset_y = 0u)
{
python_unblock_auto_block b;
mapnik::agg_renderer<mapnik::image_32> ren(map,image,detector,scale_factor,offset_x,offset_y);
ren.apply();
}
void render_layer2(mapnik::Map const& map,
mapnik::image_32& image,
unsigned layer_idx,
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());
}
python_unblock_auto_block b;
mapnik::layer const& layer = layers[layer_idx];
mapnik::agg_renderer<mapnik::image_32> ren(map,image,scale_factor,offset_x,offset_y);
std::set<std::string> names;
ren.apply(layer,names);
}
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
void render3(mapnik::Map const& map,
PycairoSurface* py_surface,
double scale_factor = 1.0,
unsigned offset_x = 0,
unsigned offset_y = 0)
{
python_unblock_auto_block b;
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,mapnik::create_context(surface),scale_factor,offset_x,offset_y);
ren.apply();
}
void render4(mapnik::Map const& map, PycairoSurface* py_surface)
{
python_unblock_auto_block b;
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,mapnik::create_context(surface));
ren.apply();
}
void render5(mapnik::Map const& map,
PycairoContext* py_context,
double scale_factor = 1.0,
unsigned offset_x = 0,
unsigned offset_y = 0)
{
python_unblock_auto_block b;
mapnik::cairo_ptr context(cairo_reference(py_context->ctx), mapnik::cairo_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context,scale_factor,offset_x, offset_y);
ren.apply();
}
void render6(mapnik::Map const& map, PycairoContext* py_context)
{
python_unblock_auto_block b;
mapnik::cairo_ptr context(cairo_reference(py_context->ctx), mapnik::cairo_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context);
ren.apply();
}
void render_with_detector2(
mapnik::Map const& map,
PycairoContext* py_context,
std::shared_ptr<mapnik::label_collision_detector4> detector)
{
python_unblock_auto_block b;
mapnik::cairo_ptr context(cairo_reference(py_context->ctx), mapnik::cairo_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context,detector);
ren.apply();
}
void render_with_detector3(
mapnik::Map const& map,
PycairoContext* py_context,
std::shared_ptr<mapnik::label_collision_detector4> detector,
double scale_factor = 1.0,
unsigned offset_x = 0u,
unsigned offset_y = 0u)
{
python_unblock_auto_block b;
mapnik::cairo_ptr context(cairo_reference(py_context->ctx), mapnik::cairo_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context,detector,scale_factor,offset_x,offset_y);
ren.apply();
}
void render_with_detector4(
mapnik::Map const& map,
PycairoSurface* py_surface,
std::shared_ptr<mapnik::label_collision_detector4> detector)
{
python_unblock_auto_block b;
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map, mapnik::create_context(surface), detector);
ren.apply();
}
void render_with_detector5(
mapnik::Map const& map,
PycairoSurface* py_surface,
std::shared_ptr<mapnik::label_collision_detector4> detector,
double scale_factor = 1.0,
unsigned offset_x = 0u,
unsigned offset_y = 0u)
{
python_unblock_auto_block b;
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map, mapnik::create_context(surface), detector, scale_factor, offset_x, offset_y);
ren.apply();
}
#endif
void render_tile_to_file(mapnik::Map const& map,
unsigned offset_x, unsigned offset_y,
unsigned width, unsigned height,
std::string const& file,
std::string const& format)
{
mapnik::image_32 image(width,height);
render(map,image,1.0,offset_x, offset_y);
mapnik::save_to_file(image.data(),file,format);
}
void render_to_file1(mapnik::Map const& map,
std::string const& filename,
std::string const& format)
{
if (format == "svg-ng")
{
#if defined(SVG_RENDERER)
std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary);
if (!file)
{
throw mapnik::ImageWriterException("could not open file for writing: " + filename);
}
using iter_type = std::ostream_iterator<char>;
iter_type output_stream_iterator(file);
mapnik::svg_renderer<iter_type> ren(map,output_stream_iterator);
ren.apply();
#else
throw mapnik::ImageWriterException("SVG backend not available, cannot write to format: " + format);
#endif
}
else if (format == "pdf" || format == "svg" || format =="ps" || format == "ARGB32" || format == "RGB24")
{
#if defined(HAVE_CAIRO)
mapnik::save_to_cairo_file(map,filename,format,1.0);
#else
throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format);
#endif
}
else
{
mapnik::image_32 image(map.width(),map.height());
render(map,image,1.0,0,0);
mapnik::save_to_file(image.data(),filename,format);
}
}
void render_to_file2(mapnik::Map const& map,std::string const& filename)
{
std::string format = mapnik::guess_type(filename);
if (format == "pdf" || format == "svg" || format =="ps")
{
#if defined(HAVE_CAIRO)
mapnik::save_to_cairo_file(map,filename,format,1.0);
#else
throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format);
#endif
}
else
{
mapnik::image_32 image(map.width(),map.height());
render(map,image,1.0,0,0);
mapnik::save_to_file(image.data(),filename);
}
}
void render_to_file3(mapnik::Map const& map,
std::string const& filename,
std::string const& format,
double scale_factor = 1.0
)
{
if (format == "svg-ng")
{
#if defined(SVG_RENDERER)
std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary);
if (!file)
{
throw mapnik::ImageWriterException("could not open file for writing: " + filename);
}
using iter_type = std::ostream_iterator<char>;
iter_type output_stream_iterator(file);
mapnik::svg_renderer<iter_type> ren(map,output_stream_iterator,scale_factor);
ren.apply();
#else
throw mapnik::ImageWriterException("SVG backend not available, cannot write to format: " + format);
#endif
}
else if (format == "pdf" || format == "svg" || format =="ps" || format == "ARGB32" || format == "RGB24")
{
#if defined(HAVE_CAIRO)
mapnik::save_to_cairo_file(map,filename,format,scale_factor);
#else
throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format);
#endif
}
else
{
mapnik::image_32 image(map.width(),map.height());
render(map,image,scale_factor,0,0);
mapnik::save_to_file(image.data(),filename,format);
}
}
double scale_denominator(mapnik::Map const& map, bool geographic)
{
return mapnik::scale_denominator(map.scale(), geographic);
}
// http://docs.python.org/c-api/exceptions.html#standard-exceptions
void value_error_translator(mapnik::value_error const & ex)
{
PyErr_SetString(PyExc_ValueError, ex.what());
}
void runtime_error_translator(std::runtime_error const & ex)
{
PyErr_SetString(PyExc_RuntimeError, ex.what());
}
void out_of_range_error_translator(std::out_of_range const & ex)
{
PyErr_SetString(PyExc_IndexError, ex.what());
}
void standard_error_translator(std::exception const & ex)
{
PyErr_SetString(PyExc_RuntimeError, ex.what());
}
unsigned mapnik_version()
{
return MAPNIK_VERSION;
}
std::string mapnik_version_string()
{
return MAPNIK_VERSION_STRING;
}
bool has_proj4()
{
#if defined(MAPNIK_USE_PROJ4)
return true;
#else
return false;
#endif
}
bool has_svg_renderer()
{
#if defined(SVG_RENDERER)
return true;
#else
return false;
#endif
}
bool has_grid_renderer()
{
#if defined(GRID_RENDERER)
return true;
#else
return false;
#endif
}
bool has_jpeg()
{
#if defined(HAVE_JPEG)
return true;
#else
return false;
#endif
}
bool has_png()
{
#if defined(HAVE_PNG)
return true;
#else
return false;
#endif
}
bool has_tiff()
{
#if defined(HAVE_TIFF)
return true;
#else
return false;
#endif
}
bool has_webp()
{
#if defined(HAVE_WEBP)
return true;
#else
return false;
#endif
}
// indicator for cairo rendering support inside libmapnik
bool has_cairo()
{
#if defined(HAVE_CAIRO)
return true;
#else
return false;
#endif
}
// indicator for pycairo support in the python bindings
bool has_pycairo()
{
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
#if PY_MAJOR_VERSION >= 3
Pycairo_CAPI = (Pycairo_CAPI_t*) PyCapsule_Import(const_cast<char *>("cairo.CAPI"), 0);
#else
Pycairo_CAPI = (Pycairo_CAPI_t*) PyCObject_Import(const_cast<char *>("cairo"), const_cast<char *>("CAPI"));
#endif
if (Pycairo_CAPI == nullptr){
/*
Case where pycairo support has been compiled into
mapnik but at runtime the cairo python module
is unable to be imported and therefore Pycairo surfaces
and contexts cannot be passed to mapnik.render()
*/
return false;
}
return true;
#else
return false;
#endif
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedef"
BOOST_PYTHON_FUNCTION_OVERLOADS(load_map_overloads, load_map, 2, 4)
BOOST_PYTHON_FUNCTION_OVERLOADS(load_map_string_overloads, load_map_string, 2, 4)
BOOST_PYTHON_FUNCTION_OVERLOADS(save_map_overloads, save_map, 2, 3)
BOOST_PYTHON_FUNCTION_OVERLOADS(save_map_to_string_overloads, save_map_to_string, 1, 2)
BOOST_PYTHON_FUNCTION_OVERLOADS(render_overloads, render, 2, 5)
BOOST_PYTHON_FUNCTION_OVERLOADS(render_with_detector_overloads, render_with_detector, 3, 6)
#pragma GCC diagnostic pop
BOOST_PYTHON_MODULE(_mapnik)
{
using namespace boost::python;
using mapnik::load_map;
using mapnik::load_map_string;
using mapnik::save_map;
using mapnik::save_map_to_string;
register_exception_translator<std::exception>(&standard_error_translator);
register_exception_translator<std::out_of_range>(&out_of_range_error_translator);
register_exception_translator<mapnik::value_error>(&value_error_translator);
register_exception_translator<std::runtime_error>(&runtime_error_translator);
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
register_cairo();
#endif
export_query();
export_geometry();
export_feature();
export_featureset();
export_fontset();
export_datasource();
export_parameters();
export_color();
export_envelope();
export_palette();
export_image();
export_image_view();
export_gamma_method();
export_scaling_method();
#if defined(GRID_RENDERER)
export_grid();
export_grid_view();
#endif
export_expression();
export_rule();
export_style();
export_layer();
export_datasource_cache();
export_symbolizer();
export_markers_symbolizer();
export_point_symbolizer();
export_line_symbolizer();
export_line_pattern_symbolizer();
export_polygon_symbolizer();
export_building_symbolizer();
export_polygon_pattern_symbolizer();
export_raster_symbolizer();
export_text_placement();
export_shield_symbolizer();
export_debug_symbolizer();
export_group_symbolizer();
export_font_engine();
export_projection();
export_proj_transform();
export_view_transform();
export_coord();
export_map();
export_raster_colorizer();
export_label_collision_detector();
export_logger();
def("clear_cache", &clear_cache,
"\n"
"Clear all global caches of markers and mapped memory regions.\n"
"\n"
"Usage:\n"
">>> from mapnik import clear_cache\n"
">>> clear_cache()\n"
);
def("render_to_file",&render_to_file1,
"\n"
"Render Map to file using explicit image type.\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, render_to_file, load_map\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> render_to_file(m,'image32bit.png','png')\n"
"\n"
"8 bit (paletted) PNG can be requested with 'png256':\n"
">>> render_to_file(m,'8bit_image.png','png256')\n"
"\n"
"JPEG quality can be controlled by adding a suffix to\n"
"'jpeg' between 0 and 100 (default is 85):\n"
">>> render_to_file(m,'top_quality.jpeg','jpeg100')\n"
">>> render_to_file(m,'medium_quality.jpeg','jpeg50')\n"
);
def("render_to_file",&render_to_file2,
"\n"
"Render Map to file (type taken from file extension)\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, render_to_file, load_map\n"
">>> m = Map(256,256)\n"
">>> render_to_file(m,'image.jpeg')\n"
"\n"
);
def("render_to_file",&render_to_file3,
"\n"
"Render Map to file using explicit image type and scale factor.\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, render_to_file, load_map\n"
">>> m = Map(256,256)\n"
">>> scale_factor = 4\n"
">>> render_to_file(m,'image.jpeg',scale_factor)\n"
"\n"
);
def("render_tile_to_file",&render_tile_to_file,
"\n"
"TODO\n"
"\n"
);
def("render_with_vars",&render_with_vars,
(arg("map"),
arg("image"),
arg("vars"),
arg("scale_factor")=1.0,
arg("offset_x")=0,
arg("offset_y")=0
)
);
def("render", &render, render_overloads(
"\n"
"Render Map to an AGG image_32 using offsets\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, Image, render, load_map\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> im = Image(m.width,m.height)\n"
">>> scale_factor=2.0\n"
">>> offset = [100,50]\n"
">>> render(m,im)\n"
">>> render(m,im,scale_factor)\n"
">>> render(m,im,scale_factor,offset[0],offset[1])\n"
"\n"
));
def("render_with_detector", &render_with_detector, render_with_detector_overloads(
"\n"
"Render Map to an AGG image_32 using a pre-constructed detector.\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, Image, LabelCollisionDetector, render_with_detector, load_map\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> im = Image(m.width,m.height)\n"
">>> detector = LabelCollisionDetector(m)\n"
">>> render_with_detector(m, im, detector)\n"
));
def("render_layer", &render_layer2,
(arg("map"),
arg("image"),
arg("layer"),
arg("scale_factor")=1.0,
arg("offset_x")=0,
arg("offset_y")=0
)
);
#if defined(GRID_RENDERER)
def("render_layer", &mapnik::render_layer_for_grid,
(arg("map"),
arg("grid"),
arg("layer"),
arg("fields")=boost::python::list(),
arg("scale_factor")=1.0,
arg("offset_x")=0,
arg("offset_y")=0
)
);
#endif
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
def("render",&render3,
"\n"
"Render Map to Cairo Surface using offsets\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, render, load_map\n"
">>> from cairo import SVGSurface\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
">>> render(m,surface,1,1)\n"
"\n"
);
def("render",&render4,
"\n"
"Render Map to Cairo Surface\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, render, load_map\n"
">>> from cairo import SVGSurface\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
">>> render(m,surface)\n"
"\n"
);
def("render",&render5,
"\n"
"Render Map to Cairo Context using offsets\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, render, load_map\n"
">>> from cairo import SVGSurface, Context\n"
">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
">>> ctx = Context(surface)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> render(m,context,1,1)\n"
"\n"
);
def("render",&render6,
"\n"
"Render Map to Cairo Context\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, render, load_map\n"
">>> from cairo import SVGSurface, Context\n"
">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
">>> ctx = Context(surface)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> render(m,context)\n"
"\n"
);
def("render_with_detector", &render_with_detector2,
"\n"
"Render Map to Cairo Context using a pre-constructed detector.\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, LabelCollisionDetector, render_with_detector, load_map\n"
">>> from cairo import SVGSurface, Context\n"
">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
">>> ctx = Context(surface)\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> detector = LabelCollisionDetector(m)\n"
">>> render_with_detector(m, ctx, detector)\n"
);
def("render_with_detector", &render_with_detector3,
"\n"
"Render Map to Cairo Context using a pre-constructed detector, scale and offsets.\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, LabelCollisionDetector, render_with_detector, load_map\n"
">>> from cairo import SVGSurface, Context\n"
">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
">>> ctx = Context(surface)\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> detector = LabelCollisionDetector(m)\n"
">>> render_with_detector(m, ctx, detector, 1, 1, 1)\n"
);
def("render_with_detector", &render_with_detector4,
"\n"
"Render Map to Cairo Surface using a pre-constructed detector.\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, LabelCollisionDetector, render_with_detector, load_map\n"
">>> from cairo import SVGSurface, Context\n"
">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> detector = LabelCollisionDetector(m)\n"
">>> render_with_detector(m, surface, detector)\n"
);
def("render_with_detector", &render_with_detector5,
"\n"
"Render Map to Cairo Surface using a pre-constructed detector, scale and offsets.\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, LabelCollisionDetector, render_with_detector, load_map\n"
">>> from cairo import SVGSurface, Context\n"
">>> surface = SVGSurface('image.svg', m.width, m.height)\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> detector = LabelCollisionDetector(m)\n"
">>> render_with_detector(m, surface, detector, 1, 1, 1)\n"
);
#endif
def("scale_denominator", &scale_denominator,
(arg("map"),arg("is_geographic")),
"\n"
"Return the Map Scale Denominator.\n"
"Also available as Map.scale_denominator()\n"
"\n"
"Usage:\n"
"\n"
">>> from mapnik import Map, Projection, scale_denominator, load_map\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile.xml')\n"
">>> scale_denominator(m,Projection(m.srs).geographic)\n"
"\n"
);
def("load_map", &load_map, load_map_overloads());
def("load_map_from_string", &load_map_string, load_map_string_overloads());
def("save_map", &save_map, save_map_overloads());
/*
"\n"
"Save Map object to XML file\n"
"\n"
"Usage:\n"
">>> from mapnik import Map, load_map, save_map\n"
">>> m = Map(256,256)\n"
">>> load_map(m,'mapfile_wgs84.xml')\n"
">>> m.srs\n"
"'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n"
">>> m.srs = '+init=espg:3395'\n"
">>> save_map(m,'mapfile_mercator.xml')\n"
"\n"
);
*/
def("save_map_to_string", &save_map_to_string, save_map_to_string_overloads());
def("mapnik_version", &mapnik_version,"Get the Mapnik version number");
def("mapnik_version_string", &mapnik_version_string,"Get the Mapnik version string");
def("has_proj4", &has_proj4, "Get proj4 status");
def("has_jpeg", &has_jpeg, "Get jpeg read/write support status");
def("has_png", &has_png, "Get png read/write support status");
def("has_tiff", &has_tiff, "Get tiff read/write support status");
def("has_webp", &has_webp, "Get webp read/write support status");
def("has_svg_renderer", &has_svg_renderer, "Get svg_renderer status");
def("has_grid_renderer", &has_grid_renderer, "Get grid_renderer status");
def("has_cairo", &has_cairo, "Get cairo library status");
def("has_pycairo", &has_pycairo, "Get pycairo module status");
python_optional<mapnik::font_set>();
python_optional<mapnik::color>();
python_optional<mapnik::box2d<double> >();
python_optional<mapnik::composite_mode_e>();
python_optional<mapnik::datasource::geometry_t>();
python_optional<std::string>();
python_optional<unsigned>();
python_optional<double>();
python_optional<float>();
python_optional<bool>();
python_optional<int>();
python_optional<mapnik::text_transform_e>();
register_ptr_to_python<mapnik::expression_ptr>();
register_ptr_to_python<mapnik::path_expression_ptr>();
to_python_converter<mapnik::value_holder,mapnik_param_to_python>();
to_python_converter<mapnik::value,mapnik_value_to_python>();
to_python_converter<mapnik::enumeration_wrapper,mapnik_enumeration_wrapper_to_python>();
}

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,230 +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,423 +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/graphics.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.property_names();
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_property_name(name());
}
else
{
std::stringstream s;
s << "list of field names must be strings";
throw mapnik::value_error(s.str());
}
}
// copy property names
std::set<std::string> attributes = grid.property_names();
// 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

@ -6,9 +6,7 @@
todo todo
- gdal shared lib / avoid dlclose atexit crash - docs for base setup: sudo apt-get -y install zlib1g-dev make git
- clang debs to s3
- docs for base setup: sudo apt-get -y install zlib1g-dev python-dev make git python-dev
- shrink icu data - shrink icu data
' '
@ -20,71 +18,85 @@ function setup_mason() {
(cd ./.mason && git pull) (cd ./.mason && git pull)
fi fi
export MASON_DIR=$(pwd)/.mason export MASON_DIR=$(pwd)/.mason
if [[ $(uname -s) == 'Linux' ]]; then source ./.mason/scripts/setup_cpp11_toolchain.sh; fi
export PATH=$(pwd)/.mason:$PATH export PATH=$(pwd)/.mason:$PATH
export CXX=${CXX:-clang++} export CXX=${CXX:-clang++}
export CC=${CC:-clang} export CC=${CC:-clang}
} }
if [[ $(uname -s) == 'Darwin' ]]; then
FIND_PATTERN="\/Users\/travis\/build\/mapbox\/mason"
else
FIND_PATTERN="\/home\/travis\/build\/mapbox\/mason"
fi
REPLACE="$(pwd)"
REPLACE=${REPLACE////\\/}
function install() { function install() {
MASON_PLATFORM_ID=$(mason env MASON_PLATFORM_ID) MASON_PLATFORM_ID=$(mason env MASON_PLATFORM_ID)
if [[ ! -d ./mason_packages/${MASON_PLATFORM_ID}/${1}/ ]]; then if [[ ! -d ./mason_packages/${MASON_PLATFORM_ID}/${1}/${2} ]]; then
mason install $1 $2 mason install $1 $2
mason link $1 $2 mason link $1 $2
if [[ $3 ]]; then
LA_FILE=$(${MASON_DIR:-~/.mason}/mason prefix $1 $2)/lib/$3.la
if [[ -f ${LA_FILE} ]]; then
perl -i -p -e "s/${FIND_PATTERN}/${REPLACE}/g;" ${LA_FILE}
else
echo "$LA_FILE not found"
fi
fi
fi fi
} }
function install_mason_deps() { function install_mason_deps() {
install freetype 2.5.4 install gdal 1.11.2 libgdal &
install harfbuzz 2cd5323 install boost 1.57.0 &
install jpeg_turbo 1.4.0 install boost_libsystem 1.57.0 &
install libxml2 2.9.2 install boost_libthread 1.57.0 &
install libpng 1.6.16 install boost_libfilesystem 1.57.0 &
install webp 0.4.2 install boost_libprogram_options 1.57.0 &
install icu 54.1 install boost_libregex 1.57.0 &
install proj 4.8.0 install boost_libpython 1.57.0 &
install libtiff 4.0.4beta install freetype 2.5.5 libfreetype &
install boost 1.57.0 install harfbuzz 0.9.40 libharfbuzz &
install boost_libsystem 1.57.0 install jpeg_turbo 1.4.0 libjpeg &
install boost_libthread 1.57.0 install libxml2 2.9.2 libxml2 &
install boost_libfilesystem 1.57.0 install libpng 1.6.16 libpng &
install boost_libprogram_options 1.57.0 install webp 0.4.2 libwebp &
install boost_libregex 1.57.0 install icu 54.1 &
install boost_libpython 1.57.0 install proj 4.8.0 libproj &
install libpq 9.4.0 install libtiff 4.0.4beta libtiff &
install sqlite 3.8.8.1 install libpq 9.4.0 &
install gdal 1.11.1 install sqlite 3.8.8.1 libsqlite3 &
install expat 2.1.0 install expat 2.1.0 libexpat &
install pixman 0.32.6 install pixman 0.32.6 libpixman-1 &
install cairo 1.12.18 install cairo 1.12.18 libcairo &
wait
} }
function setup_nose() { MASON_LINKED_ABS=$(pwd)/mason_packages/.link
if [[ ! -d $(pwd)/nose-1.3.4 ]]; then MASON_LINKED_REL=./mason_packages/.link
wget -q https://pypi.python.org/packages/source/n/nose/nose-1.3.4.tar.gz export C_INCLUDE_PATH="${MASON_LINKED_ABS}/include"
tar -xzf nose-1.3.4.tar.gz export CPLUS_INCLUDE_PATH="${MASON_LINKED_ABS}/include"
fi export LIBRARY_PATH="${MASON_LINKED_ABS}/lib"
export PYTHONPATH=$(pwd)/nose-1.3.4:${PYTHONPATH}
}
function make_config() { function make_config() {
local MASON_LINKED_REL=./mason_packages/.link if [[ $(uname -s) == 'Darwin' ]]; then
export C_INCLUDE_PATH="${MASON_LINKED_REL}/include" local PATH_REPLACE="/Users/travis/build/mapbox/mason/mason_packages:./mason_packages"
export CPLUS_INCLUDE_PATH="${MASON_LINKED_REL}/include" else
export LIBRARY_PATH="${MASON_LINKED_REL}/lib" local PATH_REPLACE="/home/travis/build/mapbox/mason/mason_packages:./mason_packages"
export PATH="${MASON_LINKED_REL}/bin":${PATH} fi
echo " echo "
CXX = '$CXX' CXX = '$CXX'
CC = '$CC' CC = '$CC'
CUSTOM_CXXFLAGS = '-fvisibility=hidden -fvisibility-inlines-hidden -DU_CHARSET_IS_UTF8=1' CUSTOM_CXXFLAGS = '-fvisibility=hidden -fvisibility-inlines-hidden -DU_CHARSET_IS_UTF8=1'
CUSTOM_LDFLAGS = '-L${MASON_LINKED_REL}/lib'
RUNTIME_LINK = 'static' RUNTIME_LINK = 'static'
INPUT_PLUGINS = 'all' INPUT_PLUGINS = 'all'
PATH = '${MASON_LINKED_REL}/bin' PATH = '${MASON_LINKED_REL}/bin'
PKG_CONFIG_PATH = '${MASON_LINKED_REL}/lib/pkgconfig' PKG_CONFIG_PATH = '${MASON_LINKED_REL}/lib/pkgconfig'
PATH_REMOVE = '/usr:/usr/local' PATH_REMOVE = '/usr:/usr/local'
PATH_REPLACE = '/Users/travis/build/mapbox/mason/mason_packages:./mason_packages' PATH_REPLACE = '${PATH_REPLACE}'
BOOST_INCLUDES = '${MASON_LINKED_REL}/include' BOOST_INCLUDES = '${MASON_LINKED_REL}/include'
BOOST_LIBS = '${MASON_LINKED_REL}/lib' BOOST_LIBS = '${MASON_LINKED_REL}/lib'
ICU_INCLUDES = '${MASON_LINKED_REL}/include' ICU_INCLUDES = '${MASON_LINKED_REL}/include'
@ -101,6 +113,8 @@ WEBP_INCLUDES = '${MASON_LINKED_REL}/include'
WEBP_LIBS = '${MASON_LINKED_REL}/lib' WEBP_LIBS = '${MASON_LINKED_REL}/lib'
PROJ_INCLUDES = '${MASON_LINKED_REL}/include' PROJ_INCLUDES = '${MASON_LINKED_REL}/include'
PROJ_LIBS = '${MASON_LINKED_REL}/lib' PROJ_LIBS = '${MASON_LINKED_REL}/lib'
PG_INCLUDES = '${MASON_LINKED_REL}/include'
PG_LIBS = '${MASON_LINKED_REL}/lib'
FREETYPE_INCLUDES = '${MASON_LINKED_REL}/include/freetype2' FREETYPE_INCLUDES = '${MASON_LINKED_REL}/include/freetype2'
FREETYPE_LIBS = '${MASON_LINKED_REL}/lib' FREETYPE_LIBS = '${MASON_LINKED_REL}/lib'
XML2_INCLUDES = '${MASON_LINKED_REL}/include/libxml2' XML2_INCLUDES = '${MASON_LINKED_REL}/include/libxml2'
@ -110,28 +124,26 @@ 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
" > ./config.py " > ./config.py
} }
# NOTE: the `mapnik-settings.env` is used by test/run (which is run by `make test`)
function setup_runtime_settings() { function setup_runtime_settings() {
local MASON_LINKED_ABS=$(pwd)/mason_packages/.link echo "export PROJ_LIB=${MASON_LINKED_ABS}/share/proj" > mapnik-settings.env
export PROJ_LIB=${MASON_LINKED_ABS}/share/proj/ echo "export ICU_DATA=${MASON_LINKED_ABS}/share/icu/54.1" >> mapnik-settings.env
export ICU_DATA=${MASON_LINKED_ABS}/share/icu/54.1/ echo "export GDAL_DATA=${MASON_LINKED_ABS}/share/gdal" >> mapnik-settings.env
export GDAL_DATA=${MASON_LINKED_ABS}/share/gdal source mapnik-settings.env
} }
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:"

2
configure vendored
View file

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/sh
PYTHON=${PYTHON:-python} PYTHON=${PYTHON:-python}

View file

@ -1,7 +1,7 @@
# #
# This file is part of Mapnik (c++ mapping toolkit) # This file is part of Mapnik (c++ mapping toolkit)
# #
# Copyright (C) 2009 Artem Pavlenko, Dane Springmeyer # Copyright (C) 2015 Artem Pavlenko, Dane Springmeyer
# #
# Mapnik is free software; you can redistribute it and/or # Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,7 +17,7 @@
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# #
# #
import os import os
from copy import copy from copy import copy

View file

@ -2,7 +2,7 @@
* *
* This file is part of Mapnik (c++ mapping toolkit) * This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -24,7 +24,6 @@
#include <mapnik/layer.hpp> #include <mapnik/layer.hpp>
#include <mapnik/rule.hpp> #include <mapnik/rule.hpp>
#include <mapnik/feature_type_style.hpp> #include <mapnik/feature_type_style.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/symbolizer.hpp> #include <mapnik/symbolizer.hpp>
#include <mapnik/text/placements/dummy.hpp> #include <mapnik/text/placements/dummy.hpp>
#include <mapnik/text/text_properties.hpp> #include <mapnik/text/text_properties.hpp>
@ -37,6 +36,7 @@
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
#include <mapnik/unicode.hpp> #include <mapnik/unicode.hpp>
#include <mapnik/save_map.hpp> #include <mapnik/save_map.hpp>
#include <mapnik/cairo_io.hpp>
#if defined(HAVE_CAIRO) #if defined(HAVE_CAIRO)
#include <mapnik/cairo/cairo_renderer.hpp> #include <mapnik/cairo/cairo_renderer.hpp>
@ -305,26 +305,26 @@ int main ( int, char** )
m.zoom_to_box(box2d<double>(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855)); m.zoom_to_box(box2d<double>(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855));
image_32 buf(m.width(),m.height()); image_rgba8 buf(m.width(),m.height());
agg_renderer<image_32> ren(m,buf); agg_renderer<image_rgba8> ren(m,buf);
ren.apply(); ren.apply();
std::string msg("These maps have been rendered using AGG in the current directory:\n"); std::string msg("These maps have been rendered using AGG in the current directory:\n");
#ifdef HAVE_JPEG #ifdef HAVE_JPEG
save_to_file(buf.data(),"demo.jpg","jpeg"); save_to_file(buf,"demo.jpg","jpeg");
msg += "- demo.jpg\n"; msg += "- demo.jpg\n";
#endif #endif
#ifdef HAVE_PNG #ifdef HAVE_PNG
save_to_file(buf.data(),"demo.png","png"); save_to_file(buf,"demo.png","png");
save_to_file(buf.data(),"demo256.png","png8"); save_to_file(buf,"demo256.png","png8");
msg += "- demo.png\n"; msg += "- demo.png\n";
msg += "- demo256.png\n"; msg += "- demo256.png\n";
#endif #endif
#ifdef HAVE_TIFF #ifdef HAVE_TIFF
save_to_file(buf.data(),"demo.tif","tiff"); save_to_file(buf,"demo.tif","tiff");
msg += "- demo.tif\n"; msg += "- demo.tif\n";
#endif #endif
#ifdef HAVE_WEBP #ifdef HAVE_WEBP
save_to_file(buf.data(),"demo.webp","webp"); save_to_file(buf,"demo.webp","webp");
msg += "- demo.webp\n"; msg += "- demo.webp\n";
#endif #endif
msg += "Have a look!\n"; msg += "Have a look!\n";
@ -353,7 +353,7 @@ int main ( int, char** )
cairo_surface_write_to_png(&*image_surface, "cairo-demo.png"); cairo_surface_write_to_png(&*image_surface, "cairo-demo.png");
// but we can also benefit from quantization by converting // but we can also benefit from quantization by converting
// to a mapnik image object and then saving that // to a mapnik image object and then saving that
mapnik::image_data_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));
cairo_image_to_rgba8(im_data, image_surface); cairo_image_to_rgba8(im_data, image_surface);
save_to_file(im_data, "cairo-demo256.png","png8"); save_to_file(im_data, "cairo-demo256.png","png8");
cairo_surface_finish(&*image_surface); cairo_surface_finish(&*image_surface);

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,7 +1,7 @@
# #
# This file is part of Mapnik (c++ mapping toolkit) # This file is part of Mapnik (c++ mapping toolkit)
# #
# Copyright (C) 2013 Artem Pavlenko # Copyright (C) 2015 Artem Pavlenko
# #
# Mapnik is free software; you can redistribute it and/or # Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,13 +17,13 @@
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# #
# #
Import ('env') Import ('env')
import os import os
import platform import platform
lib_dir = os.path.normpath(env['DESTDIR'] + '/' + env['PREFIX'] + '/' + env['LIBDIR_SCHEMA'] + '/mapnik') lib_dir = os.path.normpath(env['DESTDIR'] + '/' + env['PREFIX'] + '/' + env['LIBDIR_SCHEMA'] + '/mapnik')
fonts = 1 fonts = 1
ini_template = ''' ini_template = '''

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -22,7 +22,6 @@
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <mapnik/agg_renderer.hpp> #include <mapnik/agg_renderer.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/layer.hpp> #include <mapnik/layer.hpp>
#include <mapnik/projection.hpp> #include <mapnik/projection.hpp>
#include <mapnik/scale_denominator.hpp> #include <mapnik/scale_denominator.hpp>
@ -42,7 +41,7 @@
#include "mapwidget.hpp" #include "mapwidget.hpp"
#include "info_dialog.hpp" #include "info_dialog.hpp"
using mapnik::image_32; using mapnik::image_rgba8;
using mapnik::Map; using mapnik::Map;
using mapnik::layer; using mapnik::layer;
using mapnik::box2d; using mapnik::box2d;
@ -178,47 +177,51 @@ void MapWidget::mousePressEvent(QMouseEvent* e)
if (fs) if (fs)
{ {
feature_ptr feat = fs->next(); feature_ptr feat = fs->next();
if (feat) if (feat)
{ {
feature_kv_iterator itr(*feat,true); // FIXME
feature_kv_iterator end(*feat); #if 0
feature_kv_iterator itr(*feat,true);
feature_kv_iterator end(*feat);
for ( ;itr!=end; ++itr) for ( ;itr!=end; ++itr)
{ {
info.push_back(QPair<QString,QString>(QString(std::get<0>(*itr).c_str()), info.push_back(QPair<QString,QString>(QString(std::get<0>(*itr).c_str()),
std::get<1>(*itr).to_string().c_str())); std::get<1>(*itr).to_string().c_str()));
} }
using path_type = mapnik::transform_path_adapter<mapnik::view_transform,mapnik::geometry_type>; using path_type = mapnik::transform_path_adapter<mapnik::view_transform,mapnik::vertex_adapter>;
for (unsigned i=0; i<feat->num_geometries();++i) for (unsigned i=0; i<feat->num_geometries();++i)
{ {
mapnik::geometry_type & geom = feat->get_geometry(i); mapnik::geometry_type const& geom = feat->get_geometry(i);
path_type path(t,geom,prj_trans); mapnik::vertex_adapter va(geom);
if (geom.size() > 0) path_type path(t,va,prj_trans);
{ if (va.size() > 0)
QPainterPath qpath;
double x,y;
path.vertex(&x,&y);
qpath.moveTo(x,y);
for (unsigned j = 1; j < geom.size(); ++j)
{ {
path.vertex(&x,&y); QPainterPath qpath;
qpath.lineTo(x,y); double x,y;
va.vertex(&x,&y);
qpath.moveTo(x,y);
for (unsigned j = 1; j < geom.size(); ++j)
{
va.vertex(&x,&y);
qpath.lineTo(x,y);
}
QPainter painter(&pix_);
QPen pen(QColor(255,0,0,96));
pen.setWidth(3);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
painter.setPen(pen);
painter.drawPath(qpath);
update();
} }
QPainter painter(&pix_); }
QPen pen(QColor(255,0,0,96)); #endif
pen.setWidth(3); }
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
painter.setPen(pen);
painter.drawPath(qpath);
update();
}
}
}
} }
if (info.size() > 0) if (info.size() > 0)
@ -479,7 +482,7 @@ void MapWidget::zoomToLevel(int level)
void MapWidget::export_to_file(unsigned ,unsigned ,std::string const&,std::string const&) void MapWidget::export_to_file(unsigned ,unsigned ,std::string const&,std::string const&)
{ {
//image_32 image(width,height); //image_rgba8 image(width,height);
//agg_renderer renderer(map,image); //agg_renderer renderer(map,image);
//renderer.apply(); //renderer.apply();
//image.saveToFile(filename,type); //image.saveToFile(filename,type);
@ -496,14 +499,14 @@ void render_agg(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
unsigned width=map.width(); unsigned width=map.width();
unsigned height=map.height(); unsigned height=map.height();
image_32 buf(width,height); image_rgba8 buf(width,height);
mapnik::agg_renderer<image_32> ren(map,buf,scaling_factor); mapnik::agg_renderer<image_rgba8> ren(map,buf,scaling_factor);
try try
{ {
mapnik::auto_cpu_timer t(std::clog, "rendering took: "); mapnik::auto_cpu_timer t(std::clog, "rendering took: ");
ren.apply(); ren.apply();
QImage image((uchar*)buf.raw_data(),width,height,QImage::Format_ARGB32); QImage image((uchar*)buf.data(),width,height,QImage::Format_ARGB32);
pix = QPixmap::fromImage(image.rgbSwapped()); pix = QPixmap::fromImage(image.rgbSwapped());
} }
//catch (mapnik::config_error & ex) //catch (mapnik::config_error & ex)
@ -529,7 +532,7 @@ void render_grid(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix) void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
{ {
// FIXME
#ifdef HAVE_CAIRO #ifdef HAVE_CAIRO
mapnik::cairo_surface_ptr image_surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,map.width(),map.height()), mapnik::cairo_surface_ptr image_surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,map.width(),map.height()),
mapnik::cairo_surface_closer()); mapnik::cairo_surface_closer());
@ -540,10 +543,9 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
mapnik::cairo_renderer<mapnik::cairo_ptr> renderer(map, cairo, scaling_factor); mapnik::cairo_renderer<mapnik::cairo_ptr> renderer(map, cairo, scaling_factor);
renderer.apply(); renderer.apply();
} }
mapnik::image_data_rgba8 data(map.width(), map.height()); mapnik::image_rgba8 data(map.width(), map.height());
mapnik::cairo_image_to_rgba8(data, image_surface); mapnik::cairo_image_to_rgba8(data, image_surface);
image_32 buf(std::move(data)); QImage image((uchar*)data.bytes(),data.width(),data.height(),QImage::Format_ARGB32);
QImage image((uchar*)buf.raw_data(),buf.width(),buf.height(),QImage::Format_ARGB32);
pix = QPixmap::fromImage(image.rgbSwapped()); pix = QPixmap::fromImage(image.rgbSwapped());
#endif #endif
} }

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -201,10 +201,10 @@ struct symbolizer_icon
{ {
// FIXME! // FIXME!
/* /*
std::shared_ptr<mapnik::image_data_rgba8> symbol = sym.get_image(); std::shared_ptr<mapnik::image_rgba8> symbol = sym.get_image();
if (symbol) if (symbol)
{ {
QImage image(symbol->getBytes(), QImage image(symbol->bytes(),
symbol->width(),symbol->height(),QImage::Format_ARGB32); symbol->width(),symbol->height(),QImage::Format_ARGB32);
QPixmap pix = QPixmap::fromImage(image.rgbSwapped()); QPixmap pix = QPixmap::fromImage(image.rgbSwapped());
return QIcon(pix); return QIcon(pix);

View file

@ -1,6 +1,6 @@
/* This file is part of Mapnik (c++ mapping toolkit) /* This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2014 Artem Pavlenko * Copyright (C) 2015 Artem Pavlenko
* *
* Mapnik is free software; you can redistribute it and/or * Mapnik is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License

7
deps/agg/build.py vendored
View file

@ -1,7 +1,7 @@
# #
# This file is part of Mapnik (c++ mapping toolkit) # This file is part of Mapnik (c++ mapping toolkit)
# #
# Copyright (C) 2013 Artem Pavlenko # Copyright (C) 2015 Artem Pavlenko
# #
# Mapnik is free software; you can redistribute it and/or # Mapnik is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public # modify it under the terms of the GNU Lesser General Public
@ -17,13 +17,12 @@
# License along with this library; if not, write to the Free Software # License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# #
# #
import os import os
from glob import glob from glob import glob
Import('env') Import('env')
lib_env = env.Clone() lib_env = env.Clone()
if 'g++' in env['CXX']: lib_env.Append(CXXFLAGS='-fPIC')
lib_env.Append(CXXFLAGS='-fPIC')
lib_env.StaticLibrary('agg', glob('./src/' + '*.cpp'), LIBS=[]) lib_env.StaticLibrary('agg', glob('./src/' + '*.cpp'), LIBS=[])

View file

@ -330,8 +330,8 @@ struct gray8T
//-------------------------------------------------------------------- //--------------------------------------------------------------------
self_type& opacity(double a_) self_type& opacity(double a_)
{ {
if (a_ < 0) a_ = 0; if (a_ < 0) a = 0;
else if (a_ > 1) a_ = 1; else if (a_ > 1) a = 1;
else a = (value_type)uround(a_ * double(base_mask)); else a = (value_type)uround(a_ * double(base_mask));
return *this; return *this;
} }

View file

@ -80,8 +80,8 @@ struct rgba
//-------------------------------------------------------------------- //--------------------------------------------------------------------
rgba& opacity(double a_) rgba& opacity(double a_)
{ {
if (a_ < 0) a_ = 0; if (a_ < 0) a = 0;
else if (a_ > 1) a_ = 1; else if (a_ > 1) a = 1;
else a = a_; else a = a_;
return *this; return *this;
} }
@ -472,8 +472,8 @@ struct rgba8T
//-------------------------------------------------------------------- //--------------------------------------------------------------------
self_type& opacity(double a_) self_type& opacity(double a_)
{ {
if (a_ < 0) a_ = 0; if (a_ < 0) a = 0;
else if (a_ > 1) a_ = 1; else if (a_ > 1) a = 1;
else a = (value_type)uround(a_ * double(base_mask)); else a = (value_type)uround(a_ * double(base_mask));
return *this; return *this;
} }
@ -882,8 +882,8 @@ struct rgba16
//-------------------------------------------------------------------- //--------------------------------------------------------------------
AGG_INLINE self_type& opacity(double a_) AGG_INLINE self_type& opacity(double a_)
{ {
if (a_ < 0) a_ = 0; if (a_ < 0) a = 0;
if (a_ > 1) a_ = 1; if (a_ > 1) a = 1;
a = value_type(uround(a_ * double(base_mask))); a = value_type(uround(a_ * double(base_mask)));
return *this; return *this;
} }
@ -1238,8 +1238,8 @@ struct rgba32
//-------------------------------------------------------------------- //--------------------------------------------------------------------
AGG_INLINE self_type& opacity(double a_) AGG_INLINE self_type& opacity(double a_)
{ {
if (a_ < 0) a_ = 0; if (a_ < 0) a = 0;
else if (a_ > 1) a_ = 1; else if (a_ > 1) a = 1;
else a = value_type(a_); else a = value_type(a_);
return *this; return *this;
} }

View file

@ -1,295 +0,0 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 1.1 *
* Date : 4 April 2011 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2011 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt *
* *
*******************************************************************************/
#ifndef AGG_CONV_CLIPPER_INCLUDED
#define AGG_CONV_CLIPPER_INCLUDED
#include <cmath>
#include "agg_basics.h"
#include "agg_array.h"
#include "clipper.hpp"
namespace agg
{
enum clipper_op_e { clipper_or,
clipper_and, clipper_xor, clipper_a_minus_b, clipper_b_minus_a };
enum clipper_PolyFillType {clipper_even_odd, clipper_non_zero, clipper_positive, clipper_negative};
template<class VSA, class VSB> class conv_clipper
{
enum status { status_move_to, status_line_to, status_stop };
typedef VSA source_a_type;
typedef VSB source_b_type;
typedef conv_clipper<source_a_type, source_b_type> self_type;
private:
source_a_type* m_src_a;
source_b_type* m_src_b;
status m_status;
int m_vertex;
int m_contour;
int m_scaling_factor;
clipper_op_e m_operation;
pod_bvector<ClipperLib::IntPoint, 8> m_vertex_accumulator;
ClipperLib::Paths m_poly_a;
ClipperLib::Paths m_poly_b;
ClipperLib::Paths m_result;
ClipperLib::Clipper m_clipper;
clipper_PolyFillType m_subjFillType;
clipper_PolyFillType m_clipFillType;
int Round(double val)
{
if ((val < 0)) return (int)(val - 0.5); else return (int)(val + 0.5);
}
public:
conv_clipper(source_a_type &a, source_b_type &b,
clipper_op_e op = clipper_or,
clipper_PolyFillType subjFillType = clipper_even_odd,
clipper_PolyFillType clipFillType = clipper_even_odd,
int scaling_factor = 2) :
m_src_a(&a),
m_src_b(&b),
m_status(status_move_to),
m_vertex(-1),
m_contour(-1),
m_operation(op),
m_subjFillType(subjFillType),
m_clipFillType(clipFillType)
{
m_scaling_factor = std::max(std::min(scaling_factor, 6),0);
m_scaling_factor = Round(std::pow((double)10, m_scaling_factor));
}
~conv_clipper()
{
}
void attach1(VSA &source, clipper_PolyFillType subjFillType = clipper_even_odd)
{ m_src_a = &source; m_subjFillType = subjFillType; }
void attach2(VSB &source, clipper_PolyFillType clipFillType = clipper_even_odd)
{ m_src_b = &source; m_clipFillType = clipFillType; }
void operation(clipper_op_e v) { m_operation = v; }
void rewind(unsigned path_id);
unsigned vertex(double* x, double* y);
bool next_contour();
bool next_vertex(double* x, double* y);
void start_extracting();
void add_vertex_(double &x, double &y);
void end_contour(ClipperLib::Paths &p);
template<class VS> void add(VS &src, ClipperLib::Paths &p){
unsigned cmd;
double x; double y; double start_x; double start_y;
bool starting_first_line;
start_x = 0.0;
start_y = 0.0;
starting_first_line = true;
p.resize(0);
cmd = src->vertex( &x , &y );
while(!is_stop(cmd))
{
if(is_vertex(cmd))
{
if(is_move_to(cmd))
{
if(!starting_first_line ) end_contour(p);
start_x = x;
start_y = y;
}
add_vertex_( x, y );
starting_first_line = false;
}
else if(is_end_poly(cmd))
{
if(!starting_first_line && is_closed(cmd))
add_vertex_( start_x, start_y );
}
cmd = src->vertex( &x, &y );
}
end_contour(p);
}
};
//------------------------------------------------------------------------
template<class VSA, class VSB>
void conv_clipper<VSA, VSB>::start_extracting()
{
m_status = status_move_to;
m_contour = -1;
m_vertex = -1;
}
//------------------------------------------------------------------------------
template<class VSA, class VSB>
void conv_clipper<VSA, VSB>::rewind(unsigned path_id)
{
m_src_a->rewind( path_id );
m_src_b->rewind( path_id );
add( m_src_a , m_poly_a );
add( m_src_b , m_poly_b );
m_result.resize(0);
ClipperLib::PolyFillType pftSubj, pftClip;
switch (m_subjFillType)
{
case clipper_even_odd: pftSubj = ClipperLib::pftEvenOdd; break;
case clipper_non_zero: pftSubj = ClipperLib::pftNonZero; break;
case clipper_positive: pftSubj = ClipperLib::pftPositive; break;
default: pftSubj = ClipperLib::pftNegative;
}
switch (m_clipFillType)
{
case clipper_even_odd: pftClip = ClipperLib::pftEvenOdd; break;
case clipper_non_zero: pftClip = ClipperLib::pftNonZero; break;
case clipper_positive: pftClip = ClipperLib::pftPositive; break;
default: pftClip = ClipperLib::pftNegative;
}
m_clipper.Clear();
switch( m_operation ) {
case clipper_or:
{
m_clipper.AddPaths( m_poly_a , ClipperLib::ptSubject, true );
m_clipper.AddPaths( m_poly_b , ClipperLib::ptClip, true );
m_clipper.Execute( ClipperLib::ctUnion , m_result , pftSubj, pftClip);
break;
}
case clipper_and:
{
m_clipper.AddPaths( m_poly_a , ClipperLib::ptSubject, true );
m_clipper.AddPaths( m_poly_b , ClipperLib::ptClip, true );
m_clipper.Execute( ClipperLib::ctIntersection , m_result, pftSubj, pftClip );
break;
}
case clipper_xor:
{
m_clipper.AddPaths( m_poly_a , ClipperLib::ptSubject, true );
m_clipper.AddPaths( m_poly_b , ClipperLib::ptClip, true );
m_clipper.Execute( ClipperLib::ctXor , m_result, pftSubj, pftClip );
break;
}
case clipper_a_minus_b:
{
m_clipper.AddPaths( m_poly_a , ClipperLib::ptSubject, true );
m_clipper.AddPaths( m_poly_b , ClipperLib::ptClip, true );
m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip );
break;
}
case clipper_b_minus_a:
{
m_clipper.AddPaths( m_poly_b , ClipperLib::ptSubject, true );
m_clipper.AddPaths( m_poly_a , ClipperLib::ptClip, true );
m_clipper.Execute( ClipperLib::ctDifference , m_result, pftSubj, pftClip );
break;
}
}
start_extracting();
}
//------------------------------------------------------------------------------
template<class VSA, class VSB>
void conv_clipper<VSA, VSB>::end_contour( ClipperLib::Paths &p)
{
unsigned i, len;
if( m_vertex_accumulator.size() < 3 ) return;
len = p.size();
p.resize(len+1);
p[len].resize(m_vertex_accumulator.size());
for( i = 0 ; i < m_vertex_accumulator.size() ; i++ )
p[len][i] = m_vertex_accumulator[i];
m_vertex_accumulator.remove_all();
}
//------------------------------------------------------------------------------
template<class VSA, class VSB>
void conv_clipper<VSA, VSB>::add_vertex_(double &x, double &y)
{
ClipperLib::IntPoint v;
v.X = Round(x * m_scaling_factor);
v.Y = Round(y * m_scaling_factor);
m_vertex_accumulator.add( v );
}
//------------------------------------------------------------------------------
template<class VSA, class VSB>
bool conv_clipper<VSA, VSB>::next_contour()
{
m_contour++;
if(m_contour >= (int)m_result.size()) return false;
m_vertex =-1;
return true;
}
//------------------------------------------------------------------------------
template<class VSA, class VSB>
bool conv_clipper<VSA, VSB>::next_vertex(double *x, double *y)
{
m_vertex++;
if(m_vertex >= (int)m_result[m_contour].size()) return false;
*x = (double)m_result[ m_contour ][ m_vertex ].X / m_scaling_factor;
*y = (double)m_result[ m_contour ][ m_vertex ].Y / m_scaling_factor;
return true;
}
//------------------------------------------------------------------------------
template<class VSA, class VSB>
unsigned conv_clipper<VSA, VSB>::vertex(double *x, double *y)
{
if( m_status == status_move_to )
{
if( next_contour() )
{
if( next_vertex( x, y ) )
{
m_status =status_line_to;
return path_cmd_move_to;
}
else
{
m_status = status_stop;
return path_cmd_end_poly | path_flags_close;
}
}
else
return path_cmd_stop;
}
else
{
if( next_vertex( x, y ) )
{
return path_cmd_line_to;
}
else
{
m_status = status_move_to;
return path_cmd_end_poly | path_flags_close;
}
}
}
//------------------------------------------------------------------------------
} //namespace agg
#endif //AGG_CONV_CLIPPER_INCLUDED

236
deps/agg/include/agg_conv_offset.h vendored Normal file
View file

@ -0,0 +1,236 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 1.1 *
* Date : 4 April 2011 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2011 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt *
* *
*******************************************************************************/
// based on adapted agg_conv_clipper.h
#ifndef AGG_CONV_OFFSET_INCLUDED
#define AGG_CONV_OFFSET_INCLUDED
#include <cmath>
#include "agg_basics.h"
#include "agg_array.h"
#include "clipper.hpp"
namespace agg
{
template<class VSA> class conv_offset
{
enum status { status_move_to, status_line_to, status_stop };
typedef VSA source_a_type;
typedef conv_offset<source_a_type> self_type;
private:
source_a_type* m_src_a;
double m_offset;
status m_status;
int m_vertex;
int m_contour;
int m_scaling_factor;
pod_bvector<ClipperLib::IntPoint, 8> m_vertex_accumulator;
ClipperLib::Paths m_poly_a;
ClipperLib::Paths m_result;
ClipperLib::ClipperOffset m_clipper_offset;
int Round(double val)
{
if ((val < 0)) return (int)(val - 0.5); else return (int)(val + 0.5);
}
public:
conv_offset(source_a_type &a, double offset = 0.0,
int scaling_factor = 0)
: m_src_a(&a),
m_offset(offset),
m_status(status_move_to),
m_vertex(-1),
m_contour(-1)
{
m_scaling_factor = std::max(std::min(scaling_factor, 6),0);
m_scaling_factor = Round(std::pow((double)10, m_scaling_factor));
}
~conv_offset()
{
}
void set_offset(double offset) { m_offset = offset;}
unsigned type() const
{
return static_cast<unsigned>(m_src_a->type());
}
double get_offset() const
{
return m_offset;
}
void rewind(unsigned path_id);
unsigned vertex(double* x, double* y);
bool next_contour();
bool next_vertex(double* x, double* y);
void start_extracting();
void add_vertex_(double &x, double &y);
void end_contour(ClipperLib::Paths &p);
template<class VS> void add(VS &src, ClipperLib::Paths &p)
{
unsigned cmd;
double x; double y; double start_x; double start_y;
bool starting_first_line;
start_x = 0.0;
start_y = 0.0;
starting_first_line = true;
p.resize(0);
cmd = src->vertex( &x , &y );
while(!is_stop(cmd))
{
if(is_vertex(cmd))
{
if(is_move_to(cmd))
{
if(!starting_first_line ) end_contour(p);
start_x = x;
start_y = y;
}
add_vertex_( x, y );
starting_first_line = false;
}
else if(is_end_poly(cmd))
{
if(!starting_first_line && is_closed(cmd))
add_vertex_( start_x, start_y );
}
cmd = src->vertex( &x, &y );
}
end_contour(p);
}
};
//------------------------------------------------------------------------
template<class VSA>
void conv_offset<VSA>::start_extracting()
{
m_status = status_move_to;
m_contour = -1;
m_vertex = -1;
}
//------------------------------------------------------------------------------
template<class VSA>
void conv_offset<VSA>::rewind(unsigned path_id)
{
m_src_a->rewind( path_id );
//m_src_b->rewind( path_id );
add( m_src_a , m_poly_a );
//add( m_src_b , m_poly_b );
m_result.resize(0);
m_clipper_offset.Clear();
m_clipper_offset.AddPaths(m_poly_a,ClipperLib::jtMiter, ClipperLib::etOpenButt);//ClosedLine);//Polygon);
m_clipper_offset.Execute(m_result, m_offset * m_scaling_factor);
start_extracting();
}
//------------------------------------------------------------------------------
template<class VSA>
void conv_offset<VSA>::end_contour( ClipperLib::Paths &p)
{
unsigned i, len;
if( m_vertex_accumulator.size() < 3 ) return;
len = p.size();
p.resize(len+1);
p[len].resize(m_vertex_accumulator.size());
for( i = 0 ; i < m_vertex_accumulator.size() ; i++ )
p[len][i] = m_vertex_accumulator[i];
m_vertex_accumulator.remove_all();
}
//------------------------------------------------------------------------------
template<class VSA>
void conv_offset<VSA>::add_vertex_(double &x, double &y)
{
ClipperLib::IntPoint v;
v.X = Round(x * m_scaling_factor);
v.Y = Round(y * m_scaling_factor);
m_vertex_accumulator.add( v );
}
//------------------------------------------------------------------------------
template<class VSA>
bool conv_offset<VSA>::next_contour()
{
m_contour++;
if(m_contour >= (int)m_result.size()) return false;
m_vertex =-1;
return true;
}
//------------------------------------------------------------------------------
template<class VSA>
bool conv_offset<VSA>::next_vertex(double *x, double *y)
{
m_vertex++;
if(m_vertex >= (int)m_result[m_contour].size()) return false;
*x = (double)m_result[ m_contour ][ m_vertex ].X / m_scaling_factor;
*y = (double)m_result[ m_contour ][ m_vertex ].Y / m_scaling_factor;
return true;
}
//------------------------------------------------------------------------------
template<class VSA>
unsigned conv_offset<VSA>::vertex(double *x, double *y)
{
if( m_status == status_move_to )
{
if( next_contour() )
{
if( next_vertex( x, y ) )
{
m_status =status_line_to;
return path_cmd_move_to;
}
else
{
m_status = status_stop;
return path_cmd_end_poly | path_flags_close;
}
}
else
return path_cmd_stop;
}
else
{
if( next_vertex( x, y ) )
{
return path_cmd_line_to;
}
else
{
m_status = status_move_to;
return path_cmd_end_poly | path_flags_close;
}
}
}
//------------------------------------------------------------------------------
} //namespace agg
#endif //AGG_CONV_OFFSET_INCLUDED

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