update from master
This commit is contained in:
commit
249cb3e2ca
1390 changed files with 51563 additions and 20112 deletions
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -39,8 +39,16 @@ tests/data/sqlite/*index
|
|||
demo/c++/cairo-demo.pdf
|
||||
demo/c++/cairo-demo.png
|
||||
demo/c++/cairo-demo256.png
|
||||
demo/c++/cairo-demo.svg
|
||||
demo/c++/demo.tif
|
||||
demo/c++/demo.jpg
|
||||
demo/c++/demo.png
|
||||
demo/c++/demo256.png
|
||||
demo/viewer/Makefile
|
||||
demo/viewer/Makefile.Debug
|
||||
demo/viewer/Makefile.Release
|
||||
demo/viewer/release/
|
||||
demo/viewer/ui_about.h
|
||||
demo/viewer/ui_info.h
|
||||
demo/viewer/ui_layer_info.h
|
||||
tests/cpp_tests/*-bin
|
||||
|
|
21
.travis.yml
Normal file
21
.travis.yml
Normal file
|
@ -0,0 +1,21 @@
|
|||
language: cpp
|
||||
|
||||
compiler: clang
|
||||
|
||||
before_install:
|
||||
- echo 'yes' | sudo add-apt-repository ppa:mapnik/boost
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq libboost-dev libboost-filesystem-dev libboost-program-options-dev libboost-python-dev libboost-regex-dev libboost-system-dev libboost-thread-dev python-nose libicu-dev libpng-dev libjpeg-dev libtiff-dev libz-dev libfreetype6-dev libxml2-dev libproj-dev
|
||||
|
||||
script:
|
||||
- ./configure DEMO=False BINDINGS='python' CPP_TESTS=False CAIRO=False INPUT_PLUGINS='' OPTIMIZATION=1 JOBS=2 FAST=True && make
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#mapnik"
|
||||
use_notice: true
|
115
AUTHORS.md
115
AUTHORS.md
|
@ -2,60 +2,61 @@
|
|||
|
||||
Mapnik is written by Artem Pavlenko with contributions from:
|
||||
|
||||
Andy Allen
|
||||
AJ Ashton
|
||||
Matt Amos
|
||||
Lucio Asnaghi
|
||||
Justin Bronn
|
||||
Christopher Brown
|
||||
Jon Burgess
|
||||
Toby Collet
|
||||
Robert Coup
|
||||
Berteun Damman
|
||||
Craig de Stigter
|
||||
Jean-Francois Doyon
|
||||
David Eastcott
|
||||
Krzysztof Godlewski
|
||||
Beau Gunderson
|
||||
John Hague
|
||||
Dominic Hargreaves
|
||||
Aubrey Holland
|
||||
Tom Hughes
|
||||
Konstantin Käfer
|
||||
Mak Kolybabi
|
||||
Peter Körner
|
||||
Hermann Kraus
|
||||
Stella Laurenzo
|
||||
David Leaver
|
||||
Carlos López
|
||||
Dennis Luxen
|
||||
Tom MacWright
|
||||
Michal Migurski
|
||||
Andrii Mishkovskyi
|
||||
Ben Moores
|
||||
Dražen Odobašić
|
||||
Cameron Patrick
|
||||
Igor Podolskiy
|
||||
Reid Priedhorsky
|
||||
Brian Quinion
|
||||
Marcin Rudowski
|
||||
Christopher Schmidt
|
||||
Andreas Schneider
|
||||
Vincent Schut
|
||||
Ehud Shabtai
|
||||
David Siegel
|
||||
Steve Singer
|
||||
Paul Smith
|
||||
Vince Spader
|
||||
Philipp Spitzer
|
||||
Dane Springmeyer
|
||||
Dave Stubbs
|
||||
River Tarnell
|
||||
Oliver Tonnhofer
|
||||
Alberto Valverde
|
||||
Martijn van Oosterhout
|
||||
Andreas Volz
|
||||
Lennard voor den Dag
|
||||
Shaun Walbridge
|
||||
Nick Whitelegg
|
||||
Leslie Wu
|
||||
* Andy Allen
|
||||
* AJ Ashton
|
||||
* Matt Amos
|
||||
* Lucio Asnaghi
|
||||
* Justin Bronn
|
||||
* Christopher Brown
|
||||
* Jon Burgess
|
||||
* Toby Collet
|
||||
* Robert Coup
|
||||
* Berteun Damman
|
||||
* Craig de Stigter
|
||||
* Jean-Francois Doyon
|
||||
* David Eastcott
|
||||
* Krzysztof Godlewski
|
||||
* Beau Gunderson
|
||||
* John Hague
|
||||
* Dominic Hargreaves
|
||||
* Aubrey Holland
|
||||
* Tom Hughes
|
||||
* Konstantin Käfer
|
||||
* Mak Kolybabi
|
||||
* Peter Körner
|
||||
* Hermann Kraus
|
||||
* Stella Laurenzo
|
||||
* David Leaver
|
||||
* Carlos López
|
||||
* Dennis Luxen
|
||||
* Tom MacWright
|
||||
* Michal Migurski
|
||||
* Andrii Mishkovskyi
|
||||
* Ben Moores
|
||||
* Dražen Odobašić
|
||||
* Cameron Patrick
|
||||
* Igor Podolskiy
|
||||
* Reid Priedhorsky
|
||||
* Brian Quinion
|
||||
* Marcin Rudowski
|
||||
* Christopher Schmidt
|
||||
* Andreas Schneider
|
||||
* Vincent Schut
|
||||
* Ehud Shabtai
|
||||
* David Siegel
|
||||
* Steve Singer
|
||||
* Paul Smith
|
||||
* Vince Spader
|
||||
* Philipp Spitzer
|
||||
* Dane Springmeyer
|
||||
* Dave Stubbs
|
||||
* River Tarnell
|
||||
* Oliver Tonnhofer
|
||||
* Alberto Valverde
|
||||
* Martijn van Oosterhout
|
||||
* Andreas Volz
|
||||
* Lennard voor den Dag
|
||||
* Shaun Walbridge
|
||||
* Rich Wareham
|
||||
* Nick Whitelegg
|
||||
* Leslie Wu
|
||||
|
|
342
CHANGELOG.md
342
CHANGELOG.md
|
@ -4,24 +4,129 @@ A simple log of core changes affecting Mapnik usage.
|
|||
|
||||
Developers: Please commit along with changes.
|
||||
|
||||
For a complete change history, see the SVN log.
|
||||
For a complete change history, see the git log.
|
||||
|
||||
## Future
|
||||
|
||||
- Added Layer `buffer-size` that can be used to override Map `buffer-size` to avoid
|
||||
over-fetching of data that does not need to be buffered as much as other layers.
|
||||
Map level `buffer-size` will be default if layers do not set the option. Renamed a
|
||||
previously undocumented parameter by the same name that impacted clipping extent and
|
||||
was not needed (clipping padding should likely be a symbolizer level option) (#1566)
|
||||
|
||||
- Fixed building symbolizer rendering to be fully sensitive to alpha (8b66128c892 / bc8ea1c5a7a)
|
||||
|
||||
- Added 64 bit integer support in the grid_renderer (#1662)
|
||||
|
||||
- `<Filter>[attr]</Filter>` now returns false if attr is an empty string (#1665)
|
||||
|
||||
- Added 64 bit integer support in expressions and feature ids (#1661,#1662)
|
||||
|
||||
- Added support for DBF `Logical` type: #1614
|
||||
|
||||
- Added serialization of `line-offset` to save_map (#1562)
|
||||
|
||||
- Enabled default input plugin directory and fonts path to be set inherited from environment settings in
|
||||
python bindings to make it easier to run tests locally (#1594). New environment settings are:
|
||||
- MAPNIK_INPUT_PLUGINS_DIRECTORY
|
||||
- MAPNIK_FONT_DIRECTORY
|
||||
|
||||
- Added support for controlling rendering behavior of markers on multi-geometries `marker-multi-policy` (#1555,#1573)
|
||||
|
||||
- Added alternative PNG/ZLIB implementation (`miniz`) that can be enabled with `e=miniz` (#1554)
|
||||
|
||||
- Added support for setting zlib `Z_FIXED` strategy with format string: `png:z=fixed`
|
||||
|
||||
- Fixed handling of transparency level option in Octree-based PNG encoding (#1556)
|
||||
|
||||
- Faster rendering of rasters by reducing memory allocation of temporary buffers (#1516)
|
||||
|
||||
- Added ability to pass a pre-created collision detector to the cairo renderer (#1444)
|
||||
|
||||
- Tolerance parameter is now supported for querying datasources at a given point (#503/#1499)
|
||||
|
||||
- Improved detection of newlines in CSV files - now more robust in the face of mixed newline types (#1497)
|
||||
|
||||
- Allow style level compositing operations to work outside of featureset extents across tiled requests (#1477)
|
||||
|
||||
- Support for encoding `literal` postgres types as strings 69fb17cd3/#1466
|
||||
|
||||
- Fixed zoom_all behavior when Map maximum-extent is provided. Previously maximum-extent was used outright but
|
||||
now the combined layer extents will be again respected: they will be clipped to the maximum-extent if possible
|
||||
and only when back-projecting fails for all layers will the maximum-extent be used as a fallback (#1473)
|
||||
|
||||
## Mapnik 2.1.0
|
||||
|
||||
Released Aug 23, 2012
|
||||
|
||||
(Packaged from a25aac8)
|
||||
|
||||
- Feature-level compositing (comp-op) for all symbolizers (except building) in AGG and Cairo renderers (#1409)
|
||||
|
||||
- Style-level compositing (comp-op) (#1409) and style-level opacity for AGG renderer (#314)
|
||||
|
||||
- New experimental framework for image manipulation called `image-filters` to allow things to be done across entire layer canvas like burring (#1412)
|
||||
|
||||
- Support for recoloring stroke, fill, and opacity of SVG files (#1410 / #659)
|
||||
|
||||
- Support for data-driven transform expressions (#664)
|
||||
|
||||
- New support for offsetting geometries / parallel lines in line_symbolizer (#927/#1269)
|
||||
|
||||
- New support for clipping geometries - now default enabled on all symbolizers (#1116)
|
||||
|
||||
- Framework for chainable geometry transformations (called `vertex_converters`) so that you can do things like clip, smooth, and offset at the same time (#927)
|
||||
|
||||
- WKT parsing now is more robust and supports multi-geometries (#745)
|
||||
|
||||
- New support for outputting WKT/WKB/GeoJSON/SVG from mapnik.Geometry objects (#1411)
|
||||
|
||||
- New experimental python datasource plugin (#1337)
|
||||
|
||||
- New experimental geojson datasource plugin using in-memory rtree indexing (#1413)
|
||||
|
||||
- Cairo rendering is now much more similiar to AGG rendering as cairo backend now supports `scale_factor` (#1280) and other fixed have landed (#1343, #1233, #1344, #1242, #687, #737, #1006, #1071)
|
||||
|
||||
- mapnik::Feature objects and datasource plugins now use a `Context` to store attribute schemas to reduce the memory footprint of features (#834)
|
||||
|
||||
- Added Stroke `miterlimit` (#786)
|
||||
|
||||
- Python: exposed Map `background_image` (and aliased `background` to `background_color`)
|
||||
|
||||
- Python: exposed BuildingSymbolizer
|
||||
|
||||
- Support in the CSV plugin for reading JSON encoded geometries (#1392)
|
||||
|
||||
- Increased grid encoding performance (#1315)
|
||||
|
||||
- Added support for setting opacity dynamically on images in polygon pattern and markers symbolizers
|
||||
|
||||
- Added support for filtering on a features geometry type, either `point`, `linestring`, `polygon`,
|
||||
or `collection` using the expression keyword of `[mapnik::geometry_type]` (#546)
|
||||
|
||||
- MarkersSymbolizer width and height moved to expressions (#1102)
|
||||
|
||||
- PostGIS: Added `simplify_geometries` option - will trigger ST_Simplify on geometries before returning to Mapnik (#1179)
|
||||
|
||||
- Improved error feedback for invalid values passed to map.query_point
|
||||
|
||||
- Fixed rendering of thin svg lines (#1129)
|
||||
|
||||
- Improved logging/debugging system with release logs and file redirection (https://github.com/mapnik/mapnik/wiki/Runtime-Logging) (#937 and partially #986, #467)
|
||||
|
||||
- GDAL: allow setting nodata value on the fly (will override value if nodata is set in data) (#1161)
|
||||
|
||||
- GDAL: respect nodata for paletted/colormapped images (#1160)
|
||||
|
||||
- PostGIS: Added a new option called 'autodetect_key_field' (by default false) that if true will
|
||||
trigger autodetection of a given tables' primary key allowing for feature.id() to represent
|
||||
globally unique ids. This option has no effect if the user has not manually supplied the 'key_field' option. (#804)
|
||||
- PostGIS: Added a new option called `autodetect_key_field` (by default false) that if true will
|
||||
trigger autodetection of the table primary key allowing for feature.id() to represent
|
||||
globally unique ids. This option has no effect if the user has not manually supplied the `key_field` option. (#804)
|
||||
|
||||
- Cairo: Add full rendering support for markers to match AGG renderer functionality (#1071)
|
||||
|
||||
- Fix Markers rendering so that ellipse height/width units are pixels (previously were unintentionally radii) (#1134)
|
||||
|
||||
- Added 'ignore-placement` attribute to markers-symbolizer (#1135)
|
||||
- Added `ignore-placement` attribute to markers-symbolizer (#1135)
|
||||
|
||||
- Removed PointDatasource - use more robust MemoryDatasource instead (#1032)
|
||||
|
||||
|
@ -37,10 +142,43 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- Added support for justify-alignment=auto. This is the new default. (#1125)
|
||||
|
||||
- Added support for grouped rendering using the `group-by` layer option: https://github.com/mapnik/mapnik/wiki/Grouped-rendering
|
||||
|
||||
|
||||
## Mapnik 2.0.2
|
||||
|
||||
Released Aug 3, 2012
|
||||
|
||||
(Packaged from adb2ec741)
|
||||
|
||||
- Fixed handling of empty WKB geometries (#1334)
|
||||
|
||||
- Fixed naming of `stroke-dashoffset` in save_map (cc3cd5f63f28)
|
||||
|
||||
- Fixed support for boost 1.50 (8dea5a5fe239233)
|
||||
|
||||
- Fixed TextSymbolizer placement in Cairo backend so it respects avoid-edges and minimum-padding across all renderers (#1242)
|
||||
|
||||
- Fixed ShieldSymbolizer placement so it respects avoid-edges and minimum-padding across all renderers (#1242)
|
||||
|
||||
- Rolled back change made in 2.0.1 to marker width/height meaning that Mapnik > 2.0.2 will stick to assuming width/heigh are radii for back compatibility with 2.0.0. The reverted change is seen below as "Fix Markers rendering so that ellipse height/width units are pixels (previously were unintentionally radii)". Issue tracking this is #1163
|
||||
|
||||
- XML: Fixed to avoid throwing if a `<Parameters>` element is encountered (which is supported in >= 2.1.x)
|
||||
|
||||
- Support for PostGIS 2.0 in the pgsql2sqlite command (e69c44e/47e5b3c)
|
||||
|
||||
- Fixed reference counting of Py_None when returning null attributes from Postgres during UTFGrid encoding, which could cause a Fatal Python error: deallocating None (#1221)
|
||||
|
||||
- Fixed possible breakage registering plugins via python if a custom PREFIX or DESTDIR was used (e.g. macports/homebrew) (#1171)
|
||||
|
||||
- Fixed memory leak in the case of proj >= 4.8 and a projection initialization error (#1173)
|
||||
|
||||
|
||||
## Mapnik 2.0.1
|
||||
|
||||
(Packaged from 5cd3cb2efdaf7e9990a57e8e00b652a81aaa39ae)
|
||||
Released April 10, 2012
|
||||
|
||||
(Packaged from 57347e9106)
|
||||
|
||||
- Support for PostGIS 2.0 (#956,#1083)
|
||||
|
||||
|
@ -54,7 +192,7 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- Fix Markers rendering so that ellipse height/width units are pixels (previously were unintentially radii) (#1134)
|
||||
|
||||
- Added 'ignore-placement` attribute to markers-symbolizer (#1135)
|
||||
- Added `ignore-placement` attribute to markers-symbolizer (#1135)
|
||||
|
||||
- Removed svn_revision info from mapnik-config and python bindings as git is now used
|
||||
|
||||
|
@ -75,11 +213,15 @@ For a complete change history, see the SVN log.
|
|||
|
||||
## Mapnik 2.0.0
|
||||
|
||||
Released September 26, 2011
|
||||
|
||||
(Packaged from 5b4c20eab3)
|
||||
|
||||
- Add minimum-path-length property to text_symbolizer to allow labels to be placed only on lines of a certain length (#865)
|
||||
|
||||
- Add support for png quantization using fixed palettes (#843)
|
||||
|
||||
- Add AlsoFilter functionality - http://trac.mapnik.org/wiki/AlsoFilter
|
||||
- Add AlsoFilter functionality - https://github.com/mapnik/mapnik/wiki/AlsoFilter
|
||||
|
||||
- SQLite Plugin: optimize i/o using shared cache and no mutexes (#797)
|
||||
|
||||
|
@ -100,13 +242,13 @@ For a complete change history, see the SVN log.
|
|||
from a file that files directory is used. And a custom value can still be passed as an argument to
|
||||
load_map_from_string().
|
||||
|
||||
- Added python function 'render_grid' to allow conversion of grid buffer to python object containing list of grid
|
||||
- Added python function `render_grid` to allow conversion of grid buffer to python object containing list of grid
|
||||
pixels, list of keys, and a and dictionary of feature attributes.
|
||||
|
||||
- Added new rendering backend, grid_renderer, that collects the attributes of rendered features and
|
||||
burns their ids into a grid buffer.
|
||||
|
||||
- Added optional 'maximum-extent' parameter to map object. If set will be used, instead of combined
|
||||
- Added optional `maximum-extent` parameter to map object. If set will be used, instead of combined
|
||||
layer extents, for return value of map.zoom_all(). Useful in cases where the combined layer extents
|
||||
cannot possibly be projected into the map srs or the user wishes to control map bounds without
|
||||
modifying the extents of each layer.
|
||||
|
@ -119,9 +261,9 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- Added support for drawing only first matching rule using filter-mode="first" in Style (#706)
|
||||
|
||||
- Added support to PointSymbolizer ('ignore_placement') for skipping adding placed points to collision detector (#564)
|
||||
- Added support to PointSymbolizer (`ignore_placement`) for skipping adding placed points to collision detector (#564)
|
||||
|
||||
- Added ability to register fonts within XML using Map level 'font_directory' parameter (#168)
|
||||
- Added ability to register fonts within XML using Map level `font-directory` parameter (#168)
|
||||
|
||||
- TextSymbolizer: Change text_convert to text_transform to better match css naming (r2211)
|
||||
|
||||
|
@ -129,8 +271,8 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- Upgraded to the latest proj4 string literal for EPSG:4326 (WGS84) as global default projection (#333)
|
||||
|
||||
- Added 'mapnik_version_from_string()' function in python bindings to easily convert string representation
|
||||
of version number to the integer format used in 'mapnik/version.hpp'. e.g. '0.7.1' --> 701.
|
||||
- Added `mapnik_version_from_string()` function in python bindings to easily convert string representation
|
||||
of version number to the integer format used in `mapnik/version.hpp`. e.g. `0.7.1` --> `701`.
|
||||
|
||||
- Added xinclude (http://www.w3.org/TR/xinclude/) support to libxml2-based xml parser (oldtopos) (#567)
|
||||
|
||||
|
@ -138,7 +280,7 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- Added support for setting global alignment of polygon pattern fills (#203)
|
||||
|
||||
- Added support for choosing OGR layer by index number using 'layer_by_index' parameter (r1904)
|
||||
- Added support for choosing OGR layer by index number using `layer_by_index` parameter (r1904)
|
||||
|
||||
- Added support for fractional halo widths (using FT Stroker) (#93)
|
||||
|
||||
|
@ -162,9 +304,13 @@ For a complete change history, see the SVN log.
|
|||
- Implement MarkersSymbolizer in Cairo render and improve the markers placement finder. (#553)
|
||||
|
||||
|
||||
# Mapnik 0.7.2 Release
|
||||
# Mapnik 0.7.2
|
||||
|
||||
- Added forward compatibility for Mapnik 2.0 XML syntax (https://trac.mapnik.org/wiki/Mapnik2/Changes)
|
||||
Released Oct 18, 2011
|
||||
|
||||
(Packaged from bc5cabeb6a)
|
||||
|
||||
- Added forward compatibility for Mapnik 2.0 XML syntax (https://github.com/mapnik/mapnik/wiki/Mapnik2/Changes)
|
||||
|
||||
- Build fixes to ensure boost_threads are not used unless THREADING=multi build option is used
|
||||
|
||||
|
@ -196,7 +342,7 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- Various fixes to sqlite, ogr, and occi driver backported from trunk.
|
||||
|
||||
- Ensured that '\n' triggers linebreaks in text rendering (#584)
|
||||
- Ensured that `\n` triggers linebreaks in text rendering (#584)
|
||||
|
||||
- Support for boost filesystem v3
|
||||
|
||||
|
@ -205,9 +351,53 @@ For a complete change history, see the SVN log.
|
|||
- Fixed reading of label_position_tolerance on text_symbolizer and height for building_symbolizer
|
||||
|
||||
|
||||
# Mapnik 0.7.0 Release
|
||||
# Mapnik 0.7.1
|
||||
|
||||
(Packaged from r1574)
|
||||
Released March 23, 2010
|
||||
|
||||
(Packaged from r1745/db89f1ca75)
|
||||
|
||||
- Rasters: Various fixes and improvements to 8bit png output ([#522](https://github.com/mapnik/mapnik/issues/522),[#475](https://github.com/mapnik/mapnik/issues/475))
|
||||
|
||||
- XML: Save map buffer_size when serializing map.
|
||||
|
||||
- SCons: Added new build options `PRIORITIZE_LINKING` and `LINK_PRIORITY`. The first is a boolean (default True)
|
||||
of whether to use the new sorting implementation that gives explcit preference to custom or local paths
|
||||
during compile and linking that will affect builds when duplicate libraries and include directories are on the
|
||||
system. LINK_PRIORITY defaults to prioritizing internal sources of the mapnik source folder, then local/user
|
||||
installed libraries over system libraries, but the option can be customized. Sorting not only ensures that
|
||||
compiling and linking will more likely match the desired libraries but also gives more likelyhood to avoid
|
||||
the scenario where libraries are linked that don`t match the includes libmapnik compiled against.
|
||||
|
||||
- XML: Fixed behavior of PolygonPatternSymbolizer and LinePatternSymbolizer whereby width, height,
|
||||
and type of images is actually allowed to be optionally ommitted ([#508](https://github.com/mapnik/mapnik/issues/508)). This was added in r1543 but
|
||||
only worked correctly for PointSymbolizer and ShieldSymbolizer.
|
||||
|
||||
- Fixed reading of PostGIS data on Big Endian systems ([#515](https://github.com/mapnik/mapnik/issues/515))
|
||||
|
||||
- PostGIS: Added better support for alterative schemas ([#500](https://github.com/mapnik/mapnik/issues/500))
|
||||
|
||||
- AGG Renderer - Enforced default gamma function on all symbolizers to ensure proper antialiasing
|
||||
even when gamma is modified on the PolygonSymbolizer. ([#512](https://github.com/mapnik/mapnik/issues/512))
|
||||
|
||||
- PNG: fixed png256 for large images and some improvements to reduce color corruptions ([#522](https://github.com/mapnik/mapnik/issues/522))
|
||||
|
||||
- PNG: Added new quantization method for indexed png format using hextree with full support for alpha
|
||||
channel. Also new method has some optimizations for color gradients common when using elevation based
|
||||
rasters. By default old method using octree is used. (r1680, r1683, [#477](https://github.com/mapnik/mapnik/issues/477))
|
||||
|
||||
- PNG: Added initial support for passing options to png writter like number of colors, transparency
|
||||
support, quantization method and possibly other in future using type parameter. For example
|
||||
"png8:c=128:t=1:m=h" limits palette to 128 colors, uses only binary transparency (0 - none,
|
||||
1 - binary, 2 - full), and new method of quantization using hextree (h - hextree, o - octree).
|
||||
Existing type "png256" can be also written using "png8:c=256:m=o:t=2" (r1680, r1683, [#477](https://github.com/mapnik/mapnik/issues/477))
|
||||
|
||||
|
||||
# Mapnik 0.7.0
|
||||
|
||||
Released January, 19 2010
|
||||
|
||||
(Packaged from r1574/a0da946be9)
|
||||
|
||||
- Core: Fixed linking to external libagg (r1297,r1299)
|
||||
|
||||
|
@ -217,26 +407,26 @@ For a complete change history, see the SVN log.
|
|||
|
||||
* Use the gdaladdo utility to add overviews to existing GDAL datasets
|
||||
|
||||
- PostGIS: Added an optional 'geometry_table' parameter. The 'geometry_table' used by Mapnik to look up
|
||||
metadata in the geometry_columns and calculate extents (when the 'geometry_field' and 'srid' parameters
|
||||
are not supplied). If 'geometry_table' is not specified Mapnik will attempt to determine the name of the
|
||||
table to query based on parsing the 'table' parameter, which may fail for complex queries with more than
|
||||
one 'from' keyword. Using this parameter should allow for existing metadata and table indexes to be used
|
||||
while opening the door to much more complicated subqueries being passed to the 'table' parameter without
|
||||
- PostGIS: Added an optional `geometry_table` parameter. The `geometry_table` used by Mapnik to look up
|
||||
metadata in the geometry_columns and calculate extents (when the `geometry_field` and `srid` parameters
|
||||
are not supplied). If `geometry_table` is not specified Mapnik will attempt to determine the name of the
|
||||
table to query based on parsing the `table` parameter, which may fail for complex queries with more than
|
||||
one `from` keyword. Using this parameter should allow for existing metadata and table indexes to be used
|
||||
while opening the door to much more complicated subqueries being passed to the `table` parameter without
|
||||
failing (#260, #426).
|
||||
|
||||
- PostGIS Plugin: Added optional 'geometry_field' and 'srid' parameters. If specified these will allow
|
||||
- PostGIS Plugin: Added optional `geometry_field` and `srid` parameters. If specified these will allow
|
||||
Mapnik to skip several queries to try to determine these values dynamically, and can be helpful to avoid
|
||||
possible query failures during metadata lookup with complex subqueries as discussed in #260 and #436, but
|
||||
also solvable by specifying the 'geometry_table' parameter. (r1300,#376)
|
||||
also solvable by specifying the `geometry_table` parameter. (r1300,#376)
|
||||
|
||||
- PostGIS: Added an optional 'extent_from_subquery' parameter that when true (while the 'extent' parameter is
|
||||
not provided and 'estimate_extent' is false) will direct Mapnik to calculate the extent upon the exact table
|
||||
or sql provided in the 'table' parameter. If a sub-select is used for the table parameter then this will,
|
||||
- PostGIS: Added an optional `extent_from_subquery` parameter that when true (while the `extent` parameter is
|
||||
not provided and `estimate_extent` is false) will direct Mapnik to calculate the extent upon the exact table
|
||||
or sql provided in the `table` parameter. If a sub-select is used for the table parameter then this will,
|
||||
in cases where the subquery limits results, provide a faster and more accurate layer extent. It will have
|
||||
no effect if the 'table' parameter is simply an existing table. This parameter is false by default. (#456)
|
||||
no effect if the `table` parameter is simply an existing table. This parameter is false by default. (#456)
|
||||
|
||||
- PostGIS Plugin: Added '!bbox!' token substitution ability in sql query string. This opens the door for various
|
||||
- PostGIS Plugin: Added `!bbox!` token substitution ability in sql query string. This opens the door for various
|
||||
complex queries that may aggregate geometries to be kept fast by allowing proper placement of the bbox
|
||||
query to be used by indexes. (#415)
|
||||
|
||||
|
@ -252,7 +442,7 @@ For a complete change history, see the SVN log.
|
|||
(Select * from table where geom && !bbox!) as map
|
||||
</Parameter>
|
||||
|
||||
- PostGIS Plugin: Added 'scale_denominator' substitution ability in sql query string (#415/#465)
|
||||
- PostGIS Plugin: Added `scale_denominator` substitution ability in sql query string (#415/#465)
|
||||
|
||||
* Pass the scale_denominator token inside a subquery like: !scale_denominator!
|
||||
|
||||
|
@ -260,7 +450,7 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- PostGIS Plugin: Added support for quoted table names (r1454) (#393)
|
||||
|
||||
- PostGIS: Add a 'persist_connection' option (default true), that when false will release
|
||||
- PostGIS: Add a `persist_connection` option (default true), that when false will release
|
||||
the idle psql connection after datasource goes out of scope (r1337) (#433,#434)
|
||||
|
||||
- PostGIS: Added support for BigInt (int8) postgres type (384)
|
||||
|
@ -281,19 +471,19 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- PNG: Added support for semi-transparency in png256 output (#477,#202)
|
||||
|
||||
- PolygonSymbolizer: Added 'gamma' attribute to allow for dilation of polygon edges - a solution
|
||||
- PolygonSymbolizer: Added `gamma` attribute to allow for dilation of polygon edges - a solution
|
||||
to gap artifacts or "ghost lines" between adjacent polygons and allows for slight sharpening of
|
||||
the edges of non overlapping polygons. Accepts any values but 0-1 is the recommended range.
|
||||
|
||||
- TextSymbolizer: Large set of new attributes: 'text_transform', 'line_spacing', 'character_spacing',
|
||||
'wrap_character', 'wrap_before', 'horizontal_alignment', 'justify_alignment', and 'opacity'.
|
||||
- TextSymbolizer: Large set of new attributes: `text_transform`, `line_spacing`, `character_spacing`,
|
||||
`wrap_character`, `wrap_before`, `horizontal_alignment`, `justify_alignment`, and `opacity`.
|
||||
|
||||
* More details at changesets: r1254 and r1341
|
||||
|
||||
- SheildSymbolizer: Added special new attributes: 'unlock_image', 'VERTEX' placement, 'no_text' and many
|
||||
attributes previously only supported in the TextSymbolizer: 'allow_overlap', 'vertical_alignment',
|
||||
'horizontal_alignment', 'justify_alignment', 'wrap_width', 'wrap_character', 'wrap_before', 'text_transform',
|
||||
'line_spacing', 'character_spacing', and 'opacity'.
|
||||
- SheildSymbolizer: Added special new attributes: `unlock_image`, `VERTEX` placement, `no_text` and many
|
||||
attributes previously only supported in the TextSymbolizer: `allow_overlap`, `vertical_alignment`,
|
||||
`horizontal_alignment`, `justify_alignment`, `wrap_width`, `wrap_character`, `wrap_before`, `text_transform`,
|
||||
`line_spacing`, `character_spacing`, and `opacity`.
|
||||
|
||||
* More details at changeset r1341
|
||||
|
||||
|
@ -301,42 +491,42 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- XML: Fixed memory leak in libxml2 implementation (#473)
|
||||
|
||||
- XML: Added function to serialize map to string, called 'mapnik.save_map_to_string()' (#396)
|
||||
- XML: Added function to serialize map to string, called `mapnik.save_map_to_string()` (#396)
|
||||
|
||||
- XML: Added parameter to <Map> called 'minimum_version' to allow for enforcing the minimum Mapnik version
|
||||
- XML: Added parameter to <Map> called `minimum_version` to allow for enforcing the minimum Mapnik version
|
||||
needed for XML features used in the mapfiles. Uses Major.Minor.Point syntax, for example
|
||||
<Map minimum_version="0.6.1"> would throw an error if the user is running Mapnik less than 0.6.1.
|
||||
|
||||
- XML: Added support for relative paths when using entities and 'mapnik.load_map_from_string()' (#440)
|
||||
- XML: Added support for relative paths when using entities and `mapnik.load_map_from_string()` (#440)
|
||||
|
||||
- XML: Made width and height optional for symbolizers using images (r1543)
|
||||
|
||||
- XML: Ensured that default values for layers are not serialized in save_map() (r1366)
|
||||
|
||||
- XML: Added missing serialization of PointSymbolizer 'opacity' and 'allow_overlap' attributes (r1358)
|
||||
- XML: Added missing serialization of PointSymbolizer `opacity` and `allow_overlap` attributes (r1358)
|
||||
|
||||
- XML: Default text vertical_alignment now dependent on dy (#485, r1527)
|
||||
|
||||
- Python: Exposed ability to write to Cairo formats using 'mapnik.render_to_file()' and without pycairo (#381)
|
||||
- Python: Exposed ability to write to Cairo formats using `mapnik.render_to_file()` and without pycairo (#381)
|
||||
|
||||
- Python: Fixed potential crash if pycairo support is enabled but python-cairo module is missing (#392)
|
||||
|
||||
- Python: Added 'mapnik.has_pycairo()' function to test for pycairo support (r1278) (#284)
|
||||
- Python: Added `mapnik.has_pycairo()` function to test for pycairo support (r1278) (#284)
|
||||
|
||||
- Python: Added 'mapnik.register_plugins()' and 'mapnik.register_fonts()' functions (r1256)
|
||||
- Python: Added `mapnik.register_plugins()` and `mapnik.register_fonts()` functions (r1256)
|
||||
|
||||
- Python: Pickling support for point_symbolizer (r1295) (#345)
|
||||
|
||||
- Python: Ensured mapnik::config_errors now throw RuntimeError exception instead of UserWarning exception (#442)
|
||||
|
||||
- Filters: Added support for '!=' as an alias to '<>' for not-equals filters (avoids <>) (r1326) (#427)
|
||||
- Filters: Added support for `!=` as an alias to `<>` for not-equals filters (avoids <>) (r1326) (#427)
|
||||
|
||||
- SCons: Improved boost auto-detection (r1255,r1279)
|
||||
|
||||
- SCons: Fixed support for JOBS=N and FAST=True to enable faster compiling (r1440)
|
||||
|
||||
- SCons: Ensured that -h or --help will properly print help on custom Mapnik options before a user
|
||||
has been able to properly run 'configure'. (r1514)
|
||||
has been able to properly run `configure`. (r1514)
|
||||
|
||||
- SCons: Added ability to link to custom icu library name using ICU_LIB_NAME (r1414)
|
||||
|
||||
|
@ -345,12 +535,13 @@ For a complete change history, see the SVN log.
|
|||
- Fonts: Added unifont to auto-installed fonts, which is used by the OSM styles as a fallback font (r1328)
|
||||
|
||||
|
||||
# Mapnik 0.6.1
|
||||
|
||||
# Mapnik 0.6.1 Release
|
||||
Released July 14, 2009
|
||||
|
||||
(Packaged from r1247)
|
||||
(Packaged from r1247/353ff576c7)
|
||||
|
||||
- Plugins: expose list of registered plugins as a 'plugin_names()' method of DatasourceCache (r1180)
|
||||
- Plugins: expose list of registered plugins as a `plugin_names()` method of DatasourceCache (r1180)
|
||||
|
||||
- XML: Fixed serialization and parsing bugs related to handling of integers and Enums (#328,#353)
|
||||
|
||||
|
@ -390,13 +581,13 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- Python: Pickling support for raster_symbolizer (r1154) (#345)
|
||||
|
||||
- Python: Added 'mapnik.has_cairo()' function to test for cairo support (r1152) (#284)
|
||||
- Python: Added `mapnik.has_cairo()` function to test for cairo support (r1152) (#284)
|
||||
|
||||
- Python: Exposed dash_array get method (r1151) (#317)
|
||||
|
||||
- Python: Pickling support for Coord objects (#345)
|
||||
|
||||
- GDAL Plugin: Added an experimental option to open files in 'shared mode' (r1143)
|
||||
- GDAL Plugin: Added an experimental option to open files in `shared mode` (r1143)
|
||||
|
||||
- Python: Exposed RasterSymbolizer options in Python (r1139)
|
||||
|
||||
|
@ -408,13 +599,13 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- XML: Ensured relative paths in XML are interpreted relative to XML file location (r1124) (#326)
|
||||
|
||||
- XML: Added ability to serialize all default symbolizer values by passing third argument to save_map(m,'file.xml',True)(r1117) (#327)
|
||||
- XML: Added ability to serialize all default symbolizer values by passing third argument to save_map(m,`file.xml`,True)(r1117) (#327)
|
||||
|
||||
- Core: Added support for alpha transparency when writing to png256 (patch from Marcin Rudowski) (#202)
|
||||
|
||||
- SCons: Ensured ABI compatibility information is embedded in libmapnik.dylib on Mac OS X (#322)
|
||||
|
||||
- SCons: Ensured that the full 'install_name' path would be added to libmapnik.dylib on Mac OS X (#374)
|
||||
- SCons: Ensured that the full `install_name` path would be added to libmapnik.dylib on Mac OS X (#374)
|
||||
|
||||
- Tests: Added testing framework in Python using nose (r1101-r1105)
|
||||
|
||||
|
@ -429,16 +620,17 @@ For a complete change history, see the SVN log.
|
|||
- Plugins: Fixed segfault in OGR Plugin with empty geometries (r1074) (#292)
|
||||
|
||||
|
||||
# Mapnik 0.6.0
|
||||
|
||||
# Mapnik 0.6.0 Release
|
||||
Released April 1, 2009
|
||||
|
||||
(Packaged from r1066)
|
||||
(Packaged from r1066/c88e03436f)
|
||||
|
||||
- Python: Added support for aspect_fix_mode (r1013)
|
||||
|
||||
- OGCServer Fixed axis-ordering for WMS 1.3.0 request (r1051) (#241)
|
||||
|
||||
- Plugins: Added option to all plugins to support using a 'base' path argument (r1042)
|
||||
- Plugins: Added option to all plugins to support using a `base` path argument (r1042)
|
||||
|
||||
- Symbolizers: RasterSymbolizer now support composing modes for hillshading (r1027)
|
||||
|
||||
|
@ -459,7 +651,7 @@ For a complete change history, see the SVN log.
|
|||
- Plugins: PostGIS plugin now accepts multi-line queries (r862)
|
||||
|
||||
- Filter parsing: Allow numbers in the filter field name.
|
||||
This allows for shapefiles with columns like '1970'.
|
||||
This allows for shapefiles with columns like `1970`.
|
||||
|
||||
- Plugins: Added OGR driver for reading all OGR supported formats (kunitoki) (r836) (#170)
|
||||
|
||||
|
@ -481,7 +673,7 @@ For a complete change history, see the SVN log.
|
|||
|
||||
- Core: Transformation is now skipped if srs values match exactly (r777)
|
||||
|
||||
- Symbolizers: 'min_distance' now honored for POINT placement using Text Symbolizer (r771)
|
||||
- Symbolizers: `min_distance` now honored for POINT placement using Text Symbolizer (r771)
|
||||
|
||||
- Plugins: PostGIS plugin now accepts a geometry_field,record_limit, cursor_size options (r769,r872)
|
||||
|
||||
|
@ -522,3 +714,27 @@ For a complete change history, see the SVN log.
|
|||
- Plugins: Use memory mapped files for reading shape file (r628)
|
||||
|
||||
- Core: Use streams to write images (i/o refactor) (r628) (#15)
|
||||
|
||||
# Mapnik 0.5.1
|
||||
|
||||
Released April 15, 2008
|
||||
|
||||
(Packaged from c29cb7386d)
|
||||
|
||||
# Mapnik 0.5.0
|
||||
|
||||
Released April 15, 2008
|
||||
|
||||
(Packaged from 0464a3563c)
|
||||
|
||||
# Mapnik 0.4.0
|
||||
|
||||
Released February 26, 2007
|
||||
|
||||
(Packaged from 8d73e3a8dc)
|
||||
|
||||
# Mapnik 0.3.0
|
||||
|
||||
Released May 22, 2006
|
||||
|
||||
(Packaged from 3ae046ebe2)
|
||||
|
|
145
INSTALL.md
145
INSTALL.md
|
@ -1,84 +1,83 @@
|
|||
# Mapnik Installation
|
||||
|
||||
Mapnik is cross platform and runs on Linux, Mac OSX, Solaris, *BSD, and Windows.
|
||||
|
||||
## Quick Start
|
||||
|
||||
To configure and build mapnik do:
|
||||
To configure and build Mapnik do:
|
||||
|
||||
./configure
|
||||
make
|
||||
|
||||
NOTE: the above will not work on windows, rather see https://github.com/mapnik/mapnik/wiki/BuildingOnWindows
|
||||
|
||||
Then to run the tests locally (without needing to install):
|
||||
|
||||
make test-local
|
||||
|
||||
Install like:
|
||||
|
||||
sudo make install
|
||||
|
||||
If you need to uninstall do:
|
||||
|
||||
sudo make uninstall
|
||||
|
||||
For more details see the 'Building' Section below.
|
||||
For more details see the `Building` Section below.
|
||||
|
||||
Platform specific install guides at http://trac.mapnik.org/wiki/MapnikInstallation
|
||||
Platform specific install guides at https://github.com/mapnik/mapnik/wiki/Mapnik-Installation
|
||||
|
||||
For troubleshooting help see http://trac.mapnik.org/wiki/InstallationTroubleshooting
|
||||
For troubleshooting help see https://github.com/mapnik/mapnik/wiki/InstallationTroubleshooting
|
||||
|
||||
|
||||
## Depends
|
||||
|
||||
Mapnik is cross platform and runs on Linux, Mac OSX, Solaris, *BSD, and Windows.
|
||||
|
||||
The build system should work for all posix/unix systems but for windows see:
|
||||
|
||||
http://trac.mapnik.org/wiki/BuildingOnWindows
|
||||
|
||||
Build dependencies are:
|
||||
Build system dependencies are:
|
||||
|
||||
* C++ compiler (like g++ or clang++)
|
||||
* Python >= 2.4
|
||||
* >= 2 GB RAM
|
||||
* Python 2.4-2.7
|
||||
* Scons (a copy is bundled)
|
||||
|
||||
Mapnik Core depends on:
|
||||
|
||||
* Boost
|
||||
- >= 1.46 is recommended
|
||||
- >= 1.45 is required if compiling with clang++
|
||||
- >= 1.42 works on most systems and most compilers
|
||||
- >= 1.47 is required to support wkt/wkb geometry output (optional)
|
||||
- These libraries are required:
|
||||
- >= 1.47 is required.
|
||||
- These libraries are used:
|
||||
- filesystem
|
||||
- system
|
||||
- thread (if mapnik threadsafe support is required, default on)
|
||||
- regex (optionally built with icu regex support)
|
||||
- program_options (optionally for mapnik command line programs)
|
||||
|
||||
* libicuuc >= 4.0 (ideally >= 4.2) - International Components for Unicode
|
||||
* libpng >= 1.2.x - PNG Graphics
|
||||
* libjpeg - JPEG Graphics
|
||||
* libtiff - TIFF Graphics
|
||||
* libz - Zlib Compression
|
||||
* libfreetype - Freetype2 for Font support (Install requires freetype-config)
|
||||
* libpng >= 1.2.x - PNG graphics
|
||||
* libjpeg - JPEG graphics
|
||||
* libtiff - TIFF graphics
|
||||
* libz - Zlib compression
|
||||
* libfreetype - Freetype2 for font support (Install requires freetype-config)
|
||||
* libxml2 - XML parsing (Install requires xml2-config)
|
||||
* libproj - PROJ.4 Projection library
|
||||
* libproj - PROJ.4 projection library
|
||||
|
||||
Mapnik Python binding depend on:
|
||||
Mapnik Python bindings depend on:
|
||||
|
||||
* Python >= 2.4
|
||||
* Python 2.5-2.7 or >= 3.2
|
||||
* Boost python
|
||||
|
||||
Note: Python3k is supported, see: https://github.com/mapnik/mapnik/wiki/Python3k
|
||||
|
||||
Optional dependencies:
|
||||
|
||||
* Cairo - Graphics library for PDF, PS, and SVG formats
|
||||
* Cairo - Graphics library for output formats like PDF, PS, and SVG
|
||||
- pkg-config - Required for building with cairo support
|
||||
- libsigc++ - C++ support for cairomm
|
||||
- cairomm - C++ bindings for cairo
|
||||
- pycairo - Python bindings for cairo
|
||||
* libpq - PostgreSQL libraries (For PostGIS plugin support)
|
||||
* libgdal - GDAL/OGR input (For gdal and ogr plugin support)
|
||||
* libsqlite3 - SQLite input (needs RTree support) (sqlite plugin support)
|
||||
* libsqlite3 - SQLite input (needs RTree support builtin) (sqlite plugin support)
|
||||
* libocci - Oracle input plugin support
|
||||
* libcurl - OSM input plugin support
|
||||
|
||||
Instructions for installing many of these dependencies on
|
||||
various platforms can be found at the Mapnik Community Wiki
|
||||
(http://trac.mapnik.org/wiki/MapnikInstallation).
|
||||
various platforms can be found at the Mapnik Wiki:
|
||||
|
||||
https://github.com/mapnik/mapnik/wiki/Mapnik-Installation
|
||||
|
||||
|
||||
## Building
|
||||
|
@ -89,6 +88,10 @@ We provide a simple Makefile wrapper that can be used like:
|
|||
|
||||
./configure && make && make install
|
||||
|
||||
For help on what options are accepted do:
|
||||
|
||||
./configure --help
|
||||
|
||||
To interact with the local copy of scons directly you can do:
|
||||
|
||||
python scons/scons.py configure
|
||||
|
@ -101,9 +104,9 @@ If you want to clean your build do:
|
|||
|
||||
make clean
|
||||
|
||||
If you experience odd configure errors, try resetting the SCons caches:
|
||||
If you experience odd configure errors, try cleaning the configure caches:
|
||||
|
||||
make reset
|
||||
make distclean
|
||||
|
||||
To install in a custom location do:
|
||||
|
||||
|
@ -121,72 +124,50 @@ To pass custom paths to a dependency, like icu, do:
|
|||
|
||||
./configure ICU_INCLUDES=/usr/local/include ICU_LIBS=/usr/local/include
|
||||
|
||||
If you want to see configure options do:
|
||||
For more details on usage see:
|
||||
|
||||
./configure --help
|
||||
|
||||
For more details on all the options see:
|
||||
|
||||
http://trac.mapnik.org/wiki/UsingScons
|
||||
https://github.com/mapnik/mapnik/wiki/UsingScons
|
||||
|
||||
|
||||
## Testing Installation
|
||||
|
||||
First, try importing the Mapnik python module in a python interpreter,
|
||||
and make sure it does so without errors:
|
||||
You can run the Mapnik tests locally (without installing) like:
|
||||
|
||||
$ python
|
||||
Python 2.5.1 (r251:54863, Jan 17 2008, 19:35:17)
|
||||
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> import mapnik
|
||||
>>>
|
||||
make test-local # see the Makefile for how this works
|
||||
|
||||
Then, try rendering the demo map, included in the Mapnik source code::
|
||||
Or you can install and test like:
|
||||
|
||||
cd demo/python
|
||||
python rundemo.py
|
||||
make install && make test
|
||||
|
||||
If the resulting maps look good, this indicates the core components of
|
||||
Mapnik are installed properly, as well as the Shapefile plugin, Unicode
|
||||
text support (ICU), and re-projection support using Proj.
|
||||
Many of the tests are written in python and you can run them individually like:
|
||||
|
||||
For further tests see the `tests` folder within the Mapnik source code.
|
||||
make install
|
||||
python tests/python_tests/shapefile_test.py
|
||||
|
||||
|
||||
## Learning Mapnik
|
||||
|
||||
### Users
|
||||
### Help
|
||||
|
||||
Visit http://trac.mapnik.org/wiki/LearningMapnik for basic tutorials on making maps with Mapnik using the Python bindings.
|
||||
Mapnik has an active community of talented users and developers making beautiful maps.
|
||||
|
||||
### Developers
|
||||
If you need help or want to participate starting points include:
|
||||
|
||||
Visit http://trac.mapnik.org/#DevelopersCorner for resources for getting involved with Mapnik development.
|
||||
- Sign up and post to the mailing list: http://mapnik.org/contact/
|
||||
- Join and ask questions on the #mapnik channel on irc://irc.freenode.net/mapnik
|
||||
- Add your help questions to https://github.com/mapnik/mapnik-support
|
||||
|
||||
### Cartographers
|
||||
|
||||
## Mapnik Community
|
||||
TileMill, which uses Mapnik internally, offers great step by step tutorials for
|
||||
learning advanced map styling: http://mapbox.com/tilemill/docs/crashcourse/introduction/
|
||||
|
||||
### Programmers
|
||||
|
||||
Mapnik has an active community of talented users and developers making
|
||||
amazing maps.
|
||||
Mapnik is great for building your own mapping applications. Visit
|
||||
https://github.com/mapnik/mapnik/wiki/LearningMapnik for basic
|
||||
tutorials on how to programmatically use Mapnik.
|
||||
|
||||
If you are looking for further help on installation or usage and you can't
|
||||
find what you are looking for from searching the users list archives
|
||||
(http://lists.berlios.de/pipermail/mapnik-users/) or the trac wiki
|
||||
(http://trac.mapnik.org/), feel free to join the Mapnik community and
|
||||
introduce yourself.
|
||||
### Contributers
|
||||
|
||||
You can get involved by:
|
||||
|
||||
* Subscribing to the mapnik-users list:
|
||||
|
||||
http://lists.berlios.de/mailman/listinfo/mapnik-users
|
||||
|
||||
* Subscribing to the mapnik-developers list:
|
||||
|
||||
http://lists.berlios.de/mailman/listinfo/mapnik-devel
|
||||
|
||||
* Joining the #mapnik channel on irc://irc.freenode.net/mapnik
|
||||
|
||||
* Signing up as a user or contributor at http://www.ohloh.net/p/mapnik/
|
||||
Read docs/contributing.markdown for resources for getting involved with Mapnik development.
|
||||
|
|
68
Makefile
68
Makefile
|
@ -1,31 +1,60 @@
|
|||
UNAME := $(shell uname)
|
||||
LINK_FIX=LD_LIBRARY_PATH
|
||||
ifeq ($(UNAME), Darwin)
|
||||
LINK_FIX=DYLD_LIBRARY_PATH
|
||||
else
|
||||
endif
|
||||
|
||||
all: mapnik
|
||||
|
||||
install:
|
||||
python scons/scons.py install
|
||||
@python scons/scons.py --config=cache --implicit-cache --max-drift=1 install
|
||||
|
||||
mapnik:
|
||||
python scons/scons.py
|
||||
@python scons/scons.py --config=cache --implicit-cache --max-drift=1
|
||||
|
||||
clean:
|
||||
python scons/scons.py -c
|
||||
@python scons/scons.py -c --config=cache --implicit-cache --max-drift=1
|
||||
@if test -e ".sconsign.dblite"; then rm ".sconsign.dblite"; fi
|
||||
@if test -e "config.log"; then rm "config.log"; fi
|
||||
@if test -e ".sconf_temp/"; then rm -r ".sconf_temp/"; fi
|
||||
@find ./ -name "*.os" -exec rm {} \;
|
||||
@find ./ -name "*.o" -exec rm {} \;
|
||||
@find ./ -name "*.pyc" -exec rm {} \;
|
||||
@rm bindings/python/mapnik/paths.py
|
||||
|
||||
reset:
|
||||
if test -e ".sconf_temp/"; then rm -r ".sconf_temp/"; fi
|
||||
if test -e ".sconsign.dblite"; then rm ".sconsign.dblite"; fi
|
||||
if test -e "config.cache"; then rm "config.cache"; fi
|
||||
distclean:
|
||||
@if test -e "config.cache"; then rm "config.cache"; fi
|
||||
if test -e "config.py"; then mv "config.py" "config.py.backup"; fi
|
||||
|
||||
reset: distclean
|
||||
|
||||
rebuild:
|
||||
make uninstall && make clean && time make && make install
|
||||
|
||||
uninstall:
|
||||
python scons/scons.py uninstall
|
||||
@python scons/scons.py --config=cache --implicit-cache --max-drift=1 uninstall
|
||||
|
||||
test:
|
||||
@echo "*** Running visual tests…"
|
||||
@python tests/visual_tests/test.py -q
|
||||
@echo "*** Running C++ tests..."
|
||||
@for FILE in tests/cpp_tests/*-bin; do \
|
||||
$${FILE}; \
|
||||
done
|
||||
@echo "*** Running python tests..."
|
||||
@python tests/run_tests.py -q
|
||||
@ ./run_tests
|
||||
|
||||
test-local:
|
||||
@echo "*** Boostrapping local test environment..."
|
||||
@export ${LINK_FIX}=`pwd`/src:${${LINK_FIX}} && \
|
||||
export PYTHONPATH=`pwd`/bindings/python/:${PYTHONPATH} && \
|
||||
export MAPNIK_FONT_DIRECTORY=`pwd`/fonts/dejavu-fonts-ttf-2.33/ttf/ && \
|
||||
export MAPNIK_INPUT_PLUGINS_DIRECTORY=`pwd`/plugins/input/ && \
|
||||
make test
|
||||
|
||||
bench:
|
||||
@export ${LINK_FIX}=`pwd`/src:${${LINK_FIX}} && \
|
||||
./benchmark/run
|
||||
|
||||
check: test-local
|
||||
|
||||
demo:
|
||||
@echo "*** Running rundemo.cpp…"
|
||||
cd demo/c++; ./rundemo `mapnik-config --prefix`/lib/mapnik
|
||||
|
||||
pep8:
|
||||
# https://gist.github.com/1903033
|
||||
|
@ -38,4 +67,9 @@ grind:
|
|||
valgrind --leak-check=full --log-fd=1 $${FILE} | grep definitely; \
|
||||
done
|
||||
|
||||
.PHONY: clean reset uninstall test install
|
||||
render:
|
||||
@for FILE in tests/data/good_maps/*xml; do \
|
||||
nik2img.py $${FILE} /tmp/$$(basename $${FILE}).png; \
|
||||
done
|
||||
|
||||
.PHONY: install mapnik clean distclean reset uninstall test demo pep8 grind render
|
||||
|
|
18
README.md
18
README.md
|
@ -1,12 +1,14 @@
|
|||
```
|
||||
_/ _/ _/ _/
|
||||
_/_/ _/_/ _/_/_/ _/_/_/ _/_/_/ _/ _/
|
||||
_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/_/
|
||||
_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/
|
||||
_/ _/ _/_/_/ _/_/_/ _/ _/ _/ _/ _/
|
||||
_/
|
||||
_/
|
||||
```
|
||||
_/ _/ _/ _/
|
||||
_/_/ _/_/ _/_/_/ _/_/_/ _/_/_/ _/ _/
|
||||
_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/_/
|
||||
_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/
|
||||
_/ _/ _/_/_/ _/_/_/ _/ _/ _/ _/ _/
|
||||
_/
|
||||
_/
|
||||
```
|
||||
|
||||
[![Build Status](https://secure.travis-ci.org/mapnik/mapnik.png)](http://travis-ci.org/mapnik/mapnik)
|
||||
|
||||
# What is Mapnik?
|
||||
|
||||
|
|
645
SConstruct
645
SConstruct
File diff suppressed because it is too large
Load diff
49
benchmark/allocation.cpp
Normal file
49
benchmark/allocation.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/wkt/wkt_factory.hpp>
|
||||
|
||||
|
||||
#define BOOST_CHRONO_HEADER_ONLY
|
||||
#include <boost/chrono/process_cpu_clocks.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
using namespace boost::chrono;
|
||||
using namespace mapnik;
|
||||
|
||||
void threaded_benchmark(void test(),std::string const& name, unsigned threads) {
|
||||
using namespace boost::chrono;
|
||||
typedef process_cpu_clock clock_type;
|
||||
process_real_cpu_clock::time_point start = process_real_cpu_clock::now();
|
||||
boost::thread_group threads;
|
||||
for (unsigned i=0;i<threads;++i)
|
||||
{
|
||||
threads.create_thread(test);
|
||||
}
|
||||
threads.join_all();
|
||||
clock_type::duration elapsed = process_real_cpu_clock::now() - start;
|
||||
std::clog << boost::chrono::duration_cast<milliseconds>(elapsed)
|
||||
<< " (" << boost::chrono::duration_cast<seconds>(elapsed) << ")"
|
||||
<< " <-- " << name << "\n";
|
||||
}
|
||||
|
||||
|
||||
void test_wkt_creation()
|
||||
{
|
||||
boost::ptr_vector<mapnik::geometry_type> paths;
|
||||
mapnik::wkt_parser parse_wkt;
|
||||
std::string value("GEOMETRYCOLLECTION(MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 45 20, 30 5, 10 10, 10 30, 20 35),(30 20, 20 25, 20 15, 30 20))),POINT(2 3),LINESTRING(2 3,3 4),MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 45 20, 30 5, 10 10, 10 30, 20 35),(30 20, 20 25, 20 15, 30 20))),MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 45 20, 30 5, 10 10, 10 30, 20 35),(30 20, 20 25, 20 15, 30 20))),MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 45 20, 30 5, 10 10, 10 30, 20 35),(30 20, 20 25, 20 15, 30 20))))");
|
||||
if (!parse_wkt.parse(value, paths)) std::clog << "failed to parse\n";
|
||||
int iterations = 10000;
|
||||
typedef process_cpu_clock clock_type;
|
||||
process_real_cpu_clock::time_point start = process_real_cpu_clock::now();
|
||||
for (int i=0;i<iterations;++i) {
|
||||
parse_wkt.parse(value, paths);
|
||||
}
|
||||
clock_type::duration elapsed = process_real_cpu_clock::now() - start;
|
||||
std::clog << "elapsed: " << boost::chrono::duration_cast<milliseconds>(elapsed) << "\n";
|
||||
}
|
||||
|
||||
int main( int, char*[] )
|
||||
{
|
||||
return 0;
|
||||
}
|
22
benchmark/build.py
Normal file
22
benchmark/build.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
import os
|
||||
import glob
|
||||
from copy import copy
|
||||
|
||||
Import ('env')
|
||||
|
||||
test_env = env.Clone()
|
||||
|
||||
test_env['LIBS'] = copy(env['LIBMAPNIK_LIBS'])
|
||||
test_env.AppendUnique(LIBS='mapnik')
|
||||
#test_env.AppendUnique(LIBS='sqlite3')
|
||||
test_env.AppendUnique(CXXFLAGS='-g')
|
||||
|
||||
for cpp_test in glob.glob('run*.cpp'):
|
||||
name = cpp_test.replace('.cpp','')
|
||||
source_files = [cpp_test]
|
||||
test_env_local = test_env.Clone()
|
||||
test_program = test_env_local.Program(name, source=source_files, LINKFLAGS=env['CUSTOM_LDFLAGS'])
|
||||
Depends(test_program, env.subst('../src/%s' % env['MAPNIK_LIB_NAME']))
|
||||
# build locally if installing
|
||||
if 'install' in COMMAND_LINE_TARGETS:
|
||||
env.Alias('install',test_program)
|
BIN
benchmark/data/multicolor-hextree-expected.png
Normal file
BIN
benchmark/data/multicolor-hextree-expected.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
BIN
benchmark/data/multicolor.png
Normal file
BIN
benchmark/data/multicolor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 256 KiB |
315
benchmark/run.cpp
Normal file
315
benchmark/run.cpp
Normal file
|
@ -0,0 +1,315 @@
|
|||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/image_data.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/image_reader.hpp>
|
||||
#include <mapnik/util/conversions.hpp>
|
||||
|
||||
|
||||
// stl
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
|
||||
// boost
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#define BOOST_CHRONO_HEADER_ONLY
|
||||
#include <boost/chrono/process_cpu_clocks.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
using namespace boost::chrono;
|
||||
using namespace mapnik;
|
||||
|
||||
typedef process_cpu_clock clock_type;
|
||||
typedef clock_type::duration dur;
|
||||
|
||||
template <typename T>
|
||||
void benchmark(T test, std::string const& name)
|
||||
{
|
||||
if (!test.validate()) throw std::runtime_error(std::string("test did not validate: ") + name);
|
||||
process_cpu_clock::time_point start;
|
||||
dur elapsed;
|
||||
if (test.threads_ > 0) {
|
||||
boost::thread_group tg;
|
||||
for (unsigned i=0;i<test.threads_;++i)
|
||||
{
|
||||
tg.create_thread(test);
|
||||
}
|
||||
start = process_cpu_clock::now();
|
||||
tg.join_all();
|
||||
elapsed = process_cpu_clock::now() - start;
|
||||
} else {
|
||||
start = process_cpu_clock::now();
|
||||
test();
|
||||
elapsed = process_cpu_clock::now() - start;
|
||||
}
|
||||
std::clog << (test.threads_ ? "threaded -> ": "")
|
||||
<< name << ": "
|
||||
<< boost::chrono::duration_cast<milliseconds>(elapsed) << "\n";
|
||||
}
|
||||
|
||||
bool compare_images(std::string const& src_fn,std::string const& dest_fn)
|
||||
{
|
||||
std::auto_ptr<mapnik::image_reader> reader1(mapnik::get_image_reader(dest_fn,"png"));
|
||||
if (!reader1.get())
|
||||
{
|
||||
throw mapnik::image_reader_exception("Failed to load: " + dest_fn);
|
||||
}
|
||||
boost::shared_ptr<image_32> image_ptr1 = boost::make_shared<image_32>(reader1->width(),reader1->height());
|
||||
reader1->read(0,0,image_ptr1->data());
|
||||
|
||||
std::auto_ptr<mapnik::image_reader> reader2(mapnik::get_image_reader(src_fn,"png"));
|
||||
if (!reader2.get())
|
||||
{
|
||||
throw mapnik::image_reader_exception("Failed to load: " + src_fn);
|
||||
}
|
||||
boost::shared_ptr<image_32> image_ptr2 = boost::make_shared<image_32>(reader2->width(),reader2->height());
|
||||
reader2->read(0,0,image_ptr2->data());
|
||||
|
||||
image_data_32 const& dest = image_ptr1->data();
|
||||
image_data_32 const& src = image_ptr2->data();
|
||||
|
||||
unsigned int width = src.width();
|
||||
unsigned int height = src.height();
|
||||
if ((width != dest.width()) || height != dest.height()) return false;
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
const unsigned int* row_from = src.getRow(y);
|
||||
const unsigned int* row_to = dest.getRow(y);
|
||||
for (unsigned int x = 0; x < width; ++x)
|
||||
{
|
||||
if (row_from[x] != row_to[x]) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct test1
|
||||
{
|
||||
unsigned iter_;
|
||||
unsigned threads_;
|
||||
explicit test1(unsigned iterations, unsigned threads=0) :
|
||||
iter_(iterations),
|
||||
threads_(threads)
|
||||
{}
|
||||
|
||||
bool validate()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
mapnik::image_data_32 im(256,256);
|
||||
std::string out;
|
||||
for (unsigned i=0;i<iter_;++i) {
|
||||
out.clear();
|
||||
out = mapnik::save_to_string(im,"png");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct test2
|
||||
{
|
||||
unsigned iter_;
|
||||
unsigned threads_;
|
||||
boost::shared_ptr<image_32> im_;
|
||||
explicit test2(unsigned iterations, unsigned threads=0) :
|
||||
iter_(iterations),
|
||||
threads_(threads),
|
||||
im_()
|
||||
{
|
||||
std::string filename("./benchmark/data/multicolor.png");
|
||||
std::auto_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(filename,"png"));
|
||||
if (!reader.get())
|
||||
{
|
||||
throw mapnik::image_reader_exception("Failed to load: " + filename);
|
||||
}
|
||||
im_ = boost::make_shared<image_32>(reader->width(),reader->height());
|
||||
reader->read(0,0,im_->data());
|
||||
}
|
||||
|
||||
bool validate()
|
||||
{
|
||||
std::string expected("./benchmark/data/multicolor-hextree-expected.png");
|
||||
std::string actual("./benchmark/data/multicolor-hextree-actual.png");
|
||||
mapnik::save_to_file(im_->data(),actual, "png8:m=h");
|
||||
return compare_images(actual,expected);
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
std::string out;
|
||||
for (unsigned i=0;i<iter_;++i) {
|
||||
out.clear();
|
||||
out = mapnik::save_to_string(im_->data(),"png8:m=h");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct test3
|
||||
{
|
||||
unsigned iter_;
|
||||
unsigned threads_;
|
||||
double val_;
|
||||
explicit test3(unsigned iterations, unsigned threads=0) :
|
||||
iter_(iterations),
|
||||
threads_(threads),
|
||||
val_(-0.123) {}
|
||||
bool validate()
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << val_;
|
||||
return (s.str() == "-0.123");
|
||||
}
|
||||
void operator()()
|
||||
{
|
||||
std::string out;
|
||||
for (unsigned i=0;i<iter_;++i) {
|
||||
std::ostringstream s;
|
||||
s << val_;
|
||||
out = s.str();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct test4
|
||||
{
|
||||
unsigned iter_;
|
||||
unsigned threads_;
|
||||
double val_;
|
||||
explicit test4(unsigned iterations, unsigned threads=0) :
|
||||
iter_(iterations),
|
||||
threads_(threads),
|
||||
val_(-0.123) {}
|
||||
|
||||
bool validate()
|
||||
{
|
||||
std::string s;
|
||||
mapnik::util::to_string(s,val_);
|
||||
return (s == "-0.123");
|
||||
}
|
||||
void operator()()
|
||||
{
|
||||
std::string out;
|
||||
for (unsigned i=0;i<iter_;++i) {
|
||||
out.clear();
|
||||
mapnik::util::to_string(out,val_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct test5
|
||||
{
|
||||
unsigned iter_;
|
||||
unsigned threads_;
|
||||
double val_;
|
||||
explicit test5(unsigned iterations, unsigned threads=0) :
|
||||
iter_(iterations),
|
||||
threads_(threads),
|
||||
val_(-0.123) {}
|
||||
|
||||
bool validate()
|
||||
{
|
||||
std::string s;
|
||||
to_string_impl(s,val_);
|
||||
return (s == "-0.123");
|
||||
}
|
||||
bool to_string_impl(std::string &s , double val)
|
||||
{
|
||||
s.resize(s.capacity());
|
||||
while (true)
|
||||
{
|
||||
size_t n2 = static_cast<size_t>(snprintf(&s[0], s.size()+1, "%g", val_));
|
||||
if (n2 <= s.size())
|
||||
{
|
||||
s.resize(n2);
|
||||
break;
|
||||
}
|
||||
s.resize(n2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void operator()()
|
||||
{
|
||||
std::string out;
|
||||
for (unsigned i=0;i<iter_;++i)
|
||||
{
|
||||
out.clear();
|
||||
to_string_impl(out , val_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main( int, char*[] )
|
||||
{
|
||||
try
|
||||
{
|
||||
std::cout << "starting benchmark…\n";
|
||||
{
|
||||
test1 runner(100);
|
||||
benchmark(runner,"encoding blank image as png");
|
||||
}
|
||||
|
||||
{
|
||||
test2 runner(100);
|
||||
benchmark(runner,"encoding multicolor image as png8:m=h");
|
||||
}
|
||||
|
||||
{
|
||||
test1 runner(10,10);
|
||||
benchmark(runner,"encoding blank image as png");
|
||||
}
|
||||
|
||||
{
|
||||
test2 runner(10,10);
|
||||
benchmark(runner,"encoding multicolor image as png8:m=h");
|
||||
}
|
||||
|
||||
{
|
||||
test3 runner(1000000);
|
||||
benchmark(runner,"double to string conversion with std::ostringstream");
|
||||
}
|
||||
|
||||
{
|
||||
test4 runner(1000000);
|
||||
benchmark(runner,"double to string conversion with mapnik::util_to_string");
|
||||
}
|
||||
|
||||
{
|
||||
test5 runner(1000000);
|
||||
benchmark(runner,"double to string conversion with snprintf");
|
||||
}
|
||||
|
||||
{
|
||||
test3 runner(1000000,10);
|
||||
benchmark(runner,"double to string conversion with std::ostringstream");
|
||||
}
|
||||
|
||||
{
|
||||
test4 runner(1000000,10);
|
||||
benchmark(runner,"double to string conversion with mapnik::util_to_string");
|
||||
}
|
||||
|
||||
{
|
||||
test5 runner(1000000,10);
|
||||
benchmark(runner,"double to string conversion with snprintf");
|
||||
}
|
||||
|
||||
std::cout << "...benchmark done\n";
|
||||
return 0;
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
std::clog << "test error: " << ex.what() << "\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
15
benchmark/utils/random_image.py
Normal file
15
benchmark/utils/random_image.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
import mapnik
|
||||
import random
|
||||
|
||||
im = mapnik.Image(256,256)
|
||||
|
||||
for x in xrange(0,im.width()):
|
||||
for y in xrange(0,im.height()):
|
||||
r = int(random.random() * 255)
|
||||
g = random.random() * 255
|
||||
b = random.random() * 255
|
||||
a = random.random()
|
||||
color = mapnik.Color('rgba(%i,%i,%i,%f)' % (r,g,b,a))
|
||||
im.set_pixel(x,y,color)
|
||||
|
||||
im.save('./benchmark/data/multicolor.png')
|
|
@ -17,7 +17,7 @@
|
|||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
import os, re, sys, glob
|
||||
from subprocess import Popen, PIPE
|
||||
|
@ -43,15 +43,7 @@ prefix = env['PREFIX']
|
|||
target_path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik')
|
||||
target_path_deprecated = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2')
|
||||
|
||||
libraries = ['mapnik']
|
||||
|
||||
if env['BOOST_PYTHON_LIB']:
|
||||
libraries.append(env['BOOST_PYTHON_LIB'])
|
||||
else:
|
||||
if is_py3():
|
||||
libraries.append('boost_python3%s' % env['BOOST_APPEND'])
|
||||
else:
|
||||
libraries.append('boost_python%s' % env['BOOST_APPEND'])
|
||||
libraries = ['mapnik',env['BOOST_PYTHON_LIB']]
|
||||
|
||||
# TODO - do solaris/fedora need direct linking too?
|
||||
if env['PLATFORM'] == 'Darwin':
|
||||
|
@ -73,7 +65,7 @@ if env['PLATFORM'] == 'Darwin':
|
|||
# 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 http://trac.mapnik.org/ticket/453 for the seeds of a better approach
|
||||
# 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
|
||||
|
@ -94,7 +86,7 @@ if env['PLATFORM'] == 'Darwin':
|
|||
# /System/Library/Frameworks/Python.framework/Python/Versions/
|
||||
# or
|
||||
# /Library/Frameworks/Python.framework/Python/Versions/
|
||||
# See: http://trac.mapnik.org/ticket/380
|
||||
# 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])
|
||||
|
@ -143,10 +135,7 @@ paths += "__all__ = [mapniklibpath,inputpluginspath,fontscollectionpath]\n"
|
|||
if not os.path.exists('mapnik'):
|
||||
os.mkdir('mapnik')
|
||||
|
||||
if hasattr(os.path,'relpath'): # python 2.6 and above
|
||||
file('mapnik/paths.py','w').write(paths % (os.path.relpath(env['MAPNIK_LIB_DIR'],target_path)))
|
||||
else:
|
||||
file('mapnik/paths.py','w').write(paths % (env['MAPNIK_LIB_DIR']))
|
||||
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
|
||||
|
@ -154,8 +143,14 @@ try:
|
|||
os.chmod('mapnik/paths.py',0666)
|
||||
except: pass
|
||||
|
||||
# install the core mapnik python files, including '__init__.py'
|
||||
# install the shared object beside the module directory
|
||||
sources = glob.glob('*.cpp')
|
||||
|
||||
py_env = env.Clone()
|
||||
py_env.Append(CPPPATH = env['PYTHON_INCLUDES'])
|
||||
|
||||
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')
|
||||
|
@ -165,8 +160,7 @@ if 'install' in COMMAND_LINE_TARGETS:
|
|||
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'
|
||||
if 'install' in COMMAND_LINE_TARGETS:
|
||||
# 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
|
||||
|
@ -177,22 +171,16 @@ if 'install' in COMMAND_LINE_TARGETS:
|
|||
Chmod("$TARGET", 0644),
|
||||
])
|
||||
|
||||
if 'uninstall' not in COMMAND_LINE_TARGETS:
|
||||
if env['HAS_CAIRO']:
|
||||
py_env.Append(CPPPATH = env['CAIRO_CPPPATHS'])
|
||||
py_env.Append(CXXFLAGS = '-DHAVE_CAIRO')
|
||||
if env['PLATFORM'] == 'Darwin':
|
||||
py_env.Append(LIBS=env['CAIRO_LINKFLAGS'])
|
||||
|
||||
# install the shared object beside the module directory
|
||||
sources = glob.glob('*.cpp')
|
||||
|
||||
py_env = env.Clone()
|
||||
py_env.Append(CPPPATH = env['PYTHON_INCLUDES'])
|
||||
|
||||
if env['HAS_CAIRO']:
|
||||
py_env.Append(CPPPATH = env['CAIROMM_CPPPATHS'])
|
||||
py_env.Append(CXXFLAGS = '-DHAVE_CAIRO')
|
||||
if env['PLATFORM'] == 'Darwin':
|
||||
py_env.Append(LIBS=env['CAIROMM_LINKFLAGS'])
|
||||
|
||||
if env['HAS_PYCAIRO']:
|
||||
py_env.ParseConfig('pkg-config --cflags pycairo')
|
||||
py_env.Append(CXXFLAGS = '-DHAVE_PYCAIRO')
|
||||
if env['HAS_PYCAIRO']:
|
||||
py_env.ParseConfig('pkg-config --cflags pycairo')
|
||||
py_env.Append(CXXFLAGS = '-DHAVE_PYCAIRO')
|
||||
|
||||
libraries.append('boost_thread%s' % env['BOOST_APPEND'])
|
||||
_mapnik = py_env.LoadableModule('mapnik/_mapnik', sources, LIBS=libraries, LDMODULEPREFIX='', LDMODULESUFFIX='.so',LINKFLAGS=linkflags)
|
||||
|
@ -204,7 +192,7 @@ if env['PLATFORM'] == 'SunOS' and env['PYTHON_IS_64BIT']:
|
|||
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)
|
||||
|
|
|
@ -39,12 +39,36 @@ Several things happen when you do:
|
|||
|
||||
"""
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
def bootstrap_env():
|
||||
"""
|
||||
If an optional settings file exists, inherit its
|
||||
environment settings before loading the mapnik library.
|
||||
|
||||
This feature is intended for customized packages of mapnik.
|
||||
|
||||
The settings file should be a python file with an 'env' variable
|
||||
that declares a dictionary of key:value pairs to push into the
|
||||
global process environment, if not already set, like:
|
||||
|
||||
env = {'ICU_DATA':'/usr/local/share/icu/'}
|
||||
"""
|
||||
if os.path.exists(os.path.join(os.path.dirname(__file__),'mapnik_settings.py')):
|
||||
from mapnik_settings import env
|
||||
process_keys = os.environ.keys()
|
||||
for key, value in env.items():
|
||||
if key not in process_keys:
|
||||
os.environ[key] = value
|
||||
|
||||
bootstrap_env()
|
||||
|
||||
from _mapnik import *
|
||||
from paths import inputpluginspath, fontscollectionpath
|
||||
from paths import inputpluginspath
|
||||
from paths import fontscollectionpath
|
||||
|
||||
import printing
|
||||
printing.renderer = render
|
||||
|
@ -67,13 +91,13 @@ class _MapnikMetaclass(BoostPythonMetaclass):
|
|||
_injector = _MapnikMetaclass('_injector', (object, ), {})
|
||||
|
||||
def Filter(*args,**kwargs):
|
||||
warnings.warn("'Filter' is deprecated and will be removed in Mapnik 2.0.1, use 'Expression' instead",
|
||||
warnings.warn("'Filter' is deprecated and will be removed in Mapnik 3.x, use 'Expression' instead",
|
||||
DeprecationWarning, 2)
|
||||
return Expression(*args, **kwargs)
|
||||
|
||||
class Envelope(Box2d):
|
||||
def __init__(self, *args, **kwargs):
|
||||
warnings.warn("'Envelope' is deprecated and will be removed in Mapnik 2.0.1, use 'Box2d' instead",
|
||||
warnings.warn("'Envelope' is deprecated and will be removed in Mapnik 3.x, use 'Box2d' instead",
|
||||
DeprecationWarning, 2)
|
||||
Box2d.__init__(self, *args, **kwargs)
|
||||
|
||||
|
@ -113,18 +137,18 @@ class _Coord(Coord,_injector):
|
|||
|
||||
def forward(self, projection):
|
||||
"""
|
||||
Projects the point from the geographic coordinate
|
||||
space into the cartesian space. The x component is
|
||||
considered to be longitude, the y component the
|
||||
Projects the point from the geographic coordinate
|
||||
space into the cartesian space. The x component is
|
||||
considered to be longitude, the y component the
|
||||
latitude.
|
||||
|
||||
Returns the easting (x) and northing (y) as a
|
||||
Returns the easting (x) and northing (y) as a
|
||||
coordinate pair.
|
||||
|
||||
Example: Project the geographic coordinates of the
|
||||
Example: Project the geographic coordinates of the
|
||||
city center of Stuttgart into the local
|
||||
map projection (GK Zone 3/DHDN, EPSG 31467)
|
||||
>>> p = Projection('+init=epsg:31467')
|
||||
map projection (GK Zone 3/DHDN, EPSG 31467)
|
||||
>>> p = Projection('+init=epsg:31467')
|
||||
>>> Coord(9.1, 48.7).forward(p)
|
||||
Coord(3507360.12813,5395719.2749)
|
||||
"""
|
||||
|
@ -132,19 +156,19 @@ class _Coord(Coord,_injector):
|
|||
|
||||
def inverse(self, projection):
|
||||
"""
|
||||
Projects the point from the cartesian space
|
||||
into the geographic space. The x component is
|
||||
considered to be the easting, the y component
|
||||
Projects the point from the cartesian space
|
||||
into the geographic space. The x component is
|
||||
considered to be the easting, the y component
|
||||
to be the northing.
|
||||
|
||||
Returns the longitude (x) and latitude (y) as a
|
||||
Returns the longitude (x) and latitude (y) as a
|
||||
coordinate pair.
|
||||
|
||||
Example: Project the cartesian coordinates of the
|
||||
Example: Project the cartesian coordinates of the
|
||||
city center of Stuttgart in the local
|
||||
map projection (GK Zone 3/DHDN, EPSG 31467)
|
||||
into geographic coordinates:
|
||||
>>> p = Projection('+init=epsg:31467')
|
||||
>>> p = Projection('+init=epsg:31467')
|
||||
>>> Coord(3507360.12813,5395719.2749).inverse(p)
|
||||
Coord(9.1, 48.7)
|
||||
"""
|
||||
|
@ -152,13 +176,13 @@ class _Coord(Coord,_injector):
|
|||
|
||||
class _Box2d(Box2d,_injector):
|
||||
"""
|
||||
Represents a spatial envelope (i.e. bounding box).
|
||||
Represents a spatial envelope (i.e. bounding box).
|
||||
|
||||
|
||||
Following operators are defined for Box2d:
|
||||
|
||||
Addition:
|
||||
e1 + e2 is equvalent to e1.expand_to_include(e2) but yields
|
||||
e1 + e2 is equvalent to e1.expand_to_include(e2) but yields
|
||||
a new envelope instead of modifying e1
|
||||
|
||||
Subtraction:
|
||||
|
@ -168,7 +192,7 @@ class _Box2d(Box2d,_injector):
|
|||
Multiplication and division change the width and height of the envelope
|
||||
by the given factor without modifying its center..
|
||||
|
||||
That is, e1 * x is equivalent to:
|
||||
That is, e1 * x is equivalent to:
|
||||
e1.width(x * e1.width())
|
||||
e1.height(x * e1.height()),
|
||||
except that a new envelope is created instead of modifying e1.
|
||||
|
@ -184,8 +208,8 @@ class _Box2d(Box2d,_injector):
|
|||
|
||||
def forward(self, projection):
|
||||
"""
|
||||
Projects the envelope from the geographic space
|
||||
into the cartesian space by projecting its corner
|
||||
Projects the envelope from the geographic space
|
||||
into the cartesian space by projecting its corner
|
||||
points.
|
||||
|
||||
See also:
|
||||
|
@ -195,8 +219,8 @@ class _Box2d(Box2d,_injector):
|
|||
|
||||
def inverse(self, projection):
|
||||
"""
|
||||
Projects the envelope from the cartesian space
|
||||
into the geographic space by projecting its corner
|
||||
Projects the envelope from the cartesian space
|
||||
into the geographic space by projecting its corner
|
||||
points.
|
||||
|
||||
See also:
|
||||
|
@ -211,7 +235,7 @@ class _Projection(Projection,_injector):
|
|||
|
||||
def forward(self,obj):
|
||||
"""
|
||||
Projects the given object (Box2d or Coord)
|
||||
Projects the given object (Box2d or Coord)
|
||||
from the geographic space into the cartesian space.
|
||||
|
||||
See also:
|
||||
|
@ -222,7 +246,7 @@ class _Projection(Projection,_injector):
|
|||
|
||||
def inverse(self,obj):
|
||||
"""
|
||||
Projects the given object (Box2d or Coord)
|
||||
Projects the given object (Box2d or Coord)
|
||||
from the cartesian space into the geographic space.
|
||||
|
||||
See also:
|
||||
|
@ -308,7 +332,7 @@ def Shapefile(**keywords):
|
|||
encoding -- file encoding (default 'utf-8')
|
||||
|
||||
>>> from mapnik import Shapefile, Layer
|
||||
>>> shp = Shapefile(base='/home/mapnik/data',file='world_borders')
|
||||
>>> shp = Shapefile(base='/home/mapnik/data',file='world_borders')
|
||||
>>> lyr = Layer('Shapefile Layer')
|
||||
>>> lyr.datasource = shp
|
||||
|
||||
|
@ -323,7 +347,7 @@ def PostGIS(**keywords):
|
|||
dbname -- database name to connect to
|
||||
table -- table name or subselect query
|
||||
|
||||
*Note: if using subselects for the 'table' value consider also
|
||||
*Note: if using subselects for the 'table' value consider also
|
||||
passing the 'geometry_field' and 'srid' and 'extent_from_subquery'
|
||||
options and/or specifying the 'geometry_table' option.
|
||||
|
||||
|
@ -382,7 +406,7 @@ def Raster(**keywords):
|
|||
tile_stride -- if an image is in tiles, what's the increment between rows/cols (default 1)
|
||||
|
||||
>>> from mapnik import Raster, Layer
|
||||
>>> raster = Raster(base='/home/mapnik/data',file='elevation.tif',lox=-122.8,loy=48.5,hix=-122.7,hiy=48.6)
|
||||
>>> raster = Raster(base='/home/mapnik/data',file='elevation.tif',lox=-122.8,loy=48.5,hix=-122.7,hiy=48.6)
|
||||
>>> lyr = Layer('Tiff Layer')
|
||||
>>> lyr.datasource = raster
|
||||
|
||||
|
@ -456,7 +480,7 @@ def Ogr(**keywords):
|
|||
encoding -- file encoding (default 'utf-8')
|
||||
|
||||
>>> from mapnik import Ogr, Layer
|
||||
>>> datasource = Ogr(base='/home/mapnik/data',file='rivers.geojson',layer='OGRGeoJSON')
|
||||
>>> datasource = Ogr(base='/home/mapnik/data',file='rivers.geojson',layer='OGRGeoJSON')
|
||||
>>> lyr = Layer('OGR Layer from GeoJSON file')
|
||||
>>> lyr.datasource = datasource
|
||||
|
||||
|
@ -484,7 +508,7 @@ def SQLite(**keywords):
|
|||
use_spatial_index -- boolean, instruct sqlite plugin to use Rtree spatial index (default True)
|
||||
|
||||
>>> from mapnik import SQLite, Layer
|
||||
>>> sqlite = SQLite(base='/home/mapnik/data',file='osm.db',table='osm',extent='-20037508,-19929239,20037508,19929239')
|
||||
>>> sqlite = SQLite(base='/home/mapnik/data',file='osm.db',table='osm',extent='-20037508,-19929239,20037508,19929239')
|
||||
>>> lyr = Layer('SQLite Layer')
|
||||
>>> lyr.datasource = sqlite
|
||||
|
||||
|
@ -504,7 +528,7 @@ def Rasterlite(**keywords):
|
|||
extent -- manually specified data extent (comma delimited string, default None)
|
||||
|
||||
>>> from mapnik import Rasterlite, Layer
|
||||
>>> rasterlite = Rasterlite(base='/home/mapnik/data',file='osm.db',table='osm',extent='-20037508,-19929239,20037508,19929239')
|
||||
>>> rasterlite = Rasterlite(base='/home/mapnik/data',file='osm.db',table='osm',extent='-20037508,-19929239,20037508,19929239')
|
||||
>>> lyr = Layer('Rasterlite Layer')
|
||||
>>> lyr.datasource = rasterlite
|
||||
|
||||
|
@ -524,7 +548,7 @@ def Osm(**keywords):
|
|||
bbox -- data bounding box for fetching data (default None)
|
||||
|
||||
>>> from mapnik import Osm, Layer
|
||||
>>> datasource = Osm(file='test.osm')
|
||||
>>> datasource = Osm(file='test.osm')
|
||||
>>> lyr = Layer('Osm Layer')
|
||||
>>> lyr.datasource = datasource
|
||||
|
||||
|
@ -546,7 +570,7 @@ def Kismet(**keywords):
|
|||
extent -- manually specified data extent (comma delimited string, default None)
|
||||
|
||||
>>> from mapnik import Kismet, Layer
|
||||
>>> datasource = Kismet(host='localhost',port=2501,extent='-179,-85,179,85')
|
||||
>>> datasource = Kismet(host='localhost',port=2501,extent='-179,-85,179,85')
|
||||
>>> lyr = Layer('Kismet Server Layer')
|
||||
>>> lyr.datasource = datasource
|
||||
|
||||
|
@ -564,7 +588,7 @@ def Geos(**keywords):
|
|||
extent -- manually specified data extent (comma delimited string, default None)
|
||||
|
||||
>>> from mapnik import Geos, Layer
|
||||
>>> datasource = Geos(wkt='MULTIPOINT(100 100, 50 50, 0 0)')
|
||||
>>> datasource = Geos(wkt='MULTIPOINT(100 100, 50 50, 0 0)')
|
||||
>>> lyr = Layer('GEOS Layer from WKT string')
|
||||
>>> lyr.datasource = datasource
|
||||
|
||||
|
@ -572,18 +596,423 @@ def Geos(**keywords):
|
|||
keywords['type'] = 'geos'
|
||||
return CreateDatasource(keywords)
|
||||
|
||||
def Python(**keywords):
|
||||
"""Create a Python Datasource.
|
||||
|
||||
>>> from mapnik import Python, PythonDatasource
|
||||
>>> datasource = Python('PythonDataSource')
|
||||
>>> lyr = Layer('Python datasource')
|
||||
>>> lyr.datasource = datasource
|
||||
"""
|
||||
keywords['type'] = 'python'
|
||||
return CreateDatasource(keywords)
|
||||
|
||||
class PythonDatasource(object):
|
||||
"""A base class for a Python data source.
|
||||
|
||||
Optional arguments:
|
||||
envelope -- a mapnik.Box2d (minx, miny, maxx, maxy) envelope of the data source, default (-180,-90,180,90)
|
||||
geometry_type -- one of the DataGeometryType enumeration values, default Point
|
||||
data_type -- one of the DataType enumerations, default Vector
|
||||
"""
|
||||
def __init__(self, envelope=None, geometry_type=None, data_type=None):
|
||||
self.envelope = envelope or Box2d(-180, -90, 180, 90)
|
||||
self.geometry_type = geometry_type or DataGeometryType.Point
|
||||
self.data_type = data_type or DataType.Vector
|
||||
|
||||
def features(self, query):
|
||||
"""Return an iterable which yields instances of Feature for features within the passed query.
|
||||
|
||||
Required arguments:
|
||||
query -- a Query instance specifying the region for which features should be returned
|
||||
"""
|
||||
return None
|
||||
|
||||
def features_at_point(self, point):
|
||||
"""Rarely uses. Return an iterable which yields instances of Feature for the specified point."""
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def wkb_features(cls, keys, features):
|
||||
"""A convenience function to wrap an iterator yielding pairs of WKB format geometry and dictionaries of
|
||||
key-value pairs into mapnik features. Return this from PythonDatasource.features() passing it a sequence of keys
|
||||
to appear in the output and an iterator yielding features.
|
||||
|
||||
For example. One might have a features() method in a derived class like the following:
|
||||
|
||||
def features(self, query):
|
||||
# ... create WKB features feat1 and feat2
|
||||
|
||||
return mapnik.PythonDatasource.wkb_features(
|
||||
keys = ( 'name', 'author' ),
|
||||
features = [
|
||||
(feat1, { 'name': 'feat1', 'author': 'alice' }),
|
||||
(feat2, { 'name': 'feat2', 'author': 'bob' }),
|
||||
]
|
||||
)
|
||||
|
||||
"""
|
||||
ctx = Context()
|
||||
[ctx.push(x) for x in keys]
|
||||
|
||||
def make_it(feat, idx):
|
||||
f = Feature(ctx, idx)
|
||||
geom, attrs = feat
|
||||
f.add_geometries_from_wkb(geom)
|
||||
for k, v in attrs.iteritems():
|
||||
f[k] = v
|
||||
return f
|
||||
|
||||
return itertools.imap(make_it, features, itertools.count(1))
|
||||
|
||||
@classmethod
|
||||
def wkt_features(cls, keys, features):
|
||||
"""A convenience function to wrap an iterator yielding pairs of WKT format geometry and dictionaries of
|
||||
key-value pairs into mapnik features. Return this from PythonDatasource.features() passing it a sequence of keys
|
||||
to appear in the output and an iterator yielding features.
|
||||
|
||||
For example. One might have a features() method in a derived class like the following:
|
||||
|
||||
def features(self, query):
|
||||
# ... create WKT features feat1 and feat2
|
||||
|
||||
return mapnik.PythonDatasource.wkt_features(
|
||||
keys = ( 'name', 'author' ),
|
||||
features = [
|
||||
(feat1, { 'name': 'feat1', 'author': 'alice' }),
|
||||
(feat2, { 'name': 'feat2', 'author': 'bob' }),
|
||||
]
|
||||
)
|
||||
|
||||
"""
|
||||
ctx = Context()
|
||||
[ctx.push(x) for x in keys]
|
||||
|
||||
def make_it(feat, idx):
|
||||
f = Feature(ctx, idx)
|
||||
geom, attrs = feat
|
||||
f.add_geometries_from_wkt(geom)
|
||||
for k, v in attrs.iteritems():
|
||||
f[k] = v
|
||||
return f
|
||||
|
||||
return itertools.imap(make_it, features, itertools.count(1))
|
||||
|
||||
class _TextSymbolizer(TextSymbolizer,_injector):
|
||||
@property
|
||||
def name(self):
|
||||
if isinstance(self.properties.format_tree, FormattingText):
|
||||
return self.properties.format_tree.text
|
||||
else:
|
||||
# There is no single expression which could be returned as name
|
||||
raise RuntimeError("TextSymbolizer uses complex formatting features, but old compatibility interface is used to access it. Use self.properties.format_tree instead.")
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
self.properties.format_tree = FormattingText(name)
|
||||
|
||||
@property
|
||||
def text_size(self):
|
||||
return self.format.text_size
|
||||
|
||||
@text_size.setter
|
||||
def text_size(self, text_size):
|
||||
self.format.text_size = text_size
|
||||
|
||||
@property
|
||||
def face_name(self):
|
||||
return self.format.face_name
|
||||
|
||||
@face_name.setter
|
||||
def face_name(self, face_name):
|
||||
self.format.face_name = face_name
|
||||
|
||||
|
||||
@property
|
||||
def fontset(self):
|
||||
return self.format.fontset
|
||||
|
||||
@fontset.setter
|
||||
def fontset(self, fontset):
|
||||
self.format.fontset = fontset
|
||||
|
||||
|
||||
@property
|
||||
def character_spacing(self):
|
||||
return self.format.character_spacing
|
||||
|
||||
@character_spacing.setter
|
||||
def character_spacing(self, character_spacing):
|
||||
self.format.character_spacing = character_spacing
|
||||
|
||||
|
||||
@property
|
||||
def line_spacing(self):
|
||||
return self.format.line_spacing
|
||||
|
||||
@line_spacing.setter
|
||||
def line_spacing(self, line_spacing):
|
||||
self.format.line_spacing = line_spacing
|
||||
|
||||
|
||||
@property
|
||||
def text_opacity(self):
|
||||
return self.format.text_opacity
|
||||
|
||||
@text_opacity.setter
|
||||
def text_opacity(self, text_opacity):
|
||||
self.format.text_opacity = text_opacity
|
||||
|
||||
|
||||
@property
|
||||
def wrap_char(self):
|
||||
return self.format.wrap_char
|
||||
|
||||
@wrap_char.setter
|
||||
def wrap_char(self, wrap_char):
|
||||
self.format.wrap_char = wrap_char
|
||||
|
||||
|
||||
@property
|
||||
def wrap_character(self):
|
||||
return self.format.wrap_character
|
||||
|
||||
@wrap_char.setter
|
||||
def wrap_character(self, wrap_character):
|
||||
self.format.wrap_character = wrap_character
|
||||
|
||||
|
||||
@property
|
||||
def wrap_before(self):
|
||||
return self.format.wrap_before
|
||||
|
||||
@wrap_before.setter
|
||||
def wrap_before(self, wrap_before):
|
||||
self.format.wrap_before = wrap_before
|
||||
|
||||
|
||||
@property
|
||||
def text_transform(self):
|
||||
return self.format.text_transform
|
||||
|
||||
@text_transform.setter
|
||||
def text_transform(self, text_transform):
|
||||
self.format.text_transform = text_transform
|
||||
|
||||
|
||||
@property
|
||||
def fill(self):
|
||||
return self.format.fill
|
||||
|
||||
@fill.setter
|
||||
def fill(self, fill):
|
||||
self.format.fill = fill
|
||||
|
||||
|
||||
@property
|
||||
def halo_fill(self):
|
||||
return self.format.halo_fill
|
||||
|
||||
@halo_fill.setter
|
||||
def halo_fill(self, halo_fill):
|
||||
self.format.halo_fill = halo_fill
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def halo_radius(self):
|
||||
return self.format.halo_radius
|
||||
|
||||
@halo_radius.setter
|
||||
def halo_radius(self, halo_radius):
|
||||
self.format.halo_radius = halo_radius
|
||||
|
||||
|
||||
@property
|
||||
def label_placement(self):
|
||||
return self.properties.label_placement
|
||||
|
||||
@label_placement.setter
|
||||
def label_placement(self, label_placement):
|
||||
self.properties.label_placement = label_placement
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def horizontal_alignment(self):
|
||||
return self.properties.horizontal_alignment
|
||||
|
||||
@horizontal_alignment.setter
|
||||
def horizontal_alignment(self, horizontal_alignment):
|
||||
self.properties.horizontal_alignment = horizontal_alignment
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def justify_alignment(self):
|
||||
return self.properties.justify_alignment
|
||||
|
||||
@justify_alignment.setter
|
||||
def justify_alignment(self, justify_alignment):
|
||||
self.properties.justify_alignment = justify_alignment
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def vertical_alignment(self):
|
||||
return self.properties.vertical_alignment
|
||||
|
||||
@vertical_alignment.setter
|
||||
def vertical_alignment(self, vertical_alignment):
|
||||
self.properties.vertical_alignment = vertical_alignment
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def orientation(self):
|
||||
return self.properties.orientation
|
||||
|
||||
@orientation.setter
|
||||
def orientation(self, orientation):
|
||||
self.properties.orientation = orientation
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def displacement(self):
|
||||
return self.properties.displacement
|
||||
|
||||
@displacement.setter
|
||||
def displacement(self, displacement):
|
||||
self.properties.displacement = displacement
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def label_spacing(self):
|
||||
return self.properties.label_spacing
|
||||
|
||||
@label_spacing.setter
|
||||
def label_spacing(self, label_spacing):
|
||||
self.properties.label_spacing = label_spacing
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def label_position_tolerance(self):
|
||||
return self.properties.label_position_tolerance
|
||||
|
||||
@label_position_tolerance.setter
|
||||
def label_position_tolerance(self, label_position_tolerance):
|
||||
self.properties.label_position_tolerance = label_position_tolerance
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def avoid_edges(self):
|
||||
return self.properties.avoid_edges
|
||||
|
||||
@avoid_edges.setter
|
||||
def avoid_edges(self, avoid_edges):
|
||||
self.properties.avoid_edges = avoid_edges
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def minimum_distance(self):
|
||||
return self.properties.minimum_distance
|
||||
|
||||
@minimum_distance.setter
|
||||
def minimum_distance(self, minimum_distance):
|
||||
self.properties.minimum_distance = minimum_distance
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def minimum_padding(self):
|
||||
return self.properties.minimum_padding
|
||||
|
||||
@minimum_padding.setter
|
||||
def minimum_padding(self, minimum_padding):
|
||||
self.properties.minimum_padding = minimum_padding
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def minimum_path_length(self):
|
||||
return self.properties.minimum_path_length
|
||||
|
||||
@minimum_path_length.setter
|
||||
def minimum_path_length(self, minimum_path_length):
|
||||
self.properties.minimum_path_length = minimum_path_length
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def maximum_angle_char_delta(self):
|
||||
return self.properties.maximum_angle_char_delta
|
||||
|
||||
@maximum_angle_char_delta.setter
|
||||
def maximum_angle_char_delta(self, maximum_angle_char_delta):
|
||||
self.properties.maximum_angle_char_delta = maximum_angle_char_delta
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def force_odd_labels(self):
|
||||
return self.properties.force_odd_labels
|
||||
|
||||
@force_odd_labels.setter
|
||||
def force_odd_labels(self, force_odd_labels):
|
||||
self.properties.force_odd_labels = force_odd_labels
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def allow_overlap(self):
|
||||
return self.properties.allow_overlap
|
||||
|
||||
@allow_overlap.setter
|
||||
def allow_overlap(self, allow_overlap):
|
||||
self.properties.allow_overlap = allow_overlap
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def text_ratio(self):
|
||||
return self.properties.text_ratio
|
||||
|
||||
@text_ratio.setter
|
||||
def text_ratio(self, text_ratio):
|
||||
self.properties.text_ratio = text_ratio
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def wrap_width(self):
|
||||
return self.properties.wrap_width
|
||||
|
||||
@wrap_width.setter
|
||||
def wrap_width(self, wrap_width):
|
||||
self.properties.wrap_width = wrap_width
|
||||
|
||||
|
||||
def mapnik_version_from_string(version_string):
|
||||
"""Return the Mapnik version from a string."""
|
||||
n = version_string.split('.')
|
||||
return (int(n[0]) * 100000) + (int(n[1]) * 100) + (int(n[2]));
|
||||
|
||||
def register_plugins(path=inputpluginspath):
|
||||
def register_plugins(path=None):
|
||||
"""Register plugins located by specified path"""
|
||||
DatasourceCache.instance().register_datasources(path)
|
||||
|
||||
# TODO - recurse
|
||||
def register_fonts(path=fontscollectionpath,valid_extensions=['.ttf','.otf','.ttc','.pfa','.pfb','.ttc','.dfont']):
|
||||
def register_fonts(path=None,valid_extensions=['.ttf','.otf','.ttc','.pfa','.pfb','.ttc','.dfont']):
|
||||
"""Recursively register fonts using path argument as base directory"""
|
||||
if not path:
|
||||
if os.environ.has_key('MAPNIK_FONT_DIRECTORY'):
|
||||
path = os.environ.get('MAPNIK_FONT_DIRECTORY')
|
||||
else:
|
||||
path = fontscollectionpath
|
||||
for dirpath, _, filenames in os.walk(path):
|
||||
for filename in filenames:
|
||||
if os.path.splitext(filename.lower())[1] in valid_extensions:
|
||||
|
|
52
bindings/python/mapnik_building_symbolizer.cpp
Normal file
52
bindings/python/mapnik_building_symbolizer.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2012 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 <boost/python.hpp>
|
||||
#include <mapnik/value.hpp>
|
||||
#include <mapnik/attribute.hpp>
|
||||
#include <mapnik/building_symbolizer.hpp>
|
||||
|
||||
using namespace mapnik;
|
||||
using mapnik::building_symbolizer;
|
||||
using mapnik::color;
|
||||
|
||||
void export_building_symbolizer()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
class_<building_symbolizer>("BuildingSymbolizer",
|
||||
init<>("Default BuildingSymbolizer"))
|
||||
.add_property("fill",make_function
|
||||
(&building_symbolizer::get_fill,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
&building_symbolizer::set_fill)
|
||||
.add_property("fill_opacity",
|
||||
&building_symbolizer::get_opacity,
|
||||
&building_symbolizer::set_opacity)
|
||||
.add_property("height",
|
||||
make_function(&building_symbolizer::height,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
&building_symbolizer::set_height,
|
||||
"Set/get the building height")
|
||||
;
|
||||
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/detail/api_placeholder.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
// stl
|
||||
#include <sstream>
|
||||
|
@ -30,6 +31,8 @@
|
|||
|
||||
// mapnik
|
||||
#include <mapnik/box2d.hpp>
|
||||
#include <mapnik/coord.hpp>
|
||||
#include <mapnik/query.hpp>
|
||||
#include <mapnik/datasource.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
#include <mapnik/feature_layer_desc.hpp>
|
||||
|
@ -47,24 +50,15 @@ namespace
|
|||
using namespace boost::python;
|
||||
boost::shared_ptr<mapnik::datasource> create_datasource(const dict& d)
|
||||
{
|
||||
bool bind=true;
|
||||
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 (key == "bind")
|
||||
{
|
||||
bind = extract<bool>(obj)();
|
||||
continue;
|
||||
}
|
||||
|
||||
extract<std::string> ex0(obj);
|
||||
extract<int> ex1(obj);
|
||||
extract<mapnik::value_integer> ex1(obj);
|
||||
extract<double> ex2(obj);
|
||||
|
||||
if (ex0.check())
|
||||
{
|
||||
params[key] = ex0();
|
||||
|
@ -79,7 +73,7 @@ boost::shared_ptr<mapnik::datasource> create_datasource(const dict& d)
|
|||
}
|
||||
}
|
||||
|
||||
return mapnik::datasource_cache::create(params, bind);
|
||||
return mapnik::datasource_cache::instance().create(params);
|
||||
}
|
||||
|
||||
boost::python::dict describe(boost::shared_ptr<mapnik::datasource> const& ds)
|
||||
|
@ -167,10 +161,9 @@ void export_datasource()
|
|||
.def("describe",&describe)
|
||||
.def("envelope",&datasource::envelope)
|
||||
.def("features",&datasource::features)
|
||||
.def("bind",&datasource::bind)
|
||||
.def("fields",&fields)
|
||||
.def("field_types",&field_types)
|
||||
.def("features_at_point",&datasource::features_at_point)
|
||||
.def("features_at_point",&datasource::features_at_point, (arg("coord"),arg("tolerance")=0))
|
||||
.def("params",&datasource::params,return_value_policy<copy_const_reference>(),
|
||||
"The configuration parameters of the data source. "
|
||||
"These vary depending on the type of data source.")
|
||||
|
|
|
@ -21,27 +21,72 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace boost::python;
|
||||
|
||||
boost::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;
|
||||
using mapnik::singleton;
|
||||
using mapnik::CreateStatic;
|
||||
using namespace boost::python;
|
||||
class_<singleton<datasource_cache,CreateStatic>,boost::noncopyable>("Singleton",no_init)
|
||||
.def("instance",&singleton<datasource_cache,CreateStatic>::instance,
|
||||
return_value_policy<reference_existing_object>())
|
||||
.staticmethod("instance")
|
||||
;
|
||||
|
||||
class_<datasource_cache,bases<singleton<datasource_cache,CreateStatic> >,
|
||||
boost::noncopyable>("DatasourceCache",no_init)
|
||||
.def("create",&datasource_cache::create)
|
||||
class_<datasource_cache,
|
||||
boost::noncopyable>("DatasourceCache",no_init)
|
||||
.def("create",&create_datasource)
|
||||
.staticmethod("create")
|
||||
.def("register_datasources",&datasource_cache::register_datasources)
|
||||
.def("register_datasources",®ister_datasources)
|
||||
.staticmethod("register_datasources")
|
||||
.def("plugin_names",&datasource_cache::plugin_names)
|
||||
.def("plugin_names",&plugin_names)
|
||||
.staticmethod("plugin_names")
|
||||
.def("plugin_directories",&plugin_directories)
|
||||
.staticmethod("plugin_directories")
|
||||
;
|
||||
}
|
||||
|
|
|
@ -86,6 +86,9 @@ void (box2d<double>::*re_center_p2)(coord<double,2> const& ) = &box2d<double>::r
|
|||
// 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 memo)
|
||||
{
|
||||
|
@ -160,13 +163,20 @@ void export_envelope()
|
|||
"\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"
|
||||
">>> c = Box2d(-50, -50, 50, 50)\n"
|
||||
">>> e.clip(c)\n"
|
||||
">>> e\n"
|
||||
"Box2d(10.0, 10.0, 110.0, 110.0)\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")),
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/feature.hpp>
|
||||
|
@ -46,12 +48,22 @@ expression_ptr parse_expression_(std::string const& wkt)
|
|||
return parse_expression(wkt,"utf8");
|
||||
}
|
||||
|
||||
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 const& f)
|
||||
{
|
||||
// will be auto-converted to proper python type by `mapnik_value_to_python`
|
||||
return boost::apply_visitor(mapnik::evaluate<mapnik::Feature,mapnik::value>(f),expr);
|
||||
}
|
||||
|
||||
bool expression_evaluate_to_bool_(mapnik::expr_node const& expr, mapnik::Feature const& f)
|
||||
{
|
||||
return boost::apply_visitor(mapnik::evaluate<mapnik::Feature,mapnik::value>(f),expr).to_bool();
|
||||
}
|
||||
|
||||
// path expression
|
||||
path_expression_ptr parse_path_(std::string const& path)
|
||||
{
|
||||
|
@ -75,7 +87,8 @@ void export_expression()
|
|||
"TODO"
|
||||
"",no_init)
|
||||
.def("evaluate", &expression_evaluate_)
|
||||
.def("__str__",&to_expression_string);
|
||||
.def("to_bool", &expression_evaluate_to_bool_)
|
||||
.def("__str__",&expression_to_string_);
|
||||
;
|
||||
|
||||
def("Expression",&parse_expression_,(arg("expr")),"Expression string");
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include <boost/python/tuple.hpp>
|
||||
#include <boost/python/to_python_converter.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/feature.hpp>
|
||||
|
@ -156,18 +158,53 @@ struct UnicodeString_from_python_str
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
using mapnik::Feature;
|
||||
|
||||
// Python to mapnik::value converters
|
||||
implicitly_convertible<int,mapnik::value>();
|
||||
implicitly_convertible<double,mapnik::value>();
|
||||
implicitly_convertible<UnicodeString,mapnik::value>();
|
||||
implicitly_convertible<bool,mapnik::value>();
|
||||
// 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/
|
||||
UnicodeString_from_python_str();
|
||||
value_null_from_python();
|
||||
|
||||
class_<context_type,context_ptr,boost::noncopyable>
|
||||
("Context",init<>("Default ctor."))
|
||||
|
@ -175,7 +212,7 @@ void export_feature()
|
|||
;
|
||||
|
||||
class_<Feature,boost::shared_ptr<Feature>,
|
||||
boost::noncopyable>("Feature",init<context_ptr,int>("Default ctor."))
|
||||
boost::noncopyable>("Feature",init<context_ptr,mapnik::value_integer>("Default ctor."))
|
||||
.def("id",&Feature::id)
|
||||
.def("__str__",&Feature::to_string)
|
||||
.def("add_geometries_from_wkb", &feature_add_geometries_from_wkb)
|
||||
|
@ -188,6 +225,7 @@ void export_feature()
|
|||
.def("has_key", &Feature::has_key)
|
||||
.add_property("attributes",&attributes)
|
||||
.def("__setitem__",&__setitem__)
|
||||
.def("__contains__",&__getitem__)
|
||||
.def("__getitem__",&__getitem__)
|
||||
.def("__getitem__",&__getitem2__)
|
||||
.def("__len__", &Feature::size)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/feature.hpp>
|
||||
|
@ -49,13 +50,14 @@ inline object pass_through(object const& o) { return o; }
|
|||
|
||||
inline mapnik::feature_ptr next(mapnik::featureset_ptr const& itr)
|
||||
{
|
||||
if (!itr)
|
||||
mapnik::feature_ptr f = itr->next();
|
||||
if (!f)
|
||||
{
|
||||
PyErr_SetString(PyExc_StopIteration, "No more features.");
|
||||
boost::python::throw_error_already_set();
|
||||
}
|
||||
|
||||
return itr->next();
|
||||
return f;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
|
||||
void export_font_engine()
|
||||
|
|
|
@ -30,21 +30,16 @@
|
|||
|
||||
using mapnik::font_set;
|
||||
|
||||
struct fontset_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const font_set& fs)
|
||||
{
|
||||
return boost::python::make_tuple(fs.get_name());
|
||||
}
|
||||
};
|
||||
|
||||
void export_fontset ()
|
||||
{
|
||||
using namespace boost::python;
|
||||
class_<font_set>("FontSet", init<>("default fontset constructor")
|
||||
class_<font_set>("FontSet", init<std::string const&>("default fontset constructor")
|
||||
)
|
||||
.def_pickle(fontset_pickle_suite())
|
||||
.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"
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
//$Id$
|
||||
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
|
|
@ -26,17 +26,21 @@
|
|||
#include <boost/python/iterator.hpp>
|
||||
#include <boost/ptr_container/ptr_vector.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/geometry.hpp>
|
||||
#include <mapnik/wkt/wkt_factory.hpp>
|
||||
#include <mapnik/wkb.hpp>
|
||||
#include <mapnik/json/geometry_parser.hpp>
|
||||
#include <mapnik/json/geojson_generator.hpp>
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION >= 104700
|
||||
#include <mapnik/util/geometry_to_wkb.hpp>
|
||||
#include <mapnik/util/geometry_to_wkt.hpp>
|
||||
#include <mapnik/util/geometry_to_svg.hpp>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
@ -48,7 +52,7 @@ typedef boost::ptr_vector<geometry_type> path_type;
|
|||
|
||||
geometry_type const& getitem_impl(path_type & p, int key)
|
||||
{
|
||||
if (key >=0 && key < p.size())
|
||||
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();
|
||||
|
@ -56,30 +60,65 @@ geometry_type const& getitem_impl(path_type & p, int key)
|
|||
|
||||
void add_wkt_impl(path_type& p, std::string const& wkt)
|
||||
{
|
||||
bool result = mapnik::from_wkt(wkt , p);
|
||||
if (!result) throw std::runtime_error("Failed to parse WKT");
|
||||
if (!mapnik::from_wkt(wkt , p))
|
||||
throw std::runtime_error("Failed to parse WKT");
|
||||
}
|
||||
|
||||
void add_wkb_impl(path_type& p, std::string const& wkb)
|
||||
{
|
||||
mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size());
|
||||
if (!mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size()))
|
||||
throw std::runtime_error("Failed to parse WKB");
|
||||
}
|
||||
|
||||
void add_geojson_impl(path_type& p, std::string const& json)
|
||||
{
|
||||
if (!mapnik::json::from_geojson(json, p))
|
||||
throw std::runtime_error("Failed to parse geojson geometry");
|
||||
}
|
||||
|
||||
boost::shared_ptr<path_type> from_wkt_impl(std::string const& wkt)
|
||||
{
|
||||
boost::shared_ptr<path_type> paths = boost::make_shared<path_type>();
|
||||
bool result = mapnik::from_wkt(wkt, *paths);
|
||||
if (!result) throw std::runtime_error("Failed to parse WKT");
|
||||
if (!mapnik::from_wkt(wkt, *paths))
|
||||
throw std::runtime_error("Failed to parse WKT");
|
||||
return paths;
|
||||
}
|
||||
|
||||
boost::shared_ptr<path_type> from_wkb_impl(std::string const& wkb)
|
||||
{
|
||||
boost::shared_ptr<path_type> paths = boost::make_shared<path_type>();
|
||||
mapnik::geometry_utils::from_wkb(*paths, wkb.c_str(), wkb.size());
|
||||
if (!mapnik::geometry_utils::from_wkb(*paths, wkb.c_str(), wkb.size()))
|
||||
throw std::runtime_error("Failed to parse WKB");
|
||||
return paths;
|
||||
}
|
||||
|
||||
boost::shared_ptr<path_type> from_geojson_impl(std::string const& json)
|
||||
{
|
||||
boost::shared_ptr<path_type> paths = boost::make_shared<path_type>();
|
||||
if (! mapnik::json::from_geojson(json, *paths))
|
||||
throw std::runtime_error("Failed to parse geojson geometry");
|
||||
return paths;
|
||||
}
|
||||
|
||||
mapnik::box2d<double> envelope_impl(path_type & p)
|
||||
{
|
||||
mapnik::box2d<double> b;
|
||||
bool first = true;
|
||||
BOOST_FOREACH(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()
|
||||
|
@ -93,13 +132,20 @@ inline std::string boost_version()
|
|||
PyObject* to_wkb( geometry_type const& geom, mapnik::util::wkbByteOrder byte_order)
|
||||
{
|
||||
mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(geom,byte_order);
|
||||
return
|
||||
if (wkb)
|
||||
{
|
||||
return
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
::PyBytes_FromStringAndSize
|
||||
::PyBytes_FromStringAndSize
|
||||
#else
|
||||
::PyString_FromStringAndSize
|
||||
::PyString_FromStringAndSize
|
||||
#endif
|
||||
((const char*)wkb->buffer(),wkb->size());
|
||||
((const char*)wkb->buffer(),wkb->size());
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
PyObject* to_wkb( geometry_type const& geom)
|
||||
|
@ -114,13 +160,20 @@ PyObject* to_wkb( geometry_type const& geom)
|
|||
PyObject* to_wkb2( path_type const& p, mapnik::util::wkbByteOrder byte_order)
|
||||
{
|
||||
mapnik::util::wkb_buffer_ptr wkb = mapnik::util::to_wkb(p,byte_order);
|
||||
return
|
||||
if (wkb)
|
||||
{
|
||||
return
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
::PyBytes_FromStringAndSize
|
||||
::PyBytes_FromStringAndSize
|
||||
#else
|
||||
::PyString_FromStringAndSize
|
||||
::PyString_FromStringAndSize
|
||||
#endif
|
||||
((const char*)wkb->buffer(),wkb->size());
|
||||
((const char*)wkb->buffer(),wkb->size());
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
PyObject* to_wkb2( path_type const& p)
|
||||
|
@ -174,6 +227,41 @@ std::string to_geojson( path_type const& geom)
|
|||
return json;
|
||||
}
|
||||
|
||||
std::string to_svg( geometry_type const& geom)
|
||||
{
|
||||
#if BOOST_VERSION >= 104700
|
||||
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;
|
||||
#else
|
||||
throw std::runtime_error("mapnik::to_wkt() requires at least boost 1.47 while your build was compiled against boost "
|
||||
+ boost_version());
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
// https://github.com/mapnik/mapnik/issues/1437
|
||||
std::string to_svg2( path_type const& geom)
|
||||
{
|
||||
#if BOOST_VERSION >= 104700
|
||||
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;
|
||||
#else
|
||||
throw std::runtime_error("mapnik::to_svg() requires at least boost 1.47 while your build was compiled against boost "
|
||||
+ boost_version());
|
||||
#endif
|
||||
}*/
|
||||
|
||||
|
||||
void export_geometry()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -198,21 +286,27 @@ void export_geometry()
|
|||
.def("type",&geometry_type::type)
|
||||
.def("to_wkb",&to_wkb)
|
||||
.def("to_wkt",&to_wkt)
|
||||
.def("to_svg",&to_svg)
|
||||
// TODO add other geometry_type methods
|
||||
;
|
||||
|
||||
class_<path_type, boost::shared_ptr<path_type>, boost::noncopyable>("Path")
|
||||
.def("__getitem__", getitem_impl,return_value_policy<reference_existing_object>())
|
||||
.def("__len__", &path_type::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_geojson)
|
||||
.staticmethod("from_wkt")
|
||||
.staticmethod("from_wkb")
|
||||
.staticmethod("from_geojson")
|
||||
;
|
||||
|
||||
}
|
||||
|
|
|
@ -32,13 +32,25 @@
|
|||
using namespace boost::python;
|
||||
|
||||
// help compiler see template definitions
|
||||
static dict (*encode)( mapnik::grid const&, std::string, bool, unsigned int) = mapnik::grid_encode;
|
||||
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,boost::shared_ptr<mapnik::grid> >(
|
||||
|
@ -52,6 +64,8 @@ void export_grid()
|
|||
.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"
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
using namespace boost::python;
|
||||
|
||||
// help compiler see template definitions
|
||||
static dict (*encode)( mapnik::grid_view const&, std::string, bool, unsigned int) = mapnik::grid_encode;
|
||||
static dict (*encode)( mapnik::grid_view const&, std::string const& , bool, unsigned int) = mapnik::grid_encode;
|
||||
|
||||
void export_grid_view()
|
||||
{
|
||||
|
|
|
@ -39,9 +39,6 @@ extern "C"
|
|||
#include <mapnik/image_reader.hpp>
|
||||
#include <mapnik/image_compositing.hpp>
|
||||
|
||||
// stl
|
||||
#include <sstream>
|
||||
|
||||
// jpeg
|
||||
#if defined(HAVE_JPEG)
|
||||
#include <mapnik/jpeg_io.hpp>
|
||||
|
@ -49,7 +46,7 @@ extern "C"
|
|||
|
||||
// cairo
|
||||
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
|
||||
#include <cairomm/surface.h>
|
||||
#include <mapnik/cairo_context.hpp>
|
||||
#include <pycairo.h>
|
||||
#endif
|
||||
|
||||
|
@ -121,6 +118,18 @@ bool painted(mapnik::image_32 const& im)
|
|||
return im.painted();
|
||||
}
|
||||
|
||||
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_32 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());
|
||||
|
@ -149,17 +158,16 @@ void blend (image_32 & im, unsigned x, unsigned y, image_32 const& im2, float op
|
|||
im.set_rectangle_alpha2(im2.data(),x,y,opacity);
|
||||
}
|
||||
|
||||
|
||||
void composite(image_32 & im, image_32 & im2, mapnik::composite_mode_e mode)
|
||||
void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity)
|
||||
{
|
||||
mapnik::composite(im.data(),im2.data(),mode);
|
||||
mapnik::composite(dst.data(),src.data(),mode,opacity,0,0,false);
|
||||
}
|
||||
|
||||
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
|
||||
boost::shared_ptr<image_32> from_cairo(PycairoSurface* surface)
|
||||
boost::shared_ptr<image_32> from_cairo(PycairoSurface* py_surface)
|
||||
{
|
||||
Cairo::RefPtr<Cairo::ImageSurface> s(new Cairo::ImageSurface(surface->surface));
|
||||
boost::shared_ptr<image_32> image_ptr = boost::make_shared<image_32>(s);
|
||||
mapnik::cairo_surface_ptr surface(py_surface->surface, mapnik::cairo_surface_closer());
|
||||
boost::shared_ptr<image_32> image_ptr = boost::make_shared<image_32>(surface);
|
||||
return image_ptr;
|
||||
}
|
||||
#endif
|
||||
|
@ -167,6 +175,7 @@ boost::shared_ptr<image_32> from_cairo(PycairoSurface* surface)
|
|||
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)
|
||||
|
@ -195,7 +204,12 @@ void export_image()
|
|||
.value("exclusion", mapnik::exclusion)
|
||||
.value("contrast", mapnik::contrast)
|
||||
.value("invert", mapnik::invert)
|
||||
.value("invert_rgb", mapnik::invert_rgb)
|
||||
.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)
|
||||
;
|
||||
|
||||
class_<image_32,boost::shared_ptr<image_32> >("Image","This class represents a 32 bit RGBA image.",init<int,int>())
|
||||
|
@ -210,8 +224,17 @@ void export_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)
|
||||
.def("composite",&composite,
|
||||
( arg("self"),
|
||||
arg("image"),
|
||||
arg("mode")=mapnik::src_over,
|
||||
arg("opacity")=1.0f
|
||||
))
|
||||
.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)
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2011 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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/module.hpp>
|
||||
#include <boost/python/def.hpp>
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/metawriter_inmem.hpp>
|
||||
|
||||
using mapnik::metawriter_inmem;
|
||||
using mapnik::metawriter_inmem_ptr;
|
||||
|
||||
namespace {
|
||||
std::map<std::string, mapnik::value>::const_iterator
|
||||
mapnik_value_map_begin(const std::map<std::string, mapnik::value> &m) {
|
||||
return m.begin();
|
||||
}
|
||||
|
||||
std::map<std::string, mapnik::value>::const_iterator
|
||||
mapnik_value_map_end(const std::map<std::string, mapnik::value> &m) {
|
||||
return m.end();
|
||||
}
|
||||
}
|
||||
|
||||
void export_inmem_metawriter() {
|
||||
using namespace boost::python;
|
||||
|
||||
class_<std::map<std::string, mapnik::value> >
|
||||
("MapnikProperties", "Retarded.", init<>())
|
||||
.def("__iter__", range(&mapnik_value_map_begin, &mapnik_value_map_end))
|
||||
;
|
||||
|
||||
class_<metawriter_inmem::meta_instance>
|
||||
("MetaInstance", "Single rendered instance of meta-information.", no_init)
|
||||
.def_readonly("box", &metawriter_inmem::meta_instance::box)
|
||||
.def_readonly("properties", &metawriter_inmem::meta_instance::properties)
|
||||
;
|
||||
|
||||
class_<metawriter_inmem, metawriter_inmem_ptr, boost::noncopyable>
|
||||
("MetaWriterInMem",
|
||||
"Collects meta-information about elements rendered.",
|
||||
no_init)
|
||||
.def("__iter__", range(&metawriter_inmem::inst_begin,
|
||||
&metawriter_inmem::inst_end))
|
||||
;
|
||||
}
|
|
@ -24,6 +24,8 @@
|
|||
#include <boost/python/module.hpp>
|
||||
#include <boost/python/def.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
||||
#include <mapnik/label_collision_detector.hpp>
|
||||
#include <mapnik/map.hpp>
|
||||
|
|
|
@ -77,7 +77,7 @@ struct layer_pickle_suite : boost::python::pickle_suite
|
|||
l.set_queryable(extract<bool>(state[3]));
|
||||
|
||||
mapnik::parameters params = extract<parameters>(state[4]);
|
||||
l.set_datasource(datasource_cache::instance()->create(params));
|
||||
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)
|
||||
|
@ -91,6 +91,43 @@ struct layer_pickle_suite : boost::python::pickle_suite
|
|||
|
||||
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)
|
||||
{
|
||||
return PyInt_FromLong(*buffer_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
void export_layer()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -149,7 +186,7 @@ void export_layer()
|
|||
.add_property("active",
|
||||
&layer::active,
|
||||
&layer::set_active,
|
||||
"Get/Set whether this layer is active and will be rendered.\n"
|
||||
"Get/Set whether this layer is active and will be rendered (same as status property).\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> from mapnik import Layer\n"
|
||||
|
@ -161,6 +198,21 @@ void export_layer()
|
|||
"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,
|
||||
|
@ -196,6 +248,28 @@ void export_layer()
|
|||
"<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,
|
||||
|
@ -271,6 +345,14 @@ void export_layer()
|
|||
">>> lyr.srs = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +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"
|
||||
|
|
|
@ -37,7 +37,7 @@ using mapnik::parse_path;
|
|||
namespace {
|
||||
using namespace boost::python;
|
||||
|
||||
const std::string get_filename(line_pattern_symbolizer const& t)
|
||||
std::string get_filename(line_pattern_symbolizer const& t)
|
||||
{
|
||||
return path_processor_type::to_string(*t.get_filename());
|
||||
}
|
||||
|
@ -49,17 +49,6 @@ void set_filename(line_pattern_symbolizer & t, std::string const& file_expr)
|
|||
|
||||
}
|
||||
|
||||
struct line_pattern_symbolizer_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const line_pattern_symbolizer& l)
|
||||
{
|
||||
std::string filename = path_processor_type::to_string(*l.get_filename());
|
||||
// FIXME : Do we need "type" parameter at all ?
|
||||
return boost::python::make_tuple(filename, guess_type(filename));
|
||||
}
|
||||
};
|
||||
|
||||
void export_line_pattern_symbolizer()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -67,12 +56,23 @@ void export_line_pattern_symbolizer()
|
|||
class_<line_pattern_symbolizer>("LinePatternSymbolizer",
|
||||
init<path_expression_ptr>
|
||||
("<image file expression>"))
|
||||
//.def_pickle(line_pattern_symbolizer_pickle_suite())
|
||||
.add_property("transform",
|
||||
mapnik::get_svg_transform<line_pattern_symbolizer>,
|
||||
mapnik::set_svg_transform<line_pattern_symbolizer>)
|
||||
.add_property("filename",
|
||||
&get_filename,
|
||||
&set_filename)
|
||||
.add_property("comp_op",
|
||||
&line_pattern_symbolizer::comp_op,
|
||||
&line_pattern_symbolizer::set_comp_op,
|
||||
"Set/get the comp-op")
|
||||
.add_property("clip",
|
||||
&line_pattern_symbolizer::clip,
|
||||
&line_pattern_symbolizer::set_clip,
|
||||
"Set/get the line pattern geometry's clipping status")
|
||||
.add_property("smooth",
|
||||
&line_pattern_symbolizer::smooth,
|
||||
&line_pattern_symbolizer::set_smooth,
|
||||
"smooth value (0..1.0)")
|
||||
;
|
||||
}
|
||||
|
|
|
@ -29,38 +29,41 @@ using mapnik::line_symbolizer;
|
|||
using mapnik::stroke;
|
||||
using mapnik::color;
|
||||
|
||||
struct line_symbolizer_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const line_symbolizer& l)
|
||||
{
|
||||
return boost::python::make_tuple(l.get_stroke());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void export_line_symbolizer()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
enumeration_<line_rasterizer_e>("line_rasterizer")
|
||||
.value("FULL",RASTERIZER_FULL)
|
||||
.value("FAST",RASTERIZER_FAST)
|
||||
;
|
||||
|
||||
class_<line_symbolizer>("LineSymbolizer",
|
||||
init<>("Default LineSymbolizer - 1px solid black"))
|
||||
.def(init<stroke const&>("TODO"))
|
||||
.def(init<color const& ,float>())
|
||||
.def_pickle(line_symbolizer_pickle_suite())
|
||||
.add_property("rasterizer",
|
||||
&line_symbolizer::get_rasterizer,
|
||||
&line_symbolizer::set_rasterizer,
|
||||
"Set/get the rasterization method of the line of the point")
|
||||
.add_property("stroke",make_function
|
||||
(&line_symbolizer::get_stroke,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
return_value_policy<reference_existing_object>()),
|
||||
&line_symbolizer::set_stroke)
|
||||
.add_property("simplify_tolerance",
|
||||
&line_symbolizer::simplify_tolerance,
|
||||
&line_symbolizer::set_simplify_tolerance,
|
||||
"simplification tolerance measure")
|
||||
.add_property("offset",
|
||||
&line_symbolizer::offset,
|
||||
&line_symbolizer::set_offset,
|
||||
"offset value")
|
||||
.add_property("comp_op",
|
||||
&line_symbolizer::comp_op,
|
||||
&line_symbolizer::set_comp_op,
|
||||
"Set/get the comp-op")
|
||||
.add_property("clip",
|
||||
&line_symbolizer::clip,
|
||||
&line_symbolizer::set_clip,
|
||||
"Set/get the line geometry's clipping status")
|
||||
.add_property("smooth",
|
||||
&line_symbolizer::smooth,
|
||||
&line_symbolizer::set_smooth,
|
||||
|
|
|
@ -21,113 +21,53 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <mapnik/debug.hpp>
|
||||
|
||||
using mapnik::logger::severity;
|
||||
using mapnik::logger::format;
|
||||
using mapnik::logger::output;
|
||||
|
||||
void set_severity(const severity::type& s)
|
||||
{
|
||||
severity::set(s);
|
||||
}
|
||||
|
||||
severity::type get_severity()
|
||||
{
|
||||
return severity::get();
|
||||
}
|
||||
|
||||
void set_object_severity(const std::string& object_name, const severity::type& s)
|
||||
{
|
||||
severity::set_object(object_name, s);
|
||||
}
|
||||
|
||||
severity::type get_object_severity(const std::string& object_name)
|
||||
{
|
||||
return severity::get_object(object_name);
|
||||
}
|
||||
|
||||
#include <mapnik/utils.hpp>
|
||||
#include "mapnik_enumeration.hpp"
|
||||
|
||||
void export_logger()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
enum_<mapnik::logger::severity::type>("SeverityType")
|
||||
.value("Info", severity::info)
|
||||
.value("Debug", severity::debug)
|
||||
.value("Warn", severity::warn)
|
||||
.value("Error", severity::error)
|
||||
.value("Fatal", severity::fatal)
|
||||
.value("None", severity::none)
|
||||
;
|
||||
|
||||
/*
|
||||
using mapnik::logger;
|
||||
using mapnik::singleton;
|
||||
using mapnik::CreateStatic;
|
||||
using namespace boost::python;
|
||||
|
||||
class_<singleton<severity,CreateStatic>,boost::noncopyable>("Singleton",no_init)
|
||||
.def("instance",&singleton<severity,CreateStatic>::instance,
|
||||
class_<singleton<logger,CreateStatic>,boost::noncopyable>("Singleton",no_init)
|
||||
.def("instance",&singleton<logger,CreateStatic>::instance,
|
||||
return_value_policy<reference_existing_object>())
|
||||
.staticmethod("instance")
|
||||
;
|
||||
|
||||
class_<severity,bases<singleton<severity,CreateStatic> >,
|
||||
boost::noncopyable>("Severity",no_init)
|
||||
.def("get",&severity::get)
|
||||
.def("set",&severity::set)
|
||||
.def("get_object",&severity::get_object)
|
||||
.def("set_object",&severity::set_object)
|
||||
.staticmethod("get")
|
||||
.staticmethod("set")
|
||||
.staticmethod("get_object")
|
||||
.staticmethod("set_object")
|
||||
enum_<mapnik::logger::severity_type>("severity_type")
|
||||
.value("Debug", logger::debug)
|
||||
.value("Warn", logger::warn)
|
||||
.value("Error", logger::error)
|
||||
.value("None", logger::none)
|
||||
;
|
||||
*/
|
||||
|
||||
def("set_severity", &set_severity,
|
||||
"\n"
|
||||
"Set global logger severity.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> from mapnik import SeverityType, set_severity\n"
|
||||
">>> set_severity(SeverityType.None)\n"
|
||||
">>> set_severity(SeverityType.Info)\n"
|
||||
">>> set_severity(SeverityType.Debug)\n"
|
||||
">>> set_severity(SeverityType.Warn)\n"
|
||||
">>> set_severity(SeverityType.Error)\n"
|
||||
">>> set_severity(SeverityType.Fatal)\n"
|
||||
);
|
||||
|
||||
def("get_severity", &get_severity,
|
||||
"\n"
|
||||
"Get global logger severity.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> from mapnik import get_severity\n"
|
||||
">>> get_severity()\n"
|
||||
);
|
||||
|
||||
def("set_object_severity", &set_object_severity,
|
||||
"\n"
|
||||
"Set logger severity for a single object.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> from mapnik import SeverityType, set_object_severity\n"
|
||||
">>> set_object_severity('ogr', SeverityType.None)\n"
|
||||
">>> set_object_severity('gdal', SeverityType.Info)\n"
|
||||
">>> set_object_severity('cairo_renderer', SeverityType.Debug)\n"
|
||||
">>> set_object_severity('agg_renderer', SeverityType.Warn)\n"
|
||||
">>> set_object_severity('bindings', SeverityType.Error)\n"
|
||||
);
|
||||
|
||||
def("get_object_severity", &get_object_severity,
|
||||
"\n"
|
||||
"Get logger severity for a single object.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> from mapnik import get_object_severity"
|
||||
">>> get_object_severity('ogr')\n"
|
||||
);
|
||||
|
||||
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")
|
||||
;
|
||||
}
|
||||
|
|
|
@ -26,11 +26,13 @@
|
|||
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/rule.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/projection.hpp>
|
||||
#include <mapnik/ctrans.hpp>
|
||||
#include <mapnik/feature_type_style.hpp>
|
||||
#include <mapnik/metawriter_inmem.hpp>
|
||||
#include <mapnik/util/deepcopy.hpp>
|
||||
//#include <mapnik/util/deepcopy.hpp>
|
||||
#include "mapnik_enumeration.hpp"
|
||||
|
||||
using mapnik::color;
|
||||
|
@ -39,85 +41,9 @@ using mapnik::box2d;
|
|||
using mapnik::layer;
|
||||
using mapnik::Map;
|
||||
|
||||
struct map_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const Map& m)
|
||||
{
|
||||
return boost::python::make_tuple(m.width(),m.height(),m.srs());
|
||||
}
|
||||
|
||||
static boost::python::tuple
|
||||
getstate(const Map& m)
|
||||
{
|
||||
boost::python::list l;
|
||||
for (unsigned i=0;i<m.layer_count();++i)
|
||||
{
|
||||
l.append(m.getLayer(i));
|
||||
}
|
||||
|
||||
boost::python::list s;
|
||||
Map::const_style_iterator it = m.styles().begin();
|
||||
Map::const_style_iterator end = m.styles().end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
std::string const& name = it->first;
|
||||
const mapnik::feature_type_style & style = it->second;
|
||||
boost::python::tuple style_pair = boost::python::make_tuple(name,style);
|
||||
s.append(style_pair);
|
||||
}
|
||||
|
||||
return boost::python::make_tuple(m.get_current_extent(),m.background(),l,s,m.base_path());
|
||||
}
|
||||
|
||||
static void
|
||||
setstate (Map& m, boost::python::tuple state)
|
||||
{
|
||||
using namespace boost::python;
|
||||
if (len(state) != 5)
|
||||
{
|
||||
PyErr_SetObject(PyExc_ValueError,
|
||||
("expected 5-item tuple in call to __setstate__; got %s"
|
||||
% state).ptr()
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
box2d<double> ext = extract<box2d<double> >(state[0]);
|
||||
m.zoom_to_box(ext);
|
||||
if (state[1])
|
||||
{
|
||||
color bg = extract<color>(state[1]);
|
||||
m.set_background(bg);
|
||||
}
|
||||
|
||||
boost::python::list l=extract<boost::python::list>(state[2]);
|
||||
for (int i=0;i<len(l);++i)
|
||||
{
|
||||
m.addLayer(extract<layer>(l[i]));
|
||||
}
|
||||
|
||||
boost::python::list s=extract<boost::python::list>(state[3]);
|
||||
for (int i=0;i<len(s);++i)
|
||||
{
|
||||
boost::python::tuple style_pair=extract<boost::python::tuple>(s[i]);
|
||||
std::string name = extract<std::string>(style_pair[0]);
|
||||
mapnik::feature_type_style style = extract<mapnik::feature_type_style>(style_pair[1]);
|
||||
m.insert_style(name, style);
|
||||
}
|
||||
|
||||
if (state[4])
|
||||
{
|
||||
std::string base_path = extract<std::string>(state[4]);
|
||||
m.set_base_path(base_path);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
boost::optional<mapnik::box2d<double> > const& (Map::*maximum_extent_const)() const = &Map::maximum_extent;
|
||||
|
||||
mapnik::feature_type_style find_style(mapnik::Map const& m, std::string const& name)
|
||||
{
|
||||
|
@ -141,26 +67,6 @@ mapnik::font_set find_fontset(mapnik::Map const& m, std::string const& name)
|
|||
return *fontset;
|
||||
}
|
||||
|
||||
bool has_metawriter(mapnik::Map const& m)
|
||||
{
|
||||
if (m.metawriters().size() >=1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns empty shared_ptr when the metawriter isn't found, or is
|
||||
// of the wrong type. empty pointers make it back to Python as a None.
|
||||
mapnik::metawriter_inmem_ptr find_inmem_metawriter(const mapnik::Map & m, std::string const& name) {
|
||||
mapnik::metawriter_ptr metawriter = m.find_metawriter(name);
|
||||
mapnik::metawriter_inmem_ptr inmem;
|
||||
|
||||
if (metawriter) {
|
||||
inmem = boost::dynamic_pointer_cast<mapnik::metawriter_inmem>(metawriter);
|
||||
}
|
||||
|
||||
return inmem;
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
@ -184,6 +90,7 @@ mapnik::featureset_ptr query_map_point(mapnik::Map const& m, int index, double x
|
|||
}
|
||||
|
||||
// deepcopy
|
||||
/*
|
||||
mapnik::Map map_deepcopy(mapnik::Map & m, boost::python::dict memo)
|
||||
{
|
||||
// FIXME: ignore memo for now
|
||||
|
@ -191,8 +98,8 @@ mapnik::Map map_deepcopy(mapnik::Map & m, boost::python::dict memo)
|
|||
mapnik::util::deepcopy(m, result);
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO - find a simplier way to set optional to uninitialized
|
||||
void set_maximum_extent(mapnik::Map & m, boost::optional<mapnik::box2d<double> > const& box)
|
||||
{
|
||||
if (box)
|
||||
|
@ -201,7 +108,7 @@ void set_maximum_extent(mapnik::Map & m, boost::optional<mapnik::box2d<double> >
|
|||
}
|
||||
else
|
||||
{
|
||||
m.maximum_extent().reset();
|
||||
m.reset_maximum_extent();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,9 +148,6 @@ void export_map()
|
|||
"'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n"
|
||||
))
|
||||
|
||||
.def_pickle(map_pickle_suite()
|
||||
)
|
||||
|
||||
.def("append_style",&Map::insert_style,
|
||||
(arg("style_name"),arg("style_object")),
|
||||
"Insert a Mapnik Style onto the map by appending it.\n"
|
||||
|
@ -311,15 +215,6 @@ void export_map()
|
|||
"<mapnik._mapnik.Style object at 0x654f0>\n"
|
||||
)
|
||||
|
||||
.def("has_metawriter",
|
||||
has_metawriter,
|
||||
"Check if the Map has any active metawriters\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> m.has_metawriter()\n"
|
||||
"False\n"
|
||||
)
|
||||
|
||||
.def("pan",&Map::pan,
|
||||
(arg("x"),arg("y")),
|
||||
"Set the Map center at a given x,y location\n"
|
||||
|
@ -458,39 +353,8 @@ void export_map()
|
|||
">>> extext = Box2d(-180.0, -90.0, 180.0, 90.0)\n"
|
||||
">>> m.zoom_to_box(extent)\n"
|
||||
)
|
||||
.def("get_metawriter_property", &Map::get_metawriter_property,
|
||||
(arg("name")),
|
||||
"Reads a metawriter property.\n"
|
||||
"These properties are completely user-defined and can be used to"
|
||||
"create filenames, etc.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> map.set_metawriter_property(\"x\", \"10\")\n"
|
||||
">>> map.get_metawriter_property(\"x\")\n"
|
||||
"10\n"
|
||||
)
|
||||
.def("set_metawriter_property", &Map::set_metawriter_property,
|
||||
(arg("name"),arg("value")),
|
||||
"Sets a metawriter property.\n"
|
||||
"These properties are completely user-defined and can be used to"
|
||||
"create filenames, etc.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
">>> map.set_metawriter_property(\"x\", str(x))\n"
|
||||
">>> map.set_metawriter_property(\"y\", str(y))\n"
|
||||
">>> map.set_metawriter_property(\"z\", str(z))\n"
|
||||
"\n"
|
||||
"Use a path like \"[z]/[x]/[y].json\" to create filenames.\n"
|
||||
)
|
||||
.def("find_inmem_metawriter", find_inmem_metawriter,
|
||||
(arg("name")),
|
||||
"Gets an inmem metawriter, or None if no such metawriter "
|
||||
"exists.\n"
|
||||
"Use this after the map has been rendered to retrieve information "
|
||||
"about the hit areas rendered on the map.\n"
|
||||
)
|
||||
|
||||
.def("__deepcopy__",&map_deepcopy)
|
||||
//.def("__deepcopy__",&map_deepcopy)
|
||||
.add_property("parameters",make_function(params_nonconst,return_value_policy<reference_existing_object>()),"TODO")
|
||||
|
||||
.add_property("aspect_fix_mode",
|
||||
|
@ -507,12 +371,30 @@ void export_map()
|
|||
.add_property("background",make_function
|
||||
(&Map::background,return_value_policy<copy_const_reference>()),
|
||||
&Map::set_background,
|
||||
"The background color of the map.\n"
|
||||
"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("base",
|
||||
make_function(&Map::base_path,return_value_policy<copy_const_reference>()),
|
||||
&Map::set_base_path,
|
||||
|
@ -562,7 +444,7 @@ void export_map()
|
|||
)
|
||||
|
||||
.add_property("maximum_extent",make_function
|
||||
(maximum_extent_const,return_value_policy<copy_const_reference>()),
|
||||
(&Map::maximum_extent,return_value_policy<copy_const_reference>()),
|
||||
&set_maximum_extent,
|
||||
"The maximum extent of the map.\n"
|
||||
"\n"
|
||||
|
|
|
@ -23,10 +23,14 @@
|
|||
#include <boost/python.hpp>
|
||||
|
||||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/expression_node.hpp>
|
||||
#include <mapnik/value_error.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/markers_symbolizer.hpp>
|
||||
#include <mapnik/parse_path.hpp>
|
||||
#include "mapnik_svg.hpp"
|
||||
#include "mapnik_enumeration.hpp"
|
||||
#include <mapnik/marker_cache.hpp> // for known_svg_prefix_
|
||||
|
||||
using mapnik::markers_symbolizer;
|
||||
using mapnik::symbolizer_with_image;
|
||||
|
@ -46,57 +50,61 @@ void set_filename(mapnik::markers_symbolizer & symbolizer, std::string const& fi
|
|||
symbolizer.set_filename(parse_path(file_expr));
|
||||
}
|
||||
|
||||
void set_marker_type(mapnik::markers_symbolizer & symbolizer, std::string const& marker_type)
|
||||
{
|
||||
std::string filename;
|
||||
if (marker_type == "ellipse")
|
||||
{
|
||||
filename = mapnik::marker_cache::instance().known_svg_prefix_ + "ellipse";
|
||||
}
|
||||
else if (marker_type == "arrow")
|
||||
{
|
||||
filename = mapnik::marker_cache::instance().known_svg_prefix_ + "arrow";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw mapnik::value_error("Unknown marker-type: '" + marker_type + "'");
|
||||
}
|
||||
symbolizer.set_filename(parse_path(filename));
|
||||
}
|
||||
|
||||
struct markers_symbolizer_pickle_suite : boost::python::pickle_suite
|
||||
}
|
||||
|
||||
|
||||
// https://github.com/mapnik/mapnik/issues/1367
|
||||
PyObject* get_fill_opacity_impl(markers_symbolizer & sym)
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(markers_symbolizer const& p)
|
||||
{
|
||||
std::string filename = path_processor_type::to_string(*p.get_filename());
|
||||
return boost::python::make_tuple(filename,mapnik::guess_type(filename));
|
||||
}
|
||||
|
||||
static boost::python::tuple
|
||||
getstate(markers_symbolizer const& p)
|
||||
{
|
||||
return boost::python::make_tuple(p.get_allow_overlap(),
|
||||
p.get_ignore_placement());//,p.get_opacity());
|
||||
}
|
||||
|
||||
static void
|
||||
setstate (markers_symbolizer& p, boost::python::tuple state)
|
||||
{
|
||||
using namespace boost::python;
|
||||
if (len(state) != 2)
|
||||
{
|
||||
PyErr_SetObject(PyExc_ValueError,
|
||||
("expected 2-item tuple in call to __setstate__; got %s"
|
||||
% state).ptr()
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
p.set_allow_overlap(extract<bool>(state[0]));
|
||||
p.set_ignore_placement(extract<bool>(state[1]));
|
||||
//p.set_opacity(extract<float>(state[2]));
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
boost::optional<float> fill_opacity = sym.get_fill_opacity();
|
||||
if (fill_opacity)
|
||||
return ::PyFloat_FromDouble(*fill_opacity);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
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>("MarkersSymbolizer",
|
||||
init<>("Default Markers Symbolizer - blue arrow"))
|
||||
init<>("Default Markers Symbolizer - circle"))
|
||||
.def (init<mapnik::path_expression_ptr>("<path expression ptr>"))
|
||||
//.def_pickle(markers_symbolizer_pickle_suite())
|
||||
.add_property("filename",
|
||||
&get_filename,
|
||||
&set_filename)
|
||||
.add_property("marker_type",
|
||||
&get_filename,
|
||||
&set_marker_type)
|
||||
.add_property("allow_overlap",
|
||||
&markers_symbolizer::get_allow_overlap,
|
||||
&markers_symbolizer::set_allow_overlap)
|
||||
|
@ -109,7 +117,11 @@ void export_markers_symbolizer()
|
|||
.add_property("opacity",
|
||||
&markers_symbolizer::get_opacity,
|
||||
&markers_symbolizer::set_opacity,
|
||||
"Set/get the text opacity")
|
||||
"Set/get the overall opacity")
|
||||
.add_property("fill_opacity",
|
||||
&get_fill_opacity_impl,
|
||||
&markers_symbolizer::set_fill_opacity,
|
||||
"Set/get the fill opacity")
|
||||
.add_property("ignore_placement",
|
||||
&markers_symbolizer::get_ignore_placement,
|
||||
&markers_symbolizer::set_ignore_placement)
|
||||
|
@ -117,12 +129,42 @@ void export_markers_symbolizer()
|
|||
&mapnik::get_svg_transform<markers_symbolizer>,
|
||||
&mapnik::set_svg_transform<markers_symbolizer>)
|
||||
.add_property("width",
|
||||
&markers_symbolizer::get_width,
|
||||
make_function(&markers_symbolizer::get_width,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
&markers_symbolizer::set_width,
|
||||
"Set/get the marker width")
|
||||
.add_property("height",
|
||||
&markers_symbolizer::get_height,
|
||||
make_function(&markers_symbolizer::get_height,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
&markers_symbolizer::set_height,
|
||||
"Set/get the marker height")
|
||||
.add_property("fill",
|
||||
&markers_symbolizer::get_fill,
|
||||
&markers_symbolizer::set_fill,
|
||||
"Set/get the marker fill color")
|
||||
.add_property("stroke",
|
||||
&markers_symbolizer::get_stroke,
|
||||
&markers_symbolizer::set_stroke,
|
||||
"Set/get the marker stroke (outline)")
|
||||
.add_property("placement",
|
||||
&markers_symbolizer::get_marker_placement,
|
||||
&markers_symbolizer::set_marker_placement,
|
||||
"Set/get the marker placement")
|
||||
.add_property("multi_policy",
|
||||
&markers_symbolizer::get_marker_multi_policy,
|
||||
&markers_symbolizer::set_marker_multi_policy,
|
||||
"Set/get the marker multi geometry rendering policy")
|
||||
.add_property("comp_op",
|
||||
&markers_symbolizer::comp_op,
|
||||
&markers_symbolizer::set_comp_op,
|
||||
"Set/get the marker comp-op")
|
||||
.add_property("clip",
|
||||
&markers_symbolizer::clip,
|
||||
&markers_symbolizer::set_clip,
|
||||
"Set/get the marker geometry's clipping status")
|
||||
.add_property("smooth",
|
||||
&markers_symbolizer::smooth,
|
||||
&markers_symbolizer::set_smooth,
|
||||
"Set/get the marker geometry's smooth value")
|
||||
;
|
||||
}
|
||||
|
|
|
@ -23,11 +23,12 @@
|
|||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
//mapnik
|
||||
#include <mapnik/palette.hpp>
|
||||
|
||||
static boost::shared_ptr<mapnik::rgba_palette> make_palette( const std::string& palette, const std::string& format )
|
||||
static boost::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")
|
||||
|
@ -51,5 +52,8 @@ void export_palette ()
|
|||
// "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"
|
||||
)
|
||||
;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <mapnik/params.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/value.hpp>
|
||||
// stl
|
||||
#include <iterator>
|
||||
|
||||
using mapnik::parameter;
|
||||
using mapnik::parameters;
|
||||
|
@ -78,7 +80,7 @@ struct parameters_pickle_suite : boost::python::pickle_suite
|
|||
std::string key = extract<std::string>(keys[i]);
|
||||
object obj = d[key];
|
||||
extract<std::string> ex0(obj);
|
||||
extract<int> ex1(obj);
|
||||
extract<mapnik::value_integer> ex1(obj);
|
||||
extract<double> ex2(obj);
|
||||
extract<UnicodeString> ex3(obj);
|
||||
|
||||
|
@ -142,17 +144,10 @@ mapnik::parameter get_params_by_index(mapnik::parameters const& p, int index)
|
|||
}
|
||||
|
||||
parameters::const_iterator itr = p.begin();
|
||||
parameters::const_iterator end = p.end();
|
||||
|
||||
int idx = 0;
|
||||
while (itr != end)
|
||||
std::advance(itr, index);
|
||||
if (itr != p.end())
|
||||
{
|
||||
if (idx == index)
|
||||
{
|
||||
return *itr;
|
||||
}
|
||||
++idx;
|
||||
++itr;
|
||||
return *itr;
|
||||
}
|
||||
PyErr_SetString(PyExc_IndexError, "Index is out of range");
|
||||
throw boost::python::error_already_set();
|
||||
|
@ -180,22 +175,24 @@ mapnik::value_holder get_param(mapnik::parameter const& p, int index)
|
|||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<mapnik::parameter> create_parameter_from_string(std::string const& key, std::string const& value)
|
||||
boost::shared_ptr<mapnik::parameter> create_parameter(UnicodeString const& key, mapnik::value_holder const& value)
|
||||
{
|
||||
return boost::make_shared<mapnik::parameter>(key,mapnik::value_holder(value));
|
||||
std::string key_utf8;
|
||||
mapnik::to_utf8(key, key_utf8);
|
||||
return boost::make_shared<mapnik::parameter>(key_utf8,value);
|
||||
}
|
||||
|
||||
boost::shared_ptr<mapnik::parameter> create_parameter_from_int(std::string const& key, int value)
|
||||
{
|
||||
return boost::make_shared<mapnik::parameter>(key,mapnik::value_holder(value));
|
||||
}
|
||||
// needed for Python_Unicode to std::string (utf8) conversion
|
||||
|
||||
boost::shared_ptr<mapnik::parameter> create_parameter_from_float(std::string const& key, double value)
|
||||
boost::shared_ptr<mapnik::parameter> create_parameter_from_string(UnicodeString const& key, UnicodeString const& ustr)
|
||||
{
|
||||
return boost::make_shared<mapnik::parameter>(key,mapnik::value_holder(value));
|
||||
std::string key_utf8;
|
||||
std::string ustr_utf8;
|
||||
mapnik::to_utf8(key, key_utf8);
|
||||
mapnik::to_utf8(ustr,ustr_utf8);
|
||||
return boost::make_shared<mapnik::parameter>(key_utf8, ustr_utf8);
|
||||
}
|
||||
|
||||
|
||||
boost::python::dict to_json(const parameters& p)
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -212,16 +209,19 @@ boost::python::dict to_json(const parameters& p)
|
|||
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,boost::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("__init__", make_constructor(create_parameter_from_int),
|
||||
"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_float),
|
||||
"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)
|
||||
;
|
||||
|
|
|
@ -38,7 +38,7 @@ using mapnik::parse_path;
|
|||
namespace {
|
||||
using namespace boost::python;
|
||||
|
||||
const std::string get_filename(point_symbolizer const& t)
|
||||
std::string get_filename(point_symbolizer const& t)
|
||||
{
|
||||
return path_processor_type::to_string(*t.get_filename());
|
||||
}
|
||||
|
@ -50,47 +50,6 @@ void set_filename(point_symbolizer & t, std::string const& file_expr)
|
|||
|
||||
}
|
||||
|
||||
struct point_symbolizer_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const point_symbolizer& p)
|
||||
{
|
||||
std::string filename = path_processor_type::to_string(*p.get_filename());
|
||||
return boost::python::make_tuple(filename,mapnik::guess_type(filename));
|
||||
}
|
||||
|
||||
static boost::python::tuple
|
||||
getstate(const point_symbolizer& p)
|
||||
{
|
||||
return boost::python::make_tuple(p.get_allow_overlap(),
|
||||
p.get_opacity(),
|
||||
p.get_ignore_placement(),
|
||||
p.get_point_placement());
|
||||
}
|
||||
|
||||
static void
|
||||
setstate (point_symbolizer& p, boost::python::tuple state)
|
||||
{
|
||||
using namespace boost::python;
|
||||
if (len(state) != 4)
|
||||
{
|
||||
PyErr_SetObject(PyExc_ValueError,
|
||||
("expected 4-item tuple in call to __setstate__; got %s"
|
||||
% state).ptr()
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
p.set_allow_overlap(extract<bool>(state[0]));
|
||||
p.set_opacity(extract<float>(state[1]));
|
||||
p.set_ignore_placement(extract<bool>(state[2]));
|
||||
p.set_point_placement(extract<point_placement_e>(state[3]));
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
void export_point_symbolizer()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -103,7 +62,6 @@ void export_point_symbolizer()
|
|||
class_<point_symbolizer>("PointSymbolizer",
|
||||
init<>("Default Point Symbolizer - 4x4 black square"))
|
||||
.def (init<mapnik::path_expression_ptr>("<path expression ptr>"))
|
||||
.def_pickle(point_symbolizer_pickle_suite())
|
||||
.add_property("filename",
|
||||
&get_filename,
|
||||
&set_filename)
|
||||
|
@ -123,5 +81,9 @@ void export_point_symbolizer()
|
|||
.add_property("transform",
|
||||
mapnik::get_svg_transform<point_symbolizer>,
|
||||
mapnik::set_svg_transform<point_symbolizer>)
|
||||
.add_property("comp_op",
|
||||
&point_symbolizer::comp_op,
|
||||
&point_symbolizer::set_comp_op,
|
||||
"Set/get the comp-op")
|
||||
;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ using mapnik::guess_type;
|
|||
namespace {
|
||||
using namespace boost::python;
|
||||
|
||||
const std::string get_filename(polygon_pattern_symbolizer const& t)
|
||||
std::string get_filename(polygon_pattern_symbolizer const& t)
|
||||
{
|
||||
return path_processor_type::to_string(*t.get_filename());
|
||||
}
|
||||
|
@ -49,41 +49,6 @@ void set_filename(polygon_pattern_symbolizer & t, std::string const& file_expr)
|
|||
|
||||
}
|
||||
|
||||
struct polygon_pattern_symbolizer_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const polygon_pattern_symbolizer& p)
|
||||
{
|
||||
std::string filename = path_processor_type::to_string(*p.get_filename());
|
||||
return boost::python::make_tuple(filename,guess_type(filename));
|
||||
}
|
||||
|
||||
static boost::python::tuple
|
||||
getstate(const polygon_pattern_symbolizer& p)
|
||||
{
|
||||
return boost::python::make_tuple(p.get_alignment(),p.get_gamma(),p.get_gamma_method());
|
||||
}
|
||||
|
||||
static void
|
||||
setstate (polygon_pattern_symbolizer& p, boost::python::tuple state)
|
||||
{
|
||||
using namespace boost::python;
|
||||
if (len(state) != 3)
|
||||
{
|
||||
PyErr_SetObject(PyExc_ValueError,
|
||||
("expected 3-item tuple in call to __setstate__; got %s"
|
||||
% state).ptr()
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
p.set_alignment(extract<pattern_alignment_e>(state[0]));
|
||||
p.set_gamma(extract<float>(state[1]));
|
||||
p.set_gamma_method(extract<gamma_method_e>(state[2]));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void export_polygon_pattern_symbolizer()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -95,7 +60,6 @@ void export_polygon_pattern_symbolizer()
|
|||
|
||||
class_<polygon_pattern_symbolizer>("PolygonPatternSymbolizer",
|
||||
init<path_expression_ptr>("<path_expression_ptr>"))
|
||||
.def_pickle(polygon_pattern_symbolizer_pickle_suite())
|
||||
.add_property("alignment",
|
||||
&polygon_pattern_symbolizer::get_alignment,
|
||||
&polygon_pattern_symbolizer::set_alignment,
|
||||
|
@ -106,6 +70,9 @@ void export_polygon_pattern_symbolizer()
|
|||
.add_property("filename",
|
||||
&get_filename,
|
||||
&set_filename)
|
||||
.add_property("opacity",
|
||||
&polygon_pattern_symbolizer::get_opacity,
|
||||
&polygon_pattern_symbolizer::set_opacity)
|
||||
.add_property("gamma",
|
||||
&polygon_pattern_symbolizer::get_gamma,
|
||||
&polygon_pattern_symbolizer::set_gamma)
|
||||
|
@ -113,5 +80,17 @@ void export_polygon_pattern_symbolizer()
|
|||
&polygon_pattern_symbolizer::get_gamma_method,
|
||||
&polygon_pattern_symbolizer::set_gamma_method,
|
||||
"Set/get the gamma correction method of the polygon")
|
||||
.add_property("comp_op",
|
||||
&polygon_pattern_symbolizer::comp_op,
|
||||
&polygon_pattern_symbolizer::set_comp_op,
|
||||
"Set/get the pattern comp-op")
|
||||
.add_property("clip",
|
||||
&polygon_pattern_symbolizer::clip,
|
||||
&polygon_pattern_symbolizer::set_clip,
|
||||
"Set/get the pattern geometry's clipping status")
|
||||
.add_property("smooth",
|
||||
&polygon_pattern_symbolizer::smooth,
|
||||
&polygon_pattern_symbolizer::set_smooth,
|
||||
"Set/get the pattern geometry's smooth value")
|
||||
;
|
||||
}
|
||||
|
|
|
@ -21,47 +21,12 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include "mapnik_enumeration.hpp"
|
||||
#include <mapnik/polygon_symbolizer.hpp>
|
||||
|
||||
using namespace mapnik;
|
||||
using mapnik::polygon_symbolizer;
|
||||
using mapnik::color;
|
||||
|
||||
struct polygon_symbolizer_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const polygon_symbolizer& p)
|
||||
{
|
||||
return boost::python::make_tuple(p.get_fill());
|
||||
}
|
||||
|
||||
static boost::python::tuple
|
||||
getstate(const polygon_symbolizer& p)
|
||||
{
|
||||
return boost::python::make_tuple(p.get_opacity(),p.get_gamma(),p.get_gamma_method());
|
||||
}
|
||||
|
||||
static void
|
||||
setstate (polygon_symbolizer& p, boost::python::tuple state)
|
||||
{
|
||||
using namespace boost::python;
|
||||
if (len(state) != 3)
|
||||
{
|
||||
PyErr_SetObject(PyExc_ValueError,
|
||||
("expected 3-item tuple in call to __setstate__; got %s"
|
||||
% state).ptr()
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
p.set_opacity(extract<float>(state[0]));
|
||||
p.set_gamma(extract<float>(state[1]));
|
||||
p.set_gamma_method(extract<gamma_method_e>(state[2]));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void export_polygon_symbolizer()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -69,7 +34,6 @@ void export_polygon_symbolizer()
|
|||
class_<polygon_symbolizer>("PolygonSymbolizer",
|
||||
init<>("Default PolygonSymbolizer - solid fill grey"))
|
||||
.def(init<color const&>("TODO"))
|
||||
.def_pickle(polygon_symbolizer_pickle_suite())
|
||||
.add_property("fill",make_function
|
||||
(&polygon_symbolizer::get_fill,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
|
@ -84,10 +48,22 @@ void export_polygon_symbolizer()
|
|||
&polygon_symbolizer::get_gamma_method,
|
||||
&polygon_symbolizer::set_gamma_method,
|
||||
"gamma correction method")
|
||||
.add_property("comp_op",
|
||||
&polygon_symbolizer::comp_op,
|
||||
&polygon_symbolizer::set_comp_op,
|
||||
"Set/get the polygon comp-op")
|
||||
.add_property("clip",
|
||||
&polygon_symbolizer::clip,
|
||||
&polygon_symbolizer::set_clip,
|
||||
"Set/get the polygon geometry's clipping status")
|
||||
.add_property("smooth",
|
||||
&polygon_symbolizer::smooth,
|
||||
&polygon_symbolizer::set_smooth,
|
||||
"smooth value (0..1.0)")
|
||||
"Set/get the polygon geometry's smooth value")
|
||||
.add_property("simplify_tolerance",
|
||||
&polygon_symbolizer::simplify_tolerance,
|
||||
&polygon_symbolizer::set_simplify_tolerance,
|
||||
"simplfication tolerance measure")
|
||||
;
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
// mapnik
|
||||
#include <mapnik/proj_transform.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/python.hpp>
|
||||
|
|
|
@ -37,6 +37,7 @@ void export_palette();
|
|||
void export_image();
|
||||
void export_image_view();
|
||||
void export_gamma_method();
|
||||
void export_scaling_method();
|
||||
void export_grid();
|
||||
void export_grid_view();
|
||||
void export_map();
|
||||
|
@ -56,6 +57,7 @@ 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();
|
||||
|
@ -65,18 +67,21 @@ void export_projection();
|
|||
void export_proj_transform();
|
||||
void export_view_transform();
|
||||
void export_raster_colorizer();
|
||||
void export_inmem_metawriter();
|
||||
void export_label_collision_detector();
|
||||
void export_logger();
|
||||
|
||||
#include <mapnik/version.hpp>
|
||||
#include <mapnik/value_error.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#ifdef HAVE_CAIRO
|
||||
#include <mapnik/cairo_renderer.hpp>
|
||||
#endif
|
||||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/stroke.hpp>
|
||||
#include <mapnik/font_set.hpp>
|
||||
#include <mapnik/rule.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/load_map.hpp>
|
||||
#include <mapnik/config_error.hpp>
|
||||
|
@ -88,6 +93,15 @@ void export_logger();
|
|||
#include "mapnik_value_converter.hpp"
|
||||
#include "mapnik_threads.hpp"
|
||||
#include "python_optional.hpp"
|
||||
#include <mapnik/marker_cache.hpp>
|
||||
#include <mapnik/mapped_memory_cache.hpp>
|
||||
|
||||
|
||||
void clear_cache()
|
||||
{
|
||||
mapnik::marker_cache::instance().clear();
|
||||
mapnik::mapped_memory_cache::instance().clear();
|
||||
}
|
||||
|
||||
#include <mapnik/stats_processor.hpp>
|
||||
|
||||
|
@ -159,40 +173,92 @@ void render_layer2(const mapnik::Map& map,
|
|||
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
|
||||
|
||||
void render3(const mapnik::Map& map,
|
||||
PycairoSurface* surface,
|
||||
PycairoSurface* py_surface,
|
||||
double scale_factor = 1.0,
|
||||
unsigned offset_x = 0,
|
||||
unsigned offset_y = 0)
|
||||
{
|
||||
python_unblock_auto_block b;
|
||||
Cairo::RefPtr<Cairo::Surface> s(new Cairo::Surface(surface->surface));
|
||||
mapnik::cairo_renderer<Cairo::Surface> ren(map,s,offset_x, offset_y);
|
||||
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
|
||||
mapnik::cairo_renderer<mapnik::cairo_surface_ptr> ren(map,surface,scale_factor,offset_x,offset_y);
|
||||
ren.apply();
|
||||
}
|
||||
|
||||
void render4(const mapnik::Map& map, PycairoSurface* surface)
|
||||
void render4(const mapnik::Map& map, PycairoSurface* py_surface)
|
||||
{
|
||||
python_unblock_auto_block b;
|
||||
Cairo::RefPtr<Cairo::Surface> s(new Cairo::Surface(surface->surface));
|
||||
mapnik::cairo_renderer<Cairo::Surface> ren(map,s);
|
||||
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
|
||||
mapnik::cairo_renderer<mapnik::cairo_surface_ptr> ren(map,surface);
|
||||
ren.apply();
|
||||
}
|
||||
|
||||
void render5(const mapnik::Map& map,
|
||||
PycairoContext* context,
|
||||
PycairoContext* py_context,
|
||||
double scale_factor = 1.0,
|
||||
unsigned offset_x = 0,
|
||||
unsigned offset_y = 0)
|
||||
{
|
||||
python_unblock_auto_block b;
|
||||
Cairo::RefPtr<Cairo::Context> c(new Cairo::Context(context->ctx));
|
||||
mapnik::cairo_renderer<Cairo::Context> ren(map,c,offset_x, offset_y);
|
||||
mapnik::cairo_ptr context(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(const mapnik::Map& map, PycairoContext* context)
|
||||
void render6(const mapnik::Map& map, PycairoContext* py_context)
|
||||
{
|
||||
python_unblock_auto_block b;
|
||||
Cairo::RefPtr<Cairo::Context> c(new Cairo::Context(context->ctx));
|
||||
mapnik::cairo_renderer<Cairo::Context> ren(map,c);
|
||||
mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer());
|
||||
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context);
|
||||
ren.apply();
|
||||
}
|
||||
|
||||
void render_with_detector2(
|
||||
const mapnik::Map& map,
|
||||
PycairoContext* py_context,
|
||||
boost::shared_ptr<mapnik::label_collision_detector4> detector)
|
||||
{
|
||||
python_unblock_auto_block b;
|
||||
mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer());
|
||||
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context,detector);
|
||||
ren.apply();
|
||||
}
|
||||
|
||||
void render_with_detector3(
|
||||
const mapnik::Map& map,
|
||||
PycairoContext* py_context,
|
||||
boost::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(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(
|
||||
const mapnik::Map& map,
|
||||
PycairoSurface* py_surface,
|
||||
boost::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_surface_ptr> ren(map, surface, detector);
|
||||
ren.apply();
|
||||
}
|
||||
|
||||
void render_with_detector5(
|
||||
const mapnik::Map& map,
|
||||
PycairoSurface* py_surface,
|
||||
boost::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_surface_ptr> ren(map, surface, detector, scale_factor, offset_x, offset_y);
|
||||
ren.apply();
|
||||
}
|
||||
|
||||
|
@ -202,8 +268,8 @@ void render6(const mapnik::Map& map, PycairoContext* context)
|
|||
void render_tile_to_file(const mapnik::Map& map,
|
||||
unsigned offset_x, unsigned offset_y,
|
||||
unsigned width, unsigned height,
|
||||
const std::string& file,
|
||||
const std::string& format)
|
||||
std::string const& file,
|
||||
std::string const& format)
|
||||
{
|
||||
mapnik::image_32 image(width,height);
|
||||
render(map,image,1.0,offset_x, offset_y);
|
||||
|
@ -211,13 +277,13 @@ void render_tile_to_file(const mapnik::Map& map,
|
|||
}
|
||||
|
||||
void render_to_file1(const mapnik::Map& map,
|
||||
const std::string& filename,
|
||||
const std::string& format)
|
||||
std::string const& filename,
|
||||
std::string const& format)
|
||||
{
|
||||
if (format == "pdf" || format == "svg" || format =="ps" || format == "ARGB32" || format == "RGB24")
|
||||
{
|
||||
#if defined(HAVE_CAIRO)
|
||||
mapnik::save_to_cairo_file(map,filename,format);
|
||||
mapnik::save_to_cairo_file(map,filename,format,1.0);
|
||||
#else
|
||||
throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format);
|
||||
#endif
|
||||
|
@ -230,13 +296,13 @@ void render_to_file1(const mapnik::Map& map,
|
|||
}
|
||||
}
|
||||
|
||||
void render_to_file2(const mapnik::Map& map,const std::string& filename)
|
||||
void render_to_file2(const mapnik::Map& 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);
|
||||
mapnik::save_to_cairo_file(map,filename,format,1.0);
|
||||
#else
|
||||
throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format);
|
||||
#endif
|
||||
|
@ -250,15 +316,15 @@ void render_to_file2(const mapnik::Map& map,const std::string& filename)
|
|||
}
|
||||
|
||||
void render_to_file3(const mapnik::Map& map,
|
||||
const std::string& filename,
|
||||
const std::string& format,
|
||||
std::string const& filename,
|
||||
std::string const& format,
|
||||
double scale_factor = 1.0
|
||||
)
|
||||
{
|
||||
if (format == "pdf" || format == "svg" || format =="ps" || format == "ARGB32" || format == "RGB24")
|
||||
{
|
||||
#if defined(HAVE_CAIRO)
|
||||
mapnik::save_to_cairo_file(map,filename,format);
|
||||
mapnik::save_to_cairo_file(map,filename,format,scale_factor);
|
||||
#else
|
||||
throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format);
|
||||
#endif
|
||||
|
@ -277,14 +343,21 @@ double scale_denominator(mapnik::Map const &map, bool geographic)
|
|||
}
|
||||
|
||||
// http://docs.python.org/c-api/exceptions.html#standard-exceptions
|
||||
void config_error_translator(mapnik::config_error const & ex) {
|
||||
void config_error_translator(mapnik::config_error const & ex)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, ex.what());
|
||||
}
|
||||
|
||||
void value_error_translator(mapnik::value_error const & ex) {
|
||||
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());
|
||||
}
|
||||
|
||||
unsigned mapnik_version()
|
||||
{
|
||||
return MAPNIK_VERSION;
|
||||
|
@ -319,7 +392,11 @@ bool has_cairo()
|
|||
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 == NULL){
|
||||
/*
|
||||
Case where pycairo support has been compiled into
|
||||
|
@ -356,6 +433,7 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
|
||||
register_exception_translator<mapnik::config_error>(&config_error_translator);
|
||||
register_exception_translator<mapnik::value_error>(&value_error_translator);
|
||||
register_exception_translator<std::runtime_error>(&runtime_error_translator);
|
||||
register_cairo();
|
||||
export_query();
|
||||
export_geometry();
|
||||
|
@ -370,6 +448,7 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
export_image();
|
||||
export_image_view();
|
||||
export_gamma_method();
|
||||
export_scaling_method();
|
||||
export_grid();
|
||||
export_grid_view();
|
||||
export_expression();
|
||||
|
@ -384,6 +463,7 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
export_line_symbolizer();
|
||||
export_line_pattern_symbolizer();
|
||||
export_polygon_symbolizer();
|
||||
export_building_symbolizer();
|
||||
export_polygon_pattern_symbolizer();
|
||||
export_raster_symbolizer();
|
||||
export_text_placement();
|
||||
|
@ -395,10 +475,18 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
export_coord();
|
||||
export_map();
|
||||
export_raster_colorizer();
|
||||
export_inmem_metawriter();
|
||||
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_grid",&render_grid,
|
||||
( arg("map"),
|
||||
arg("layer"),
|
||||
|
@ -551,6 +639,65 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
">>> 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,
|
||||
|
@ -596,14 +743,18 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
def("has_pycairo", &has_pycairo, "Get pycairo module status");
|
||||
|
||||
def("render_stats", &render_stats);
|
||||
|
||||
python_optional<mapnik::stroke>();
|
||||
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>();
|
||||
|
|
|
@ -30,12 +30,19 @@
|
|||
using mapnik::query;
|
||||
using mapnik::box2d;
|
||||
|
||||
struct query_pickle_suite : boost::python::pickle_suite
|
||||
namespace python = boost::python;
|
||||
|
||||
struct resolution_to_tuple
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(query const& q)
|
||||
static PyObject* convert(query::resolution_type const& x)
|
||||
{
|
||||
return boost::python::make_tuple(q.get_bbox(),q.resolution());
|
||||
python::object tuple(python::make_tuple(x.get<0>(), x.get<1>()));
|
||||
return python::incref(tuple.ptr());
|
||||
}
|
||||
|
||||
static PyTypeObject const* get_pytype()
|
||||
{
|
||||
return &PyTuple_Type;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -43,10 +50,11 @@ void export_query()
|
|||
{
|
||||
using namespace boost::python;
|
||||
|
||||
to_python_converter<query::resolution_type, resolution_to_tuple> ();
|
||||
|
||||
class_<query>("Query", "a spatial query data object",
|
||||
init<box2d<double>,query::resolution_type const&,double>() )
|
||||
.def(init<box2d<double> >())
|
||||
.def_pickle(query_pickle_suite())
|
||||
.add_property("resolution",make_function(&query::resolution,
|
||||
return_value_policy<copy_const_reference>()))
|
||||
.add_property("bbox", make_function(&query::get_bbox,
|
||||
|
|
|
@ -25,46 +25,22 @@
|
|||
|
||||
// mapnik
|
||||
#include <mapnik/raster_symbolizer.hpp>
|
||||
#include <mapnik/raster_colorizer.hpp>
|
||||
#include <mapnik/image_scaling.hpp>
|
||||
|
||||
using mapnik::raster_symbolizer;
|
||||
namespace {
|
||||
|
||||
struct raster_symbolizer_pickle_suite : boost::python::pickle_suite
|
||||
// https://github.com/mapnik/mapnik/issues/1367
|
||||
PyObject* get_premultiplied_impl(mapnik::raster_symbolizer & sym)
|
||||
{
|
||||
/*
|
||||
static boost::python::tuple
|
||||
getinitargs(const raster_symbolizer& r)
|
||||
{
|
||||
return boost::python::make_tuple();
|
||||
}
|
||||
*/
|
||||
boost::optional<bool> premultiplied = sym.premultiplied();
|
||||
if (premultiplied)
|
||||
return ::PyBool_FromLong(*premultiplied);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static boost::python::tuple
|
||||
getstate(const raster_symbolizer& r)
|
||||
{
|
||||
return boost::python::make_tuple(r.get_mode(),r.get_scaling(),r.get_opacity(),r.get_filter_factor(),r.get_mesh_size());
|
||||
}
|
||||
|
||||
static void
|
||||
setstate (raster_symbolizer& r, boost::python::tuple state)
|
||||
{
|
||||
using namespace boost::python;
|
||||
if (len(state) != 5)
|
||||
{
|
||||
PyErr_SetObject(PyExc_ValueError,
|
||||
("expected 5-item tuple in call to __setstate__; got %s"
|
||||
% state).ptr()
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
r.set_mode(extract<std::string>(state[0]));
|
||||
r.set_scaling(extract<std::string>(state[1]));
|
||||
r.set_opacity(extract<float>(state[2]));
|
||||
r.set_filter_factor(extract<float>(state[3]));
|
||||
r.set_mesh_size(extract<unsigned>(state[4]));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using mapnik::raster_symbolizer;
|
||||
|
||||
void export_raster_symbolizer()
|
||||
{
|
||||
|
@ -73,35 +49,26 @@ void export_raster_symbolizer()
|
|||
class_<raster_symbolizer>("RasterSymbolizer",
|
||||
init<>("Default ctor"))
|
||||
|
||||
.def_pickle(raster_symbolizer_pickle_suite())
|
||||
|
||||
.add_property("mode",
|
||||
make_function(&raster_symbolizer::get_mode,return_value_policy<copy_const_reference>()),
|
||||
&raster_symbolizer::set_mode,
|
||||
"Get/Set merging mode.\n"
|
||||
"Possible values are:\n"
|
||||
"normal, grain_merge, grain_merge2, multiply,\n"
|
||||
"multiply2, divide, divide2, screen, and hard_light\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
"\n"
|
||||
">>> from mapnik import RasterSymbolizer\n"
|
||||
">>> r = RasterSymbolizer()\n"
|
||||
">>> r.mode = 'grain_merge2'\n"
|
||||
"Get/Set merging mode. (deprecated, use comp_op instead)\n"
|
||||
)
|
||||
.add_property("comp_op",
|
||||
&raster_symbolizer::comp_op,
|
||||
&raster_symbolizer::set_comp_op,
|
||||
"Set/get the raster comp-op"
|
||||
)
|
||||
|
||||
.add_property("scaling",
|
||||
make_function(&raster_symbolizer::get_scaling,return_value_policy<copy_const_reference>()),
|
||||
&raster_symbolizer::set_scaling,
|
||||
&raster_symbolizer::get_scaling_method,
|
||||
&raster_symbolizer::set_scaling_method,
|
||||
"Get/Set scaling algorithm.\n"
|
||||
"Possible values are:\n"
|
||||
"fast, bilinear, and bilinear8\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
"\n"
|
||||
">>> from mapnik import RasterSymbolizer\n"
|
||||
">>> r = RasterSymbolizer()\n"
|
||||
">>> r.scaling = 'bilinear8'\n"
|
||||
">>> r.scaling = 'mapnik.scaling_method.GAUSSIAN'\n"
|
||||
)
|
||||
|
||||
.add_property("opacity",
|
||||
|
@ -164,5 +131,17 @@ void export_raster_symbolizer()
|
|||
">>> r = RasterSymbolizer()\n"
|
||||
">>> r.mesh_size = 32\n"
|
||||
)
|
||||
.add_property("premultiplied",
|
||||
&get_premultiplied_impl,
|
||||
&raster_symbolizer::set_premultiplied,
|
||||
"Get/Set premultiplied status of the source image.\n"
|
||||
"Can be used to override what the source data reports (when in error)\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
"\n"
|
||||
">>> from mapnik import RasterSymbolizer\n"
|
||||
">>> r = RasterSymbolizer()\n"
|
||||
">>> r.premultiplied = False\n"
|
||||
)
|
||||
;
|
||||
}
|
||||
|
|
|
@ -48,108 +48,6 @@ using mapnik::markers_symbolizer;
|
|||
using mapnik::symbolizer;
|
||||
using mapnik::to_expression_string;
|
||||
|
||||
struct pickle_symbolizer : public boost::static_visitor<>
|
||||
{
|
||||
public:
|
||||
pickle_symbolizer( boost::python::list syms):
|
||||
syms_(syms) {}
|
||||
|
||||
template <typename T>
|
||||
void operator () ( T const& sym )
|
||||
{
|
||||
syms_.append(sym);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::python::list syms_;
|
||||
};
|
||||
|
||||
|
||||
struct extract_symbolizer : public boost::static_visitor<>
|
||||
{
|
||||
public:
|
||||
extract_symbolizer( rule& r):
|
||||
r_(r) {}
|
||||
|
||||
template <typename T>
|
||||
void operator () ( T const& sym )
|
||||
{
|
||||
r_.append(sym);
|
||||
}
|
||||
private:
|
||||
rule& r_;
|
||||
|
||||
};
|
||||
|
||||
struct rule_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const rule& r)
|
||||
{
|
||||
return boost::python::make_tuple(r.get_name(),r.get_min_scale(),r.get_max_scale());
|
||||
}
|
||||
|
||||
static boost::python::tuple
|
||||
getstate(const rule& r)
|
||||
{
|
||||
boost::python::list syms;
|
||||
|
||||
rule::symbolizers::const_iterator begin = r.get_symbolizers().begin();
|
||||
rule::symbolizers::const_iterator end = r.get_symbolizers().end();
|
||||
pickle_symbolizer serializer( syms );
|
||||
std::for_each( begin, end , boost::apply_visitor( serializer ));
|
||||
|
||||
// We serialize filter expressions AST as strings
|
||||
std::string filter_expr = to_expression_string(*r.get_filter());
|
||||
|
||||
return boost::python::make_tuple(filter_expr,r.has_else_filter(),r.has_also_filter(),syms);
|
||||
}
|
||||
|
||||
static void
|
||||
setstate (rule& r, boost::python::tuple state)
|
||||
{
|
||||
using namespace boost::python;
|
||||
if (len(state) != 4)
|
||||
{
|
||||
PyErr_SetObject(PyExc_ValueError,
|
||||
("expected 4-item tuple in call to __setstate__; got %s"
|
||||
% state).ptr()
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
if (state[0])
|
||||
{
|
||||
rule dfl;
|
||||
std::string filter = extract<std::string>(state[1]);
|
||||
std::string default_filter = "<TODO>";//dfl.get_filter()->to_string();
|
||||
if ( filter != default_filter)
|
||||
{
|
||||
r.set_filter(mapnik::parse_expression(filter,"utf8"));
|
||||
}
|
||||
}
|
||||
|
||||
if (state[1])
|
||||
{
|
||||
r.set_else(true);
|
||||
}
|
||||
|
||||
if (state[2])
|
||||
{
|
||||
r.set_also(true);
|
||||
}
|
||||
|
||||
boost::python::list syms=extract<boost::python::list>(state[4]);
|
||||
extract_symbolizer serializer( r );
|
||||
for (int i=0;i<len(syms);++i)
|
||||
{
|
||||
//symbolizer symbol = extract<symbolizer>(syms[i]);
|
||||
//boost::apply_visitor( serializer, symbol );
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void export_rule()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -171,7 +69,6 @@ void export_rule()
|
|||
class_<rule>("Rule",init<>("default constructor"))
|
||||
.def(init<std::string const&,
|
||||
boost::python::optional<double,double> >())
|
||||
.def_pickle(rule_pickle_suite())
|
||||
.add_property("name",make_function
|
||||
(&rule::get_name,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
|
|
52
bindings/python/mapnik_scaling_method.cpp
Normal file
52
bindings/python/mapnik_scaling_method.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2012 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 <boost/python.hpp>
|
||||
#include <mapnik/image_scaling.hpp>
|
||||
#include "mapnik_enumeration.hpp"
|
||||
|
||||
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)
|
||||
.value("BILINEAR8", mapnik::SCALING_BILINEAR8)
|
||||
;
|
||||
}
|
|
@ -21,13 +21,21 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/* The functions in this file produce deprecation warnings.
|
||||
* But as shield symbolizer doesn't fully support more than one
|
||||
* placement from python yet these functions are actually the
|
||||
* correct ones.
|
||||
*/
|
||||
#define NO_DEPRECATION_WARNINGS
|
||||
|
||||
// boost
|
||||
#include <boost/python.hpp>
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/shield_symbolizer.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
#include <mapnik/path_expression_grammar.hpp>
|
||||
#include <mapnik/parse_path.hpp>
|
||||
#include <mapnik/path_expression.hpp>
|
||||
#include "mapnik_svg.hpp"
|
||||
|
||||
using mapnik::color;
|
||||
|
@ -53,12 +61,13 @@ tuple get_shield_displacement(const shield_symbolizer& s)
|
|||
|
||||
void set_shield_displacement(shield_symbolizer & s, boost::python::tuple arg)
|
||||
{
|
||||
s.set_shield_displacement(extract<double>(arg[0]),extract<double>(arg[1]));
|
||||
s.get_placement_options()->defaults.displacement.first = extract<double>(arg[0]);
|
||||
s.get_placement_options()->defaults.displacement.second = extract<double>(arg[1]);
|
||||
}
|
||||
|
||||
tuple get_text_displacement(const shield_symbolizer& t)
|
||||
{
|
||||
position const& pos = t.get_displacement();
|
||||
position const& pos = t.get_placement_options()->defaults.displacement;
|
||||
return boost::python::make_tuple(pos.first, pos.second);
|
||||
}
|
||||
|
||||
|
@ -67,7 +76,7 @@ void set_text_displacement(shield_symbolizer & t, boost::python::tuple arg)
|
|||
t.set_displacement(extract<double>(arg[0]),extract<double>(arg[1]));
|
||||
}
|
||||
|
||||
const std::string get_filename(shield_symbolizer const& t)
|
||||
std::string get_filename(shield_symbolizer const& t)
|
||||
{
|
||||
return path_processor_type::to_string(*t.get_filename());
|
||||
}
|
||||
|
@ -79,46 +88,6 @@ void set_filename(shield_symbolizer & t, std::string const& file_expr)
|
|||
|
||||
}
|
||||
|
||||
struct shield_symbolizer_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const shield_symbolizer& s)
|
||||
{
|
||||
std::string filename = path_processor_type::to_string(*s.get_filename());
|
||||
//(name, font name, font size, font color, image file, image type, width, height)
|
||||
return boost::python::make_tuple( "TODO",//s.get_name(),
|
||||
s.get_face_name(),s.get_text_size(),s.get_fill(),filename,guess_type(filename));
|
||||
|
||||
}
|
||||
|
||||
static boost::python::tuple
|
||||
getstate(const shield_symbolizer& s)
|
||||
{
|
||||
return boost::python::make_tuple(s.get_halo_fill(),s.get_halo_radius());
|
||||
}
|
||||
|
||||
// TODO add lots more...
|
||||
static void
|
||||
setstate (shield_symbolizer& s, 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();
|
||||
}*/
|
||||
|
||||
s.set_halo_fill(extract<color>(state[0]));
|
||||
s.set_halo_radius(extract<float>(state[1]));
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
void export_shield_symbolizer()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
@ -126,9 +95,8 @@ void export_shield_symbolizer()
|
|||
init<expression_ptr,
|
||||
std::string const&,
|
||||
unsigned, mapnik::color const&,
|
||||
path_expression_ptr>("TODO")
|
||||
path_expression_ptr>()
|
||||
)
|
||||
//.def_pickle(shield_symbolizer_pickle_suite())
|
||||
.add_property("allow_overlap",
|
||||
&shield_symbolizer::get_allow_overlap,
|
||||
&shield_symbolizer::set_allow_overlap,
|
||||
|
@ -238,5 +206,13 @@ void export_shield_symbolizer()
|
|||
.add_property("transform",
|
||||
mapnik::get_svg_transform<shield_symbolizer>,
|
||||
mapnik::set_svg_transform<shield_symbolizer>)
|
||||
.add_property("comp_op",
|
||||
&shield_symbolizer::comp_op,
|
||||
&shield_symbolizer::set_comp_op,
|
||||
"Set/get the comp-op")
|
||||
.add_property("clip",
|
||||
&shield_symbolizer::clip,
|
||||
&shield_symbolizer::set_clip,
|
||||
"Set/get the shield geometry's clipping status")
|
||||
;
|
||||
}
|
||||
|
|
|
@ -32,10 +32,9 @@ using namespace mapnik;
|
|||
namespace {
|
||||
using namespace boost::python;
|
||||
|
||||
list get_dashes_list(const stroke& stroke)
|
||||
list get_dashes_list(stroke const& stroke)
|
||||
{
|
||||
list l;
|
||||
|
||||
if (stroke.has_dash()) {
|
||||
mapnik::dash_array const& dash = stroke.get_dash_array();
|
||||
mapnik::dash_array::const_iterator iter = dash.begin();
|
||||
|
@ -44,67 +43,24 @@ list get_dashes_list(const stroke& stroke)
|
|||
l.append(make_tuple(iter->first, iter->second));
|
||||
}
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
void set_dasharray(stroke & stroke, list const& l)
|
||||
{
|
||||
for (int i=0; i<len(l); ++i)
|
||||
{
|
||||
boost::python::tuple dash = extract<boost::python::tuple>(l[i]);
|
||||
if (len(dash) == 2)
|
||||
{
|
||||
double d1 = extract<double>(dash[0]);
|
||||
double d2 = extract<double>(dash[1]);
|
||||
stroke.add_dash(d1,d2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct stroke_pickle_suite : boost::python::pickle_suite
|
||||
{
|
||||
static boost::python::tuple
|
||||
getinitargs(const stroke& s)
|
||||
{
|
||||
|
||||
return boost::python::make_tuple(s.get_color(),s.get_width());
|
||||
|
||||
}
|
||||
|
||||
static boost::python::tuple
|
||||
getstate(const stroke& s)
|
||||
{
|
||||
boost::python::list dashes = get_dashes_list(s);
|
||||
return boost::python::make_tuple(s.get_opacity(),
|
||||
dashes,
|
||||
s.get_line_cap(),
|
||||
s.get_line_join(),
|
||||
s.get_gamma(),
|
||||
s.get_gamma_method());
|
||||
}
|
||||
|
||||
static void
|
||||
setstate (stroke& s, boost::python::tuple state)
|
||||
{
|
||||
using namespace boost::python;
|
||||
if (len(state) != 6)
|
||||
{
|
||||
PyErr_SetObject(PyExc_ValueError,
|
||||
("expected 6-item tuple in call to __setstate__; got %s"
|
||||
% state).ptr()
|
||||
);
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
s.set_opacity(extract<float>(state[0]));
|
||||
|
||||
if (state[1])
|
||||
{
|
||||
list dashes = extract<list>(state[1]);
|
||||
for(boost::python::ssize_t i=0; i<len(dashes); i++) {
|
||||
double ds1 = extract<double>(dashes[i][0]);
|
||||
double ds2 = extract<double>(dashes[i][1]);
|
||||
s.add_dash(ds1,ds2);
|
||||
}
|
||||
}
|
||||
|
||||
s.set_line_cap(extract<line_cap_e>(state[2]));
|
||||
s.set_line_join(extract<line_join_e>(state[3]));
|
||||
s.set_gamma(extract<double>(state[4]));
|
||||
s.set_gamma_method(extract<gamma_method_e>(state[5]));
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void export_stroke ()
|
||||
{
|
||||
|
@ -132,7 +88,6 @@ void export_stroke ()
|
|||
(arg("color"),arg("width")),
|
||||
"Creates a new stroke object with a specified color and width.\n")
|
||||
)
|
||||
.def_pickle(stroke_pickle_suite())
|
||||
.add_property("color",make_function
|
||||
(&stroke::get_color,return_value_policy<copy_const_reference>()),
|
||||
&stroke::set_color,
|
||||
|
@ -159,18 +114,37 @@ void export_stroke ()
|
|||
.add_property("line_cap",
|
||||
&stroke::get_line_cap,
|
||||
&stroke::set_line_cap,
|
||||
"Gets or sets the line cap of this stroke.\n")
|
||||
"Gets or sets the line cap of this stroke. (alias of linecap)\n")
|
||||
.add_property("linecap",
|
||||
&stroke::get_line_cap,
|
||||
&stroke::set_line_cap,
|
||||
"Gets or sets the linecap of this stroke.\n")
|
||||
.add_property("line_join",
|
||||
&stroke::get_line_join,
|
||||
&stroke::set_line_join,
|
||||
"Returns the line join mode of this stroke.\n")
|
||||
// todo consider providing a single get/set property
|
||||
"Returns the line join mode of this stroke. (alias of linejoin)\n")
|
||||
.add_property("linejoin",
|
||||
&stroke::get_line_join,
|
||||
&stroke::set_line_join,
|
||||
"Returns the linejoin mode of this stroke.\n")
|
||||
.add_property("miterlimit",
|
||||
&stroke::get_miterlimit,
|
||||
&stroke::set_miterlimit,
|
||||
"Returns the miterlimit mode of this stroke.\n")
|
||||
.def("add_dash",&stroke::add_dash,
|
||||
(arg("length"),arg("gap")),
|
||||
"Adds a dash segment to the dash patterns of this stroke.\n")
|
||||
.def("get_dashes", get_dashes_list,
|
||||
"Returns the list of dash segments for this stroke.\n")
|
||||
.add_property("dasharray",
|
||||
get_dashes_list,
|
||||
set_dasharray,
|
||||
"Gets or sets dasharray string of this stroke. (alternate property to add_dash/get_dashes)\n")
|
||||
.add_property("dash_offset",
|
||||
&stroke::dash_offset,
|
||||
&stroke::set_dash_offset,
|
||||
"Gets or sets dash offset of this stroke. (alias of dashoffet)\n")
|
||||
.add_property("dashoffset",
|
||||
&stroke::dash_offset,
|
||||
&stroke::set_dash_offset,
|
||||
"Gets or sets dash offset of this stroke.\n")
|
||||
|
|
|
@ -25,51 +25,41 @@
|
|||
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/value_error.hpp>
|
||||
#include "mapnik_enumeration.hpp"
|
||||
#include <mapnik/feature_type_style.hpp>
|
||||
#include <mapnik/image_filter_grammar.hpp> // image_filter_grammar
|
||||
#include <mapnik/image_filter_types.hpp> // generate_image_filters
|
||||
|
||||
using mapnik::feature_type_style;
|
||||
using mapnik::rules;
|
||||
using mapnik::rule;
|
||||
|
||||
struct style_pickle_suite : boost::python::pickle_suite
|
||||
std::string get_image_filters(feature_type_style & style)
|
||||
{
|
||||
static boost::python::tuple
|
||||
getstate(const feature_type_style& s)
|
||||
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::string::const_iterator itr = filters.begin();
|
||||
std::string::const_iterator end = filters.end();
|
||||
mapnik::image_filter_grammar<std::string::const_iterator,
|
||||
std::vector<mapnik::filter::filter_type> > filter_grammar;
|
||||
std::vector<mapnik::filter::filter_type> new_filters;
|
||||
bool result = boost::spirit::qi::phrase_parse(itr,end,
|
||||
filter_grammar,
|
||||
boost::spirit::qi::ascii::space,
|
||||
new_filters);
|
||||
if (!result || itr!=end)
|
||||
{
|
||||
boost::python::list rule_list;
|
||||
|
||||
rules::const_iterator it = s.get_rules().begin();
|
||||
rules::const_iterator end = s.get_rules().end();
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
rule_list.append( *it );
|
||||
}
|
||||
|
||||
return boost::python::make_tuple(rule_list);
|
||||
throw mapnik::value_error("failed to parse image-filters: '" + std::string(itr,end) + "'");
|
||||
}
|
||||
|
||||
static void
|
||||
setstate (feature_type_style& s, 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();
|
||||
}
|
||||
|
||||
boost::python::list rules = extract<boost::python::list>(state[0]);
|
||||
for (int i=0; i<len(rules); ++i)
|
||||
{
|
||||
s.add_rule(extract<rule>(rules[i]));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
style.image_filters().swap(new_filters);
|
||||
}
|
||||
|
||||
void export_style()
|
||||
{
|
||||
|
@ -85,9 +75,6 @@ void export_style()
|
|||
;
|
||||
class_<feature_type_style>("Style",init<>("default style constructor"))
|
||||
|
||||
.def_pickle(style_pickle_suite()
|
||||
)
|
||||
|
||||
.add_property("rules",make_function
|
||||
(&feature_type_style::get_rules,
|
||||
return_value_policy<reference_existing_object>()),
|
||||
|
@ -102,7 +89,19 @@ void export_style()
|
|||
.add_property("filter_mode",
|
||||
&feature_type_style::get_filter_mode,
|
||||
&feature_type_style::set_filter_mode,
|
||||
"Set/get the placement of the label")
|
||||
"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",
|
||||
get_image_filters,
|
||||
set_image_filters,
|
||||
"Set/get the comp-op (composite operation) of the style")
|
||||
;
|
||||
|
||||
}
|
||||
|
|
|
@ -23,35 +23,32 @@
|
|||
#define MAPNIK_PYTHON_BINDING_SVG_INCLUDED
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/parse_transform.hpp>
|
||||
#include <mapnik/symbolizer.hpp>
|
||||
#include <mapnik/svg/svg_path_parser.hpp>
|
||||
#include <mapnik/value_error.hpp>
|
||||
|
||||
// agg
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
namespace mapnik {
|
||||
using namespace boost::python;
|
||||
|
||||
template <class T>
|
||||
const std::string get_svg_transform(T& symbolizer)
|
||||
std::string get_svg_transform(T& symbolizer)
|
||||
{
|
||||
return symbolizer.get_transform_string();
|
||||
return symbolizer.get_image_transform_string();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void set_svg_transform(T& symbolizer, std::string const& transform_wkt)
|
||||
{
|
||||
agg::trans_affine tr;
|
||||
if (!mapnik::svg::parse_transform(transform_wkt.c_str(), tr))
|
||||
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 string like: 'matrix(1, 0, 0, 1, 0, 0)'";
|
||||
ss << "Could not parse transform from '"
|
||||
<< transform_wkt
|
||||
<< "', expected SVG transform attribute";
|
||||
throw mapnik::value_error(ss.str());
|
||||
}
|
||||
mapnik::transform_type matrix;
|
||||
tr.store_to(&matrix[0]);
|
||||
symbolizer.set_transform(matrix);
|
||||
symbolizer.set_image_transform(trans_expr);
|
||||
}
|
||||
|
||||
} // end of namespace mapnik
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
// mapnik
|
||||
//symbolizer typdef here rather than mapnik/symbolizer.hpp
|
||||
|
@ -95,6 +96,13 @@ public:
|
|||
{
|
||||
return "markers";
|
||||
}
|
||||
|
||||
template <typename Symbolizer>
|
||||
std::string operator() ( Symbolizer const& sym)
|
||||
{
|
||||
boost::ignore_unused_variable_warning(sym);
|
||||
return "unknown";
|
||||
}
|
||||
};
|
||||
|
||||
std::string get_symbol_type(const symbolizer& symbol)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
*****************************************************************************/
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/python/stl_iterator.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <mapnik/text_properties.hpp>
|
||||
#include <mapnik/text_placements/simple.hpp>
|
||||
|
@ -28,7 +29,7 @@
|
|||
#include <mapnik/formatting/text.hpp>
|
||||
#include <mapnik/formatting/list.hpp>
|
||||
#include <mapnik/formatting/format.hpp>
|
||||
#include <mapnik/formatting/expression.hpp>
|
||||
#include <mapnik/formatting/expression_format.hpp>
|
||||
#include <mapnik/processed_text.hpp>
|
||||
#include <mapnik/expression_string.hpp>
|
||||
#include <mapnik/text_symbolizer.hpp>
|
||||
|
@ -230,16 +231,16 @@ struct ListNodeWrap: formatting::list_node, wrapper<formatting::list_node>
|
|||
|
||||
formatting::node_ptr get_item(int i)
|
||||
{
|
||||
if (i<0) i+= children_.size();
|
||||
if (i<children_.size()) return children_[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<children_.size()) children_[i] = ptr;
|
||||
if (i < 0) i+= children_.size();
|
||||
if (i < static_cast<int>(children_.size())) children_[i] = ptr;
|
||||
IndexError();
|
||||
}
|
||||
|
||||
|
@ -354,6 +355,14 @@ void export_text_placement()
|
|||
make_function(&get_properties, return_value_policy<reference_existing_object>()),
|
||||
&set_properties,
|
||||
"Shortcut for placements.defaults")
|
||||
.add_property("comp_op",
|
||||
&text_symbolizer::comp_op,
|
||||
&text_symbolizer::set_comp_op,
|
||||
"Set/get the comp-op")
|
||||
.add_property("clip",
|
||||
&text_symbolizer::clip,
|
||||
&text_symbolizer::set_clip,
|
||||
"Set/get the text geometry's clipping status")
|
||||
;
|
||||
|
||||
|
||||
|
@ -376,6 +385,7 @@ void export_text_placement()
|
|||
.def_readwrite("maximum_angle_char_delta", &text_symbolizer_properties::max_char_angle_delta)
|
||||
.def_readwrite("force_odd_labels", &text_symbolizer_properties::force_odd_labels)
|
||||
.def_readwrite("allow_overlap", &text_symbolizer_properties::allow_overlap)
|
||||
.def_readwrite("largest_bbox_only", &text_symbolizer_properties::largest_bbox_only)
|
||||
.def_readwrite("text_ratio", &text_symbolizer_properties::text_ratio)
|
||||
.def_readwrite("wrap_width", &text_symbolizer_properties::wrap_width)
|
||||
.def_readwrite("format", &text_symbolizer_properties::format)
|
||||
|
@ -389,18 +399,20 @@ void export_text_placement()
|
|||
set_old_style expression is just a compatibility wrapper and doesn't need to be exposed in python. */
|
||||
;
|
||||
|
||||
class_<char_properties>
|
||||
|
||||
class_with_converter<char_properties>
|
||||
("CharProperties")
|
||||
.def_readwrite_convert("text_transform", &char_properties::text_transform)
|
||||
.def_readwrite_convert("fontset", &char_properties::fontset)
|
||||
.def(init<char_properties const&>()) //Copy constructor
|
||||
.def_readwrite("face_name", &char_properties::face_name)
|
||||
.def_readwrite("fontset", &char_properties::fontset)
|
||||
.def_readwrite("text_size", &char_properties::text_size)
|
||||
.def_readwrite("character_spacing", &char_properties::character_spacing)
|
||||
.def_readwrite("line_spacing", &char_properties::line_spacing)
|
||||
.def_readwrite("text_opacity", &char_properties::text_opacity)
|
||||
.def_readwrite("wrap_char", &char_properties::wrap_char)
|
||||
.def_readwrite("wrap_character", &char_properties::wrap_char)
|
||||
.def_readwrite("wrap_before", &char_properties::wrap_before)
|
||||
.def_readwrite("text_transform", &char_properties::text_transform)
|
||||
.def_readwrite("fill", &char_properties::fill)
|
||||
.def_readwrite("halo_fill", &char_properties::halo_fill)
|
||||
.def_readwrite("halo_radius", &char_properties::halo_radius)
|
||||
|
@ -487,6 +499,7 @@ void export_text_placement()
|
|||
.def_readwrite_convert("line_spacing", &formatting::format_node::line_spacing)
|
||||
.def_readwrite_convert("text_opacity", &formatting::format_node::text_opacity)
|
||||
.def_readwrite_convert("wrap_char", &formatting::format_node::wrap_char)
|
||||
.def_readwrite_convert("wrap_character", &formatting::format_node::wrap_char)
|
||||
.def_readwrite_convert("wrap_before", &formatting::format_node::wrap_before)
|
||||
.def_readwrite_convert("text_transform", &formatting::format_node::text_transform)
|
||||
.def_readwrite_convert("fill", &formatting::format_node::fill)
|
||||
|
@ -526,6 +539,7 @@ void export_text_placement()
|
|||
.def_readwrite("line_spacing", &formatting::expression_format::line_spacing)
|
||||
.def_readwrite("text_opacity", &formatting::expression_format::text_opacity)
|
||||
.def_readwrite("wrap_char", &formatting::expression_format::wrap_char)
|
||||
.def_readwrite("wrap_character", &formatting::expression_format::wrap_char)
|
||||
.def_readwrite("wrap_before", &formatting::expression_format::wrap_before)
|
||||
.def_readwrite("fill", &formatting::expression_format::fill)
|
||||
.def_readwrite("halo_fill", &formatting::expression_format::halo_fill)
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#ifndef MAPNIK_PYTHON_BINDING_VALUE_CONVERTER_INCLUDED
|
||||
#define MAPNIK_PYTHON_BINDING_VALUE_CONVERTER_INCLUDED
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/value.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/implicit_cast.hpp>
|
||||
|
@ -30,7 +33,7 @@ namespace boost { namespace python {
|
|||
|
||||
struct value_converter : public boost::static_visitor<PyObject*>
|
||||
{
|
||||
PyObject * operator() (int val) const
|
||||
PyObject * operator() (mapnik::value_integer val) const
|
||||
{
|
||||
#if PY_VERSION_HEX >= 0x03000000
|
||||
return ::PyLong_FromLong(val);
|
||||
|
@ -51,23 +54,19 @@ namespace boost { namespace python {
|
|||
|
||||
PyObject * operator() (std::string const& s) const
|
||||
{
|
||||
PyObject *obj = Py_None;
|
||||
obj = ::PyUnicode_DecodeUTF8(s.c_str(),implicit_cast<ssize_t>(s.length()),0);
|
||||
return obj;
|
||||
return ::PyUnicode_DecodeUTF8(s.c_str(),implicit_cast<ssize_t>(s.length()),0);
|
||||
}
|
||||
|
||||
PyObject * operator() (UnicodeString const& s) const
|
||||
PyObject * operator() (mapnik::value_unicode_string const& s) const
|
||||
{
|
||||
std::string buffer;
|
||||
mapnik::to_utf8(s,buffer);
|
||||
PyObject *obj = Py_None;
|
||||
obj = ::PyUnicode_DecodeUTF8(buffer.c_str(),implicit_cast<ssize_t>(buffer.length()),0);
|
||||
return obj;
|
||||
return ::PyUnicode_DecodeUTF8(buffer.c_str(),implicit_cast<ssize_t>(buffer.length()),0);
|
||||
}
|
||||
|
||||
PyObject * operator() (mapnik::value_null const& /*s*/) const
|
||||
{
|
||||
return Py_None;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ 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;
|
||||
|
@ -55,7 +56,11 @@ static void *extract_context(PyObject* op)
|
|||
|
||||
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 == NULL) return;
|
||||
|
||||
boost::python::converter::registry::insert(&extract_surface, boost::python::type_id<PycairoSurface>());
|
||||
|
|
471
bindings/python/python_grid_utils.cpp
Normal file
471
bindings/python/python_grid_utils.cpp
Normal file
|
@ -0,0 +1,471 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2011 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
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
// 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 "mapnik_value_converter.hpp"
|
||||
#include "python_grid_utils.hpp"
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void grid2utf(T const& grid_type,
|
||||
boost::python::list& l,
|
||||
std::vector<grid::lookup_type>& key_order)
|
||||
{
|
||||
typedef std::map< typename T::lookup_type, typename T::value_type> keys_type;
|
||||
typedef typename keys_type::const_iterator keys_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
|
||||
boost::uint16_t codepoint = 32;
|
||||
|
||||
unsigned array_size = data.width();
|
||||
for (unsigned y = 0; y < data.height(); ++y)
|
||||
{
|
||||
boost::uint16_t idx = 0;
|
||||
boost::scoped_array<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)
|
||||
{
|
||||
typedef std::map< typename T::lookup_type, typename T::value_type> keys_type;
|
||||
typedef typename keys_type::const_iterator keys_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
|
||||
boost::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)
|
||||
{
|
||||
boost::uint16_t idx = 0;
|
||||
boost::scoped_array<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)
|
||||
{
|
||||
typedef std::map< typename T::lookup_type, typename T::value_type> keys_type;
|
||||
typedef typename keys_type::const_iterator keys_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;
|
||||
boost::scoped_array<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();
|
||||
BOOST_FOREACH ( 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;
|
||||
BOOST_FOREACH ( 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;
|
||||
BOOST_FOREACH ( 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);
|
||||
|
||||
/* new approach: key comes from grid object
|
||||
* grid size should be same as the map
|
||||
* encoding, resizing handled as method on grid object
|
||||
* whether features are dumped is determined by argument not 'fields'
|
||||
*/
|
||||
void render_layer_for_grid(mapnik::Map const& map,
|
||||
mapnik::grid & grid,
|
||||
unsigned layer_idx, // TODO - layer by name or index
|
||||
boost::python::list const& fields)
|
||||
{
|
||||
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,1.0,0,0);
|
||||
mapnik::layer const& layer = layers[layer_idx];
|
||||
ren.apply(layer,attributes);
|
||||
}
|
||||
|
||||
/* old, original impl - to be removed after further testing
|
||||
* grid object is created on the fly at potentially reduced size
|
||||
*/
|
||||
boost::python::dict render_grid(mapnik::Map const& map,
|
||||
unsigned layer_idx, // layer
|
||||
std::string const& key, // key_name
|
||||
unsigned int step, // resolution
|
||||
boost::python::list const& fields)
|
||||
{
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
unsigned int grid_width = map.width()/step;
|
||||
unsigned int grid_height = map.height()/step;
|
||||
|
||||
// TODO - no need to pass step here
|
||||
mapnik::grid grid(grid_width,grid_height,key,step);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mapnik::grid_renderer<mapnik::grid> ren(map,grid,1.0,0,0);
|
||||
mapnik::layer const& layer = layers[layer_idx];
|
||||
ren.apply(layer,attributes);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
bool add_features = false;
|
||||
if (num_fields > 0)
|
||||
add_features = true;
|
||||
// build dictionary and return to python
|
||||
boost::python::dict json;
|
||||
grid_encode_utf(grid,json,add_features,1);
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
|
@ -24,460 +24,66 @@
|
|||
|
||||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/debug.hpp>
|
||||
#include <mapnik/grid/grid_renderer.hpp>
|
||||
#include <mapnik/map.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 "mapnik_value_converter.hpp"
|
||||
|
||||
|
||||
namespace mapnik {
|
||||
|
||||
|
||||
template <typename T>
|
||||
static void grid2utf(T const& grid_type,
|
||||
void grid2utf(T const& grid_type,
|
||||
boost::python::list& l,
|
||||
std::vector<grid::lookup_type>& key_order)
|
||||
{
|
||||
typename T::data_type const& data = grid_type.data();
|
||||
typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys();
|
||||
typename T::key_type keys;
|
||||
typename T::key_type::const_iterator key_pos;
|
||||
typename T::feature_key_type::const_iterator feature_pos;
|
||||
// start counting at utf8 codepoint 32, aka space character
|
||||
boost::uint16_t codepoint = 32;
|
||||
|
||||
unsigned array_size = data.width();
|
||||
for (unsigned y = 0; y < data.height(); ++y)
|
||||
{
|
||||
boost::uint16_t idx = 0;
|
||||
boost::scoped_array<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)
|
||||
{
|
||||
feature_pos = feature_keys.find(row[x]);
|
||||
if (feature_pos != feature_keys.end())
|
||||
{
|
||||
mapnik::grid::lookup_type val = feature_pos->second;
|
||||
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))));
|
||||
}
|
||||
}
|
||||
std::vector<typename T::lookup_type>& key_order);
|
||||
|
||||
|
||||
template <typename T>
|
||||
static void grid2utf(T const& grid_type,
|
||||
void grid2utf(T const& grid_type,
|
||||
boost::python::list& l,
|
||||
std::vector<typename T::lookup_type>& key_order,
|
||||
unsigned int resolution)
|
||||
{
|
||||
//typename T::data_type const& data = grid_type.data();
|
||||
typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys();
|
||||
typename T::key_type keys;
|
||||
typename T::key_type::const_iterator key_pos;
|
||||
typename T::feature_key_type::const_iterator feature_pos;
|
||||
// start counting at utf8 codepoint 32, aka space character
|
||||
boost::uint16_t codepoint = 32;
|
||||
|
||||
// TODO - use double?
|
||||
unsigned array_size = static_cast<unsigned int>(grid_type.width()/resolution);
|
||||
for (unsigned y = 0; y < grid_type.height(); y=y+resolution)
|
||||
{
|
||||
boost::uint16_t idx = 0;
|
||||
boost::scoped_array<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)
|
||||
{
|
||||
feature_pos = feature_keys.find(row[x]);
|
||||
if (feature_pos != feature_keys.end())
|
||||
{
|
||||
mapnik::grid::lookup_type val = feature_pos->second;
|
||||
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))));
|
||||
}
|
||||
}
|
||||
unsigned int resolution);
|
||||
|
||||
|
||||
template <typename T>
|
||||
static void grid2utf2(T const& grid_type,
|
||||
void grid2utf2(T const& grid_type,
|
||||
boost::python::list& l,
|
||||
std::vector<typename T::lookup_type>& key_order,
|
||||
unsigned int resolution)
|
||||
{
|
||||
typename T::data_type const& data = grid_type.data();
|
||||
typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys();
|
||||
typename T::key_type keys;
|
||||
typename T::key_type::const_iterator key_pos;
|
||||
typename T::feature_key_type::const_iterator feature_pos;
|
||||
// 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;
|
||||
boost::scoped_array<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;
|
||||
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))));
|
||||
}
|
||||
}
|
||||
unsigned int resolution);
|
||||
|
||||
|
||||
template <typename T>
|
||||
static void write_features(T const& grid_type,
|
||||
void write_features(T const& grid_type,
|
||||
boost::python::dict& feature_data,
|
||||
std::vector<typename T::lookup_type> const& key_order)
|
||||
{
|
||||
std::string const& key = grid_type.get_key();
|
||||
std::set<std::string> const& attributes = grid_type.property_names();
|
||||
typename T::feature_type const& g_features = grid_type.get_grid_features();
|
||||
typename T::feature_type::const_iterator feat_itr = g_features.begin();
|
||||
typename T::feature_type::const_iterator feat_end = g_features.end();
|
||||
bool include_key = (attributes.find(key) != attributes.end());
|
||||
for (; feat_itr != feat_end; ++feat_itr)
|
||||
{
|
||||
mapnik::feature_ptr feature = feat_itr->second;
|
||||
boost::optional<std::string> join_value;
|
||||
if (key == grid_type.key_name())
|
||||
{
|
||||
std::stringstream s;
|
||||
s << feature->id();
|
||||
join_value = s.str();
|
||||
}
|
||||
else if (feature->has_key(key))
|
||||
{
|
||||
join_value = feature->get(key).to_string();
|
||||
}
|
||||
|
||||
if (join_value)
|
||||
{
|
||||
// only serialize features visible in the grid
|
||||
if(std::find(key_order.begin(), key_order.end(), *join_value) != key_order.end()) {
|
||||
boost::python::dict feat;
|
||||
bool found = false;
|
||||
if (key == grid_type.key_name())
|
||||
{
|
||||
// drop key unless requested
|
||||
if (include_key) {
|
||||
found = true;
|
||||
//TODO - add __id__ as data key?
|
||||
//feat[key] = *join_value;
|
||||
}
|
||||
}
|
||||
|
||||
feature_kv_iterator itr = feature->begin();
|
||||
feature_kv_iterator end = feature->end();
|
||||
for ( ;itr!=end; ++itr)
|
||||
{
|
||||
std::string const& key_name = boost::get<0>(*itr);
|
||||
if (key_name == key) {
|
||||
// drop key unless requested
|
||||
if (include_key) {
|
||||
found = true;
|
||||
feat[key_name] = boost::get<1>(*itr);
|
||||
}
|
||||
}
|
||||
else if ( (attributes.find(key_name) != attributes.end()) )
|
||||
{
|
||||
found = true;
|
||||
feat[key_name] = boost::get<1>(*itr);
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
feature_data[feat_itr->first] = feat;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MAPNIK_LOG_DEBUG(bindings) << "write_features: Should not get here: key " << key << " not found in grid feature properties";
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<typename T::lookup_type> const& key_order);
|
||||
|
||||
template <typename T>
|
||||
static void grid_encode_utf(T const& grid_type,
|
||||
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;
|
||||
BOOST_FOREACH ( 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;
|
||||
|
||||
}
|
||||
unsigned int resolution);
|
||||
|
||||
template <typename T>
|
||||
static boost::python::dict grid_encode( T const& grid, std::string 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());
|
||||
}
|
||||
}
|
||||
boost::python::dict grid_encode( T const& grid, std::string const& format, bool add_features, unsigned int resolution);
|
||||
|
||||
/* new approach: key comes from grid object
|
||||
* grid size should be same as the map
|
||||
* encoding, resizing handled as method on grid object
|
||||
* whether features are dumped is determined by argument not 'fields'
|
||||
*/
|
||||
static void render_layer_for_grid(const mapnik::Map& map,
|
||||
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)
|
||||
{
|
||||
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::vector
|
||||
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();
|
||||
std::string const& key = grid.get_key();
|
||||
|
||||
// if key is special __id__ keyword
|
||||
if (key == grid.key_name())
|
||||
{
|
||||
// TODO - should feature.id() be a first class attribute?
|
||||
|
||||
// if __id__ is requested to be dumped out
|
||||
// remove it so that datasource queries will not break
|
||||
if (attributes.find(key) != attributes.end())
|
||||
{
|
||||
attributes.erase(key);
|
||||
}
|
||||
}
|
||||
// if key is not the special __id__ keyword
|
||||
else if (attributes.find(key) == attributes.end())
|
||||
{
|
||||
// them make sure the datasource query includes this field
|
||||
attributes.insert(key);
|
||||
}
|
||||
|
||||
mapnik::grid_renderer<mapnik::grid> ren(map,grid,1.0,0,0);
|
||||
mapnik::layer const& layer = layers[layer_idx];
|
||||
ren.apply(layer,attributes);
|
||||
}
|
||||
boost::python::list const& fields);
|
||||
|
||||
/* old, original impl - to be removed after further testing
|
||||
* grid object is created on the fly at potentially reduced size
|
||||
*/
|
||||
static boost::python::dict render_grid(const mapnik::Map& map,
|
||||
boost::python::dict render_grid(const mapnik::Map& map,
|
||||
unsigned layer_idx, // layer
|
||||
std::string const& key, // key_name
|
||||
unsigned int step, // resolution
|
||||
boost::python::list const& fields)
|
||||
{
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
unsigned int grid_width = map.width()/step;
|
||||
unsigned int grid_height = map.height()/step;
|
||||
|
||||
// TODO - no need to pass step here
|
||||
mapnik::grid grid(grid_width,grid_height,key,step);
|
||||
|
||||
// convert python list to std::vector
|
||||
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();
|
||||
|
||||
// if key is special __id__ keyword
|
||||
if (key == grid.key_name())
|
||||
{
|
||||
// TODO - should feature.id() be a first class attribute?
|
||||
|
||||
// if __id__ is requested to be dumped out
|
||||
// remove it so that datasource queries will not break
|
||||
if (attributes.find(key) != attributes.end())
|
||||
{
|
||||
attributes.erase(key);
|
||||
}
|
||||
}
|
||||
// if key is not the special __id__ keyword
|
||||
else if (attributes.find(key) == attributes.end())
|
||||
{
|
||||
// them make sure the datasource query includes this field
|
||||
attributes.insert(key);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
mapnik::grid_renderer<mapnik::grid> ren(map,grid,1.0,0,0);
|
||||
mapnik::layer const& layer = layers[layer_idx];
|
||||
ren.apply(layer,attributes);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
bool add_features = false;
|
||||
if (num_fields > 0)
|
||||
add_features = true;
|
||||
// build dictionary and return to python
|
||||
boost::python::dict json;
|
||||
grid_encode_utf(grid,json,add_features,1);
|
||||
return json;
|
||||
}
|
||||
|
||||
boost::python::list const& fields);
|
||||
}
|
||||
|
||||
#endif // MAPNIK_PYTHON_BINDING_GRID_UTILS_INCLUDED
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
// boost::optional<T> to/from converter from John Wiegley
|
||||
|
||||
|
|
68
boost/geometry/extensions/index/rtree/helpers.hpp
Normal file
68
boost/geometry/extensions/index/rtree/helpers.hpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Boost.SpatialIndex - geometry helper functions
|
||||
//
|
||||
// Copyright 2008 Federico J. Fernandez.
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_GGL_INDEX_RTREE_HELPERS_HPP
|
||||
#define BOOST_GEOMETRY_GGL_INDEX_RTREE_HELPERS_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/area.hpp>
|
||||
#include <boost/geometry/algorithms/disjoint.hpp>
|
||||
#include <boost/geometry/core/point_type.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index {
|
||||
|
||||
/**
|
||||
* \brief Given two boxes, returns the minimal box that contains them
|
||||
*/
|
||||
// TODO: use geometry::expand
|
||||
template <typename Box>
|
||||
inline Box enlarge_box(Box const& b1, Box const& b2)
|
||||
{
|
||||
// TODO: mloskot - Refactor to readable form. Fix VC++8.0 min/max warnings:
|
||||
// warning C4002: too many actual parameters for macro 'min
|
||||
|
||||
typedef typename geometry::point_type<Box>::type point_type;
|
||||
|
||||
point_type pmin(
|
||||
geometry::get<min_corner, 0>(b1) < geometry::get<min_corner, 0>(b2)
|
||||
? geometry::get<min_corner, 0>(b1) : geometry::get<min_corner, 0>(b2),
|
||||
geometry::get<min_corner, 1>(b1) < geometry::get<min_corner, 1>(b2)
|
||||
? geometry::get<min_corner, 1>(b1) : geometry::get<min_corner, 1>(b2));
|
||||
|
||||
point_type pmax(
|
||||
geometry::get<max_corner, 0>(b1) > geometry::get<max_corner, 0>(b2)
|
||||
? geometry::get<max_corner, 0>(b1) : geometry::get<max_corner, 0>(b2),
|
||||
geometry::get<max_corner, 1>(b1) > geometry::get<max_corner, 1>(b2)
|
||||
? geometry::get<max_corner, 1>(b1) : geometry::get<max_corner, 1>(b2));
|
||||
|
||||
return Box(pmin, pmax);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Compute the area of the union of b1 and b2
|
||||
*/
|
||||
template <typename Box>
|
||||
inline typename default_area_result<Box>::type compute_union_area(Box const& b1, Box const& b2)
|
||||
{
|
||||
Box enlarged_box = enlarge_box(b1, b2);
|
||||
return geometry::area(enlarged_box);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks if boxes intersects
|
||||
*/
|
||||
// TODO: move to geometry::intersects
|
||||
template <typename Box>
|
||||
inline bool is_overlapping(Box const& b1, Box const& b2)
|
||||
{
|
||||
return ! geometry::disjoint(b1, b2);
|
||||
}
|
||||
|
||||
}}} // namespace boost::geometry::index
|
||||
|
||||
#endif // BOOST_GEOMETRY_GGL_INDEX_RTREE_HELPERS_HPP
|
774
boost/geometry/extensions/index/rtree/rtree.hpp
Normal file
774
boost/geometry/extensions/index/rtree/rtree.hpp
Normal file
|
@ -0,0 +1,774 @@
|
|||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Boost.SpatialIndex - rtree implementation
|
||||
//
|
||||
// Copyright 2008 Federico J. Fernandez.
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream> // TODO: Remove if print() is removed
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/area.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/index/rtree/rtree_node.hpp>
|
||||
#include <boost/geometry/extensions/index/rtree/rtree_leaf.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index
|
||||
{
|
||||
|
||||
template <typename Box, typename Value >
|
||||
class rtree
|
||||
{
|
||||
public:
|
||||
|
||||
typedef boost::shared_ptr<rtree_node<Box, Value> > node_pointer;
|
||||
typedef boost::shared_ptr<rtree_leaf<Box, Value> > leaf_pointer;
|
||||
|
||||
/**
|
||||
* \brief Creates a rtree with 'maximum' elements per node and 'minimum'.
|
||||
*/
|
||||
rtree(unsigned int const& maximum, unsigned int const& minimum)
|
||||
: m_count(0)
|
||||
, m_min_elems_per_node(minimum)
|
||||
, m_max_elems_per_node(maximum)
|
||||
, m_root(new rtree_node<Box, Value>(node_pointer(), 1))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates a rtree with maximum elements per node
|
||||
* and minimum (box is ignored).
|
||||
*/
|
||||
rtree(Box const& box, unsigned int const& maximum, unsigned int const& minimum)
|
||||
: m_count(0)
|
||||
, m_min_elems_per_node(minimum)
|
||||
, m_max_elems_per_node(maximum)
|
||||
, m_root(new rtree_node<Box, Value>(node_pointer(), 1))
|
||||
{
|
||||
boost::ignore_unused_variable_warning(box);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief destructor (virtual because we have virtual functions)
|
||||
*/
|
||||
virtual ~rtree() {}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Remove elements inside the 'box'
|
||||
*/
|
||||
inline void remove(Box const& box)
|
||||
{
|
||||
try
|
||||
{
|
||||
node_pointer leaf(choose_exact_leaf(box));
|
||||
typename rtree_leaf<Box, Value>::leaf_map q_leaves;
|
||||
|
||||
leaf->remove(box);
|
||||
|
||||
if (leaf->elements() < m_min_elems_per_node && elements() > m_min_elems_per_node)
|
||||
{
|
||||
q_leaves = leaf->get_leaves();
|
||||
|
||||
// we remove the leaf_node in the parent node because now it's empty
|
||||
leaf->get_parent()->remove(leaf->get_parent()->get_box(leaf));
|
||||
}
|
||||
|
||||
typename rtree_node<Box, Value>::node_map q_nodes;
|
||||
condense_tree(leaf, q_nodes);
|
||||
|
||||
std::vector<std::pair<Box, Value> > s;
|
||||
for (typename rtree_node<Box, Value>::node_map::const_iterator it = q_nodes.begin();
|
||||
it != q_nodes.end(); ++it)
|
||||
{
|
||||
typename rtree_leaf<Box, Value>::leaf_map leaves = it->second->get_leaves();
|
||||
|
||||
// reinserting leaves from nodes
|
||||
for (typename rtree_leaf<Box, Value>::leaf_map::const_iterator itl = leaves.begin();
|
||||
itl != leaves.end(); ++itl)
|
||||
{
|
||||
s.push_back(*itl);
|
||||
}
|
||||
}
|
||||
|
||||
for (typename std::vector<std::pair<Box, Value> >::const_iterator it = s.begin(); it != s.end(); ++it)
|
||||
{
|
||||
m_count--;
|
||||
insert(it->first, it->second);
|
||||
}
|
||||
|
||||
// if the root has only one child and the child is not a leaf,
|
||||
// make it the root
|
||||
if (m_root->elements() == 1)
|
||||
{
|
||||
if (!m_root->first_element()->is_leaf())
|
||||
{
|
||||
m_root = m_root->first_element();
|
||||
}
|
||||
}
|
||||
// reinserting leaves
|
||||
for (typename rtree_leaf<Box, Value>::leaf_map::const_iterator it = q_leaves.begin();
|
||||
it != q_leaves.end(); ++it)
|
||||
{
|
||||
m_count--;
|
||||
insert(it->first, it->second);
|
||||
}
|
||||
|
||||
m_count--;
|
||||
}
|
||||
catch(std::logic_error & e)
|
||||
{
|
||||
// TODO: mloskot - replace with Boost.Geometry exception
|
||||
|
||||
// not found
|
||||
std::cerr << e.what() << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Remove element inside the box with value
|
||||
*/
|
||||
void remove(Box const& box, Value const& value)
|
||||
{
|
||||
try
|
||||
{
|
||||
node_pointer leaf;
|
||||
|
||||
// find possible leaves
|
||||
typedef typename std::vector<node_pointer > node_type;
|
||||
node_type nodes;
|
||||
m_root->find_leaves(box, nodes);
|
||||
|
||||
// refine the result
|
||||
for (typename node_type::const_iterator it = nodes.begin(); it != nodes.end(); ++it)
|
||||
{
|
||||
leaf = *it;
|
||||
try
|
||||
{
|
||||
leaf->remove(value);
|
||||
break;
|
||||
} catch (...)
|
||||
{
|
||||
leaf = node_pointer();
|
||||
}
|
||||
}
|
||||
|
||||
if (!leaf)
|
||||
return;
|
||||
|
||||
typename rtree_leaf < Box, Value >::leaf_map q_leaves;
|
||||
|
||||
if (leaf->elements() < m_min_elems_per_node && elements() > m_min_elems_per_node)
|
||||
{
|
||||
q_leaves = leaf->get_leaves();
|
||||
|
||||
// we remove the leaf_node in the parent node because now it's empty
|
||||
leaf->get_parent()->remove(leaf->get_parent()->get_box(leaf));
|
||||
}
|
||||
|
||||
typename rtree_node<Box, Value>::node_map q_nodes;
|
||||
condense_tree(leaf, q_nodes);
|
||||
|
||||
std::vector<std::pair<Box, Value> > s;
|
||||
for (typename rtree_node<Box, Value>::node_map::const_iterator it = q_nodes.begin();
|
||||
it != q_nodes.end(); ++it)
|
||||
{
|
||||
typename rtree_leaf<Box, Value>::leaf_map leaves = it->second->get_leaves();
|
||||
|
||||
// reinserting leaves from nodes
|
||||
for (typename rtree_leaf<Box, Value>::leaf_map::const_iterator itl = leaves.begin();
|
||||
itl != leaves.end(); ++itl)
|
||||
{
|
||||
s.push_back(*itl);
|
||||
}
|
||||
}
|
||||
|
||||
for (typename std::vector<std::pair<Box, Value> >::const_iterator it = s.begin(); it != s.end(); ++it)
|
||||
{
|
||||
m_count--;
|
||||
insert(it->first, it->second);
|
||||
}
|
||||
|
||||
// if the root has only one child and the child is not a leaf,
|
||||
// make it the root
|
||||
if (m_root->elements() == 1)
|
||||
{
|
||||
if (!m_root->first_element()->is_leaf())
|
||||
{
|
||||
m_root = m_root->first_element();
|
||||
}
|
||||
}
|
||||
|
||||
// reinserting leaves
|
||||
for (typename rtree_leaf<Box, Value>::leaf_map::const_iterator it = q_leaves.begin();
|
||||
it != q_leaves.end(); ++it)
|
||||
{
|
||||
m_count--;
|
||||
insert(it->first, it->second);
|
||||
}
|
||||
|
||||
m_count--;
|
||||
|
||||
}
|
||||
catch(std::logic_error & e)
|
||||
{
|
||||
// TODO: mloskot - ggl exception
|
||||
|
||||
// not found
|
||||
std::cerr << e.what() << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the number of elements.
|
||||
*/
|
||||
inline unsigned int elements() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Inserts an element with 'box' as key with value.
|
||||
*/
|
||||
inline void insert(Box const& box, Value const& value)
|
||||
{
|
||||
m_count++;
|
||||
|
||||
node_pointer leaf(choose_corresponding_leaf(box));
|
||||
|
||||
// check if the selected leaf is full to do the split if necessary
|
||||
if (leaf->elements() >= m_max_elems_per_node)
|
||||
{
|
||||
leaf->insert(box, value);
|
||||
|
||||
// split!
|
||||
node_pointer n1(new rtree_leaf<Box, Value>(leaf->get_parent()));
|
||||
node_pointer n2(new rtree_leaf<Box, Value>(leaf->get_parent()));
|
||||
|
||||
split_node(leaf, n1, n2);
|
||||
adjust_tree(leaf, n1, n2);
|
||||
}
|
||||
else
|
||||
{
|
||||
leaf->insert(box, value);
|
||||
adjust_tree(leaf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Returns all the values inside 'box'
|
||||
*/
|
||||
inline std::deque<Value> find(Box const& box) const
|
||||
{
|
||||
std::deque<Value> result;
|
||||
m_root->find(box, result, false);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Print Rtree (mainly for debug)
|
||||
*/
|
||||
inline void print()
|
||||
{
|
||||
std::cerr << "===================================" << std::endl;
|
||||
std::cerr << " Min/Max: " << m_min_elems_per_node << " / " << m_max_elems_per_node << std::endl;
|
||||
std::cerr << "Leaves: " << m_root->get_leaves().size() << std::endl;
|
||||
m_root->print();
|
||||
std::cerr << "===================================" << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// number of elements
|
||||
unsigned int m_count;
|
||||
|
||||
/// minimum number of elements per node
|
||||
unsigned int m_min_elems_per_node;
|
||||
|
||||
/// maximum number of elements per node
|
||||
unsigned int m_max_elems_per_node;
|
||||
|
||||
/// tree root
|
||||
node_pointer m_root;
|
||||
|
||||
/**
|
||||
* \brief Reorganize the tree after a removal. It tries to
|
||||
* join nodes with less elements than m.
|
||||
*/
|
||||
void condense_tree(node_pointer const& leaf,
|
||||
typename rtree_node<Box, Value>::node_map& q_nodes)
|
||||
{
|
||||
if (leaf.get() == m_root.get())
|
||||
{
|
||||
// if it's the root we are done
|
||||
return;
|
||||
}
|
||||
|
||||
node_pointer parent = leaf->get_parent();
|
||||
parent->adjust_box(leaf);
|
||||
|
||||
if (parent->elements() < m_min_elems_per_node)
|
||||
{
|
||||
if (parent.get() == m_root.get())
|
||||
{
|
||||
// if the parent is underfull and it's the root we just exit
|
||||
return;
|
||||
}
|
||||
|
||||
// get the nodes that we should reinsert
|
||||
typename rtree_node<Box, Value>::node_map this_nodes = parent->get_nodes();
|
||||
for(typename rtree_node<Box, Value>::node_map::const_iterator it = this_nodes.begin();
|
||||
it != this_nodes.end(); ++it)
|
||||
{
|
||||
q_nodes.push_back(*it);
|
||||
}
|
||||
|
||||
// we remove the node in the parent node because now it should be
|
||||
// re inserted
|
||||
parent->get_parent()->remove(parent->get_parent()->get_box(parent));
|
||||
}
|
||||
|
||||
condense_tree(parent, q_nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief After an insertion splits nodes with more than 'maximum' elements.
|
||||
*/
|
||||
inline void adjust_tree(node_pointer& node)
|
||||
{
|
||||
if (node.get() == m_root.get())
|
||||
{
|
||||
// we finished the adjust
|
||||
return;
|
||||
}
|
||||
|
||||
// as there are no splits just adjust the box of the parent and go on
|
||||
node_pointer parent = node->get_parent();
|
||||
parent->adjust_box(node);
|
||||
adjust_tree(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief After an insertion splits nodes with more than maximum elements
|
||||
* (recursive step with subtrees 'n1' and 'n2' to be joined).
|
||||
*/
|
||||
void adjust_tree(node_pointer& leaf, node_pointer& n1, node_pointer& n2)
|
||||
{
|
||||
// check if we are in the root and do the split
|
||||
if (leaf.get() == m_root.get())
|
||||
{
|
||||
node_pointer new_root(new rtree_node<Box,Value>(node_pointer (), leaf->get_level() + 1));
|
||||
new_root->add_node(n1->compute_box(), n1);
|
||||
new_root->add_node(n2->compute_box(), n2);
|
||||
|
||||
n1->set_parent(new_root);
|
||||
n2->set_parent(new_root);
|
||||
|
||||
n1->update_parent(n1);
|
||||
n2->update_parent(n2);
|
||||
|
||||
m_root = new_root;
|
||||
return;
|
||||
}
|
||||
|
||||
node_pointer parent = leaf->get_parent();
|
||||
|
||||
parent->replace_node(leaf, n1);
|
||||
parent->add_node(n2->compute_box(), n2);
|
||||
|
||||
// if parent is full, split and readjust
|
||||
if (parent->elements() > m_max_elems_per_node)
|
||||
{
|
||||
node_pointer p1(new rtree_node<Box, Value>(parent->get_parent(), parent->get_level()));
|
||||
node_pointer p2(new rtree_node<Box, Value>(parent->get_parent(), parent->get_level()));
|
||||
|
||||
split_node(parent, p1, p2);
|
||||
adjust_tree(parent, p1, p2);
|
||||
}
|
||||
else
|
||||
{
|
||||
adjust_tree(parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Splits 'n' in 'n1' and 'n2'
|
||||
*/
|
||||
void split_node(node_pointer const& n, node_pointer& n1, node_pointer& n2) const
|
||||
{
|
||||
unsigned int seed1 = 0;
|
||||
unsigned int seed2 = 0;
|
||||
std::vector<Box> boxes = n->get_boxes();
|
||||
|
||||
n1->set_parent(n->get_parent());
|
||||
n2->set_parent(n->get_parent());
|
||||
|
||||
linear_pick_seeds(n, seed1, seed2);
|
||||
|
||||
if (n->is_leaf())
|
||||
{
|
||||
n1->add_value(boxes[seed1], n->get_value(seed1));
|
||||
n2->add_value(boxes[seed2], n->get_value(seed2));
|
||||
}
|
||||
else
|
||||
{
|
||||
n1->add_node(boxes[seed1], n->get_node(seed1));
|
||||
n2->add_node(boxes[seed2], n->get_node(seed2));
|
||||
}
|
||||
|
||||
unsigned int index = 0;
|
||||
|
||||
if (n->is_leaf())
|
||||
{
|
||||
// TODO: mloskot - add assert(node.size() >= 2); or similar
|
||||
|
||||
typename rtree_leaf<Box, Value>::leaf_map nodes = n->get_leaves();
|
||||
unsigned int remaining = nodes.size() - 2;
|
||||
|
||||
for (typename rtree_leaf<Box, Value>::leaf_map::const_iterator it = nodes.begin();
|
||||
it != nodes.end(); ++it, index++)
|
||||
{
|
||||
if (index != seed1 && index != seed2)
|
||||
{
|
||||
if (n1->elements() + remaining == m_min_elems_per_node)
|
||||
{
|
||||
n1->add_value(it->first, it->second);
|
||||
continue;
|
||||
}
|
||||
if (n2->elements() + remaining == m_min_elems_per_node)
|
||||
{
|
||||
n2->add_value(it->first, it->second);
|
||||
continue;
|
||||
}
|
||||
|
||||
remaining--;
|
||||
|
||||
/// current boxes of each group
|
||||
Box b1, b2;
|
||||
|
||||
/// enlarged boxes of each group
|
||||
Box eb1, eb2;
|
||||
b1 = n1->compute_box();
|
||||
b2 = n2->compute_box();
|
||||
|
||||
/// areas
|
||||
typedef typename coordinate_type<Box>::type coordinate_type;
|
||||
coordinate_type b1_area, b2_area;
|
||||
coordinate_type eb1_area, eb2_area;
|
||||
b1_area = geometry::area(b1);
|
||||
b2_area = geometry::area(b2);
|
||||
eb1_area = compute_union_area(b1, it->first);
|
||||
eb2_area = compute_union_area(b2, it->first);
|
||||
|
||||
if (eb1_area - b1_area > eb2_area - b2_area)
|
||||
{
|
||||
n2->add_value(it->first, it->second);
|
||||
}
|
||||
if (eb1_area - b1_area < eb2_area - b2_area)
|
||||
{
|
||||
n1->add_value(it->first, it->second);
|
||||
}
|
||||
if (eb1_area - b1_area == eb2_area - b2_area)
|
||||
{
|
||||
if (b1_area < b2_area)
|
||||
{
|
||||
n1->add_value(it->first, it->second);
|
||||
}
|
||||
if (b1_area > b2_area)
|
||||
{
|
||||
n2->add_value(it->first, it->second);
|
||||
}
|
||||
if (b1_area == b2_area)
|
||||
{
|
||||
if (n1->elements() > n2->elements())
|
||||
{
|
||||
n2->add_value(it->first, it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
n1->add_value(it->first, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: mloskot - add assert(node.size() >= 2); or similar
|
||||
|
||||
typename rtree_node<Box, Value>::node_map nodes = n->get_nodes();
|
||||
unsigned int remaining = nodes.size() - 2;
|
||||
for(typename rtree_node<Box, Value>::node_map::const_iterator it = nodes.begin();
|
||||
it != nodes.end(); ++it, index++)
|
||||
{
|
||||
|
||||
if (index != seed1 && index != seed2)
|
||||
{
|
||||
|
||||
if (n1->elements() + remaining == m_min_elems_per_node)
|
||||
{
|
||||
n1->add_node(it->first, it->second);
|
||||
continue;
|
||||
}
|
||||
if (n2->elements() + remaining == m_min_elems_per_node)
|
||||
{
|
||||
n2->add_node(it->first, it->second);
|
||||
continue;
|
||||
}
|
||||
|
||||
remaining--;
|
||||
|
||||
/// current boxes of each group
|
||||
Box b1, b2;
|
||||
|
||||
/// enlarged boxes of each group
|
||||
Box eb1, eb2;
|
||||
b1 = n1->compute_box();
|
||||
b2 = n2->compute_box();
|
||||
|
||||
/// areas
|
||||
typedef typename coordinate_type<Box>::type coordinate_type;
|
||||
coordinate_type b1_area, b2_area;
|
||||
coordinate_type eb1_area, eb2_area;
|
||||
b1_area = geometry::area(b1);
|
||||
b2_area = geometry::area(b2);
|
||||
|
||||
eb1_area = compute_union_area(b1, it->first);
|
||||
eb2_area = compute_union_area(b2, it->first);
|
||||
|
||||
if (eb1_area - b1_area > eb2_area - b2_area)
|
||||
{
|
||||
n2->add_node(it->first, it->second);
|
||||
}
|
||||
if (eb1_area - b1_area < eb2_area - b2_area)
|
||||
{
|
||||
n1->add_node(it->first, it->second);
|
||||
}
|
||||
if (eb1_area - b1_area == eb2_area - b2_area)
|
||||
{
|
||||
if (b1_area < b2_area)
|
||||
{
|
||||
n1->add_node(it->first, it->second);
|
||||
}
|
||||
if (b1_area > b2_area)
|
||||
{
|
||||
n2->add_node(it->first, it->second);
|
||||
}
|
||||
if (b1_area == b2_area)
|
||||
{
|
||||
if (n1->elements() > n2->elements())
|
||||
{
|
||||
n2->add_node(it->first, it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
n1->add_node(it->first, it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Choose initial values for the split algorithm (linear version)
|
||||
*/
|
||||
void linear_pick_seeds(node_pointer const& n, unsigned int &seed1, unsigned int &seed2) const
|
||||
{
|
||||
// get boxes from the node
|
||||
std::vector<Box>boxes = n->get_boxes();
|
||||
if (boxes.size() == 0)
|
||||
{
|
||||
// TODO: mloskot - throw ggl exception
|
||||
throw std::logic_error("Empty Node trying to Pick Seeds");
|
||||
}
|
||||
|
||||
// only two dim for now
|
||||
// unsigned int dimensions =
|
||||
// geometry::point_traits<Point>::coordinate_count;
|
||||
|
||||
// find the first two elements
|
||||
typedef typename coordinate_type<Box>::type coordinate_type;
|
||||
coordinate_type separation_x, separation_y;
|
||||
unsigned int first_x, second_x;
|
||||
unsigned int first_y, second_y;
|
||||
find_normalized_separations<0u>(boxes, separation_x, first_x, second_x);
|
||||
find_normalized_separations<1u>(boxes, separation_y, first_y, second_y);
|
||||
|
||||
if (separation_x > separation_y)
|
||||
{
|
||||
seed1 = first_x;
|
||||
seed2 = second_x;
|
||||
}
|
||||
else
|
||||
{
|
||||
seed1 = first_y;
|
||||
seed2 = second_y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Find distances between possible initial values for the
|
||||
* pick_seeds algorithm.
|
||||
*/
|
||||
template <std::size_t D, typename T>
|
||||
void find_normalized_separations(std::vector<Box> const& boxes, T& separation,
|
||||
unsigned int& first, unsigned int& second) const
|
||||
{
|
||||
if (boxes.size() < 2)
|
||||
{
|
||||
throw std::logic_error("At least two boxes needed to split");
|
||||
}
|
||||
|
||||
// find the lowest high
|
||||
typename std::vector<Box>::const_iterator it = boxes.begin();
|
||||
typedef typename coordinate_type<Box>::type coordinate_type;
|
||||
coordinate_type lowest_high = geometry::get<max_corner, D>(*it);
|
||||
unsigned int lowest_high_index = 0;
|
||||
unsigned int index = 1;
|
||||
++it;
|
||||
for(; it != boxes.end(); ++it)
|
||||
{
|
||||
if (geometry::get<max_corner, D>(*it) < lowest_high)
|
||||
{
|
||||
lowest_high = geometry::get<max_corner, D>(*it);
|
||||
lowest_high_index = index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// find the highest low
|
||||
coordinate_type highest_low = 0;
|
||||
unsigned int highest_low_index = 0;
|
||||
if (lowest_high_index == 0)
|
||||
{
|
||||
highest_low = geometry::get<min_corner, D>(boxes[1]);
|
||||
highest_low_index = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
highest_low = geometry::get<min_corner, D>(boxes[0]);
|
||||
highest_low_index = 0;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
for (it = boxes.begin();
|
||||
it != boxes.end(); ++it, index++)
|
||||
{
|
||||
if (geometry::get<min_corner, D>(*it) >= highest_low && index != lowest_high_index)
|
||||
{
|
||||
highest_low = geometry::get<min_corner, D>(*it);
|
||||
highest_low_index = index;
|
||||
}
|
||||
}
|
||||
|
||||
// find the lowest low
|
||||
it = boxes.begin();
|
||||
coordinate_type lowest_low = geometry::get<min_corner, D>(*it);
|
||||
++it;
|
||||
for(; it != boxes.end(); ++it)
|
||||
{
|
||||
if (geometry::get<min_corner, D>(*it) < lowest_low)
|
||||
{
|
||||
lowest_low = geometry::get<min_corner, D>(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// find the highest high
|
||||
it = boxes.begin();
|
||||
coordinate_type highest_high = geometry::get<max_corner, D>(*it);
|
||||
++it;
|
||||
for(; it != boxes.end(); ++it)
|
||||
{
|
||||
if (geometry::get<max_corner, D>(*it) > highest_high)
|
||||
{
|
||||
highest_high = geometry::get<max_corner, D>(*it);
|
||||
}
|
||||
}
|
||||
|
||||
coordinate_type const width = highest_high - lowest_low;
|
||||
|
||||
separation = (highest_low - lowest_high) / width;
|
||||
first = highest_low_index;
|
||||
second = lowest_high_index;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Choose one of the possible leaves to make an insertion
|
||||
*/
|
||||
inline node_pointer choose_corresponding_leaf(Box const& e)
|
||||
{
|
||||
node_pointer node = m_root;
|
||||
|
||||
// if the tree is empty add an initial leaf
|
||||
if (m_root->elements() == 0)
|
||||
{
|
||||
leaf_pointer new_leaf(new rtree_leaf<Box, Value>(m_root));
|
||||
m_root->add_leaf_node(Box (), new_leaf);
|
||||
|
||||
return new_leaf;
|
||||
}
|
||||
|
||||
while (!node->is_leaf())
|
||||
{
|
||||
/// traverse node's map to see which node we should select
|
||||
node = node->choose_node(e);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Choose the exact leaf where an insertion should be done
|
||||
*/
|
||||
node_pointer choose_exact_leaf(Box const&e) const
|
||||
{
|
||||
// find possible leaves
|
||||
typedef typename std::vector<node_pointer> node_type;
|
||||
node_type nodes;
|
||||
m_root->find_leaves(e, nodes);
|
||||
|
||||
// refine the result
|
||||
for (typename node_type::const_iterator it = nodes.begin(); it != nodes.end(); ++it)
|
||||
{
|
||||
typedef std::vector<std::pair<Box, Value> > leaves_type;
|
||||
leaves_type leaves = (*it)->get_leaves();
|
||||
|
||||
for (typename leaves_type::const_iterator itl = leaves.begin();
|
||||
itl != leaves.end(); ++itl)
|
||||
{
|
||||
|
||||
if (itl->first.max_corner() == e.max_corner()
|
||||
&& itl->first.min_corner() == e.min_corner())
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: mloskot - ggl exception
|
||||
throw std::logic_error("Leaf not found");
|
||||
}
|
||||
};
|
||||
|
||||
}}} // namespace boost::geometry::index
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_HPP
|
||||
|
253
boost/geometry/extensions/index/rtree/rtree_leaf.hpp
Normal file
253
boost/geometry/extensions/index/rtree/rtree_leaf.hpp
Normal file
|
@ -0,0 +1,253 @@
|
|||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Boost.SpatialIndex - rtree leaf implementation
|
||||
//
|
||||
// Copyright 2008 Federico J. Fernandez.
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_LEAF_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_LEAF_HPP
|
||||
|
||||
#include <deque>
|
||||
#include <iostream> // TODO: Remove if print() is removed
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/area.hpp>
|
||||
#include <boost/geometry/algorithms/assign.hpp>
|
||||
#include <boost/geometry/algorithms/expand.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/index/rtree/rtree_node.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index
|
||||
{
|
||||
|
||||
template <typename Box, typename Value >
|
||||
class rtree_leaf : public rtree_node<Box, Value>
|
||||
{
|
||||
public:
|
||||
|
||||
/// container type for the leaves
|
||||
typedef boost::shared_ptr<rtree_node<Box, Value> > node_pointer;
|
||||
typedef std::vector<std::pair<Box, Value> > leaf_map;
|
||||
|
||||
/**
|
||||
* \brief Creates an empty leaf
|
||||
*/
|
||||
inline rtree_leaf()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates a new leaf, with 'parent' as parent
|
||||
*/
|
||||
inline rtree_leaf(node_pointer const& parent)
|
||||
: rtree_node<Box, Value> (parent, 0)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Search for elements in 'box' in the Rtree. Add them to 'result'.
|
||||
* If exact_match is true only return the elements having as
|
||||
* key the 'box'. Otherwise return everything inside 'box'.
|
||||
*/
|
||||
virtual void find(Box const& box, std::deque<Value>& result, bool const exact_match)
|
||||
{
|
||||
for (typename leaf_map::const_iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
if (exact_match)
|
||||
{
|
||||
if (geometry::equals(it->first, box))
|
||||
{
|
||||
result.push_back(it->second);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_overlapping(it->first, box))
|
||||
{
|
||||
result.push_back(it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Compute bounding box for this leaf
|
||||
*/
|
||||
virtual Box compute_box() const
|
||||
{
|
||||
if (m_nodes.empty())
|
||||
{
|
||||
return Box ();
|
||||
}
|
||||
|
||||
Box r;
|
||||
geometry::assign_inverse(r);
|
||||
for(typename leaf_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
||||
{
|
||||
geometry::expand(r, it->first);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief True if we are a leaf
|
||||
*/
|
||||
virtual bool is_leaf() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Number of elements in the tree
|
||||
*/
|
||||
virtual unsigned int elements() const
|
||||
{
|
||||
return m_nodes.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Insert a new element, with key 'box' and value 'v'
|
||||
*/
|
||||
virtual void insert(Box const& box, Value const& v)
|
||||
{
|
||||
m_nodes.push_back(std::make_pair(box, v));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Proyect leaves of this node.
|
||||
*/
|
||||
virtual std::vector< std::pair<Box, Value> > get_leaves() const
|
||||
{
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add a new child (node) to this node
|
||||
*/
|
||||
virtual void add_node(Box const&, node_pointer const&)
|
||||
{
|
||||
// TODO: mloskot - define & use GGL exception
|
||||
throw std::logic_error("Can't add node to leaf node.");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add a new leaf to this node
|
||||
*/
|
||||
virtual void add_value(Box const& box, Value const& v)
|
||||
{
|
||||
m_nodes.push_back(std::make_pair(box, v));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \brief Proyect value in position 'index' in the nodes container
|
||||
*/
|
||||
virtual Value get_value(unsigned int index) const
|
||||
{
|
||||
return m_nodes[index].second;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Box projector for leaf
|
||||
*/
|
||||
virtual Box get_box(unsigned int index) const
|
||||
{
|
||||
return m_nodes[index].first;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Remove value with key 'box' in this leaf
|
||||
*/
|
||||
virtual void remove(Box const& box)
|
||||
{
|
||||
|
||||
for (typename leaf_map::iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
if (geometry::equals(it->first, box))
|
||||
{
|
||||
m_nodes.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: mloskot - use GGL exception
|
||||
throw std::logic_error("Node not found.");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Remove value in this leaf
|
||||
*/
|
||||
virtual void remove(Value const& v)
|
||||
{
|
||||
for (typename leaf_map::iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
if (it->second == v)
|
||||
{
|
||||
m_nodes.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: mloskot - use GGL exception
|
||||
throw std::logic_error("Node not found.");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Proyect boxes from this node
|
||||
*/
|
||||
virtual std::vector<Box> get_boxes() const
|
||||
{
|
||||
std::vector<Box> result;
|
||||
for (typename leaf_map::const_iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
result.push_back(it->first);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Print leaf (mainly for debug)
|
||||
*/
|
||||
virtual void print() const
|
||||
{
|
||||
std::cerr << "\t" << " --> Leaf --------" << std::endl;
|
||||
std::cerr << "\t" << " Size: " << m_nodes.size() << std::endl;
|
||||
for (typename leaf_map::const_iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
std::cerr << "\t" << " | ";
|
||||
std::cerr << "( " << geometry::get<min_corner, 0>
|
||||
(it->first) << " , " << geometry::get<min_corner, 1>
|
||||
(it->first) << " ) x ";
|
||||
std::cerr << "( " << geometry::get<max_corner, 0>
|
||||
(it->first) << " , " << geometry::get<max_corner, 1>
|
||||
(it->first) << " )";
|
||||
std::cerr << " -> ";
|
||||
std::cerr << it->second;
|
||||
std::cerr << " | " << std::endl;;
|
||||
}
|
||||
std::cerr << "\t" << " --< Leaf --------" << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// leaves of this node
|
||||
leaf_map m_nodes;
|
||||
};
|
||||
|
||||
}}} // namespace boost::geometry::index
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_LEAF_HPP
|
||||
|
493
boost/geometry/extensions/index/rtree/rtree_node.hpp
Normal file
493
boost/geometry/extensions/index/rtree/rtree_node.hpp
Normal file
|
@ -0,0 +1,493 @@
|
|||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Boost.SpatialIndex - rtree node implementation
|
||||
//
|
||||
// Copyright 2008 Federico J. Fernandez.
|
||||
// Use, modification and distribution is subject to the Boost Software License,
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_NODE_HPP
|
||||
#define BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_NODE_HPP
|
||||
|
||||
#include <deque>
|
||||
#include <iostream> // TODO: Remove if print() is removed
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/area.hpp>
|
||||
#include <boost/geometry/algorithms/assign.hpp>
|
||||
#include <boost/geometry/algorithms/equals.hpp>
|
||||
#include <boost/geometry/algorithms/expand.hpp>
|
||||
|
||||
#include <boost/geometry/extensions/index/rtree/helpers.hpp>
|
||||
|
||||
namespace boost { namespace geometry { namespace index
|
||||
{
|
||||
|
||||
/// forward declaration
|
||||
template <typename Box, typename Value>
|
||||
class rtree_leaf;
|
||||
|
||||
template <typename Box, typename Value>
|
||||
class rtree_node
|
||||
{
|
||||
public:
|
||||
|
||||
typedef boost::shared_ptr<rtree_node<Box, Value> > node_pointer;
|
||||
typedef boost::shared_ptr<rtree_leaf<Box, Value> > leaf_pointer;
|
||||
|
||||
/// type for the node map
|
||||
typedef std::vector<std::pair<Box, node_pointer > > node_map;
|
||||
|
||||
/**
|
||||
* \brief Creates a default node (needed for the containers)
|
||||
*/
|
||||
rtree_node()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates a node with 'parent' as parent and 'level' as its level
|
||||
*/
|
||||
rtree_node(node_pointer const& parent, unsigned int const& level)
|
||||
: m_parent(parent), m_level(level)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief destructor (virtual because we have virtual functions)
|
||||
*/
|
||||
virtual ~rtree_node()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Level projector
|
||||
*/
|
||||
virtual unsigned int get_level() const
|
||||
{
|
||||
return m_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Number of elements in the subtree
|
||||
*/
|
||||
virtual unsigned int elements() const
|
||||
{
|
||||
return m_nodes.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Project first element, to replace root in case of condensing
|
||||
*/
|
||||
inline node_pointer first_element() const
|
||||
{
|
||||
if (0 == m_nodes.size())
|
||||
{
|
||||
// TODO: mloskot - define & use GGL exception
|
||||
throw std::logic_error("first_element in empty node");
|
||||
}
|
||||
return m_nodes.begin()->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief True if it is a leaf node
|
||||
*/
|
||||
virtual bool is_leaf() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Proyector for the 'i' node
|
||||
*/
|
||||
node_pointer get_node(unsigned int index)
|
||||
{
|
||||
return m_nodes[index].second;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Search for elements in 'box' in the Rtree. Add them to 'result'.
|
||||
* If exact_match is true only return the elements having as
|
||||
* key the box 'box'. Otherwise return everything inside 'box'.
|
||||
*/
|
||||
virtual void find(Box const& box, std::deque<Value>& result, bool const exact_match)
|
||||
{
|
||||
for (typename node_map::const_iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
if (is_overlapping(it->first, box))
|
||||
{
|
||||
it->second->find(box, result, exact_match);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return in 'result' all the leaves inside 'box'
|
||||
*/
|
||||
void find_leaves(Box const& box, typename std::vector<node_pointer>& result) const
|
||||
{
|
||||
for (typename node_map::const_iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
if (is_overlapping(it->first, box))
|
||||
{
|
||||
if (it->second->is_leaf())
|
||||
{
|
||||
result.push_back(it->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second->find_leaves(box, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Compute bounding box for this node
|
||||
*/
|
||||
virtual Box compute_box() const
|
||||
{
|
||||
if (m_nodes.empty())
|
||||
{
|
||||
return Box();
|
||||
}
|
||||
|
||||
Box result;
|
||||
geometry::assign_inverse(result);
|
||||
for(typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
||||
{
|
||||
geometry::expand(result, it->first);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Insert a value (not allowed for a node, only on leaves)
|
||||
*/
|
||||
virtual void insert(Box const&, Value const&)
|
||||
{
|
||||
// TODO: mloskot - define & use GGL exception
|
||||
throw std::logic_error("Insert in node!");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the envelopes of a node
|
||||
*/
|
||||
virtual std::vector<Box> get_boxes() const
|
||||
{
|
||||
std::vector<Box> result;
|
||||
for(typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
||||
{
|
||||
result.push_back(it->first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Recompute the bounding box
|
||||
*/
|
||||
void adjust_box(node_pointer const& node)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
for (typename node_map::iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it, index++)
|
||||
{
|
||||
if (it->second.get() == node.get())
|
||||
{
|
||||
m_nodes[index] = std::make_pair(node->compute_box(), node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Remove elements inside the 'box'
|
||||
*/
|
||||
virtual void remove(Box const& box)
|
||||
{
|
||||
for (typename node_map::iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
if (geometry::equals(it->first, box))
|
||||
{
|
||||
m_nodes.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Remove value in this leaf
|
||||
*/
|
||||
virtual void remove(Value const&)
|
||||
{
|
||||
// TODO: mloskot - define & use GGL exception
|
||||
throw std::logic_error("Can't remove a non-leaf node by value.");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Replace the node in the m_nodes vector and recompute the box
|
||||
*/
|
||||
void replace_node(node_pointer const& leaf, node_pointer& new_leaf)
|
||||
{
|
||||
unsigned int index = 0;
|
||||
for(typename node_map::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it, index++)
|
||||
{
|
||||
if (it->second.get() == leaf.get())
|
||||
{
|
||||
m_nodes[index] = std::make_pair(new_leaf->compute_box(), new_leaf);
|
||||
new_leaf->update_parent(new_leaf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: mloskot - define & use GGL exception
|
||||
throw std::logic_error("Node not found.");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add a child to this node
|
||||
*/
|
||||
virtual void add_node(Box const& box, node_pointer const& node)
|
||||
{
|
||||
m_nodes.push_back(std::make_pair(box, node));
|
||||
node->update_parent(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief add a value (not allowed in nodes, only on leaves)
|
||||
*/
|
||||
virtual void add_value(Box const&, Value const&)
|
||||
{
|
||||
// TODO: mloskot - define & use GGL exception
|
||||
throw std::logic_error("Can't add value to non-leaf node.");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add a child leaf to this node
|
||||
*/
|
||||
inline void add_leaf_node(Box const& box, leaf_pointer const& leaf)
|
||||
{
|
||||
m_nodes.push_back(std::make_pair(box, leaf));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Choose a node suitable for adding 'box'
|
||||
*/
|
||||
node_pointer choose_node(Box const& box)
|
||||
{
|
||||
if (m_nodes.size() == 0)
|
||||
{
|
||||
// TODO: mloskot - define & use GGL exception
|
||||
throw std::logic_error("Empty node trying to choose the least enlargement node.");
|
||||
}
|
||||
|
||||
typedef typename coordinate_type<Box>::type coordinate_type;
|
||||
|
||||
bool first = true;
|
||||
coordinate_type min_area = 0;
|
||||
coordinate_type min_diff_area = 0;
|
||||
node_pointer chosen_node;
|
||||
|
||||
// check for the least enlargement
|
||||
for (typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
||||
{
|
||||
coordinate_type const
|
||||
diff_area = coordinate_type(compute_union_area(box, it->first))
|
||||
- geometry::area(it->first);
|
||||
|
||||
if (first)
|
||||
{
|
||||
// it's the first time, we keep the first
|
||||
min_diff_area = diff_area;
|
||||
min_area = geometry::area(it->first);
|
||||
chosen_node = it->second;
|
||||
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (diff_area < min_diff_area)
|
||||
{
|
||||
min_diff_area = diff_area;
|
||||
min_area = geometry::area(it->first);
|
||||
chosen_node = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (diff_area == min_diff_area)
|
||||
{
|
||||
if (geometry::area(it->first) < min_area)
|
||||
{
|
||||
min_diff_area = diff_area;
|
||||
min_area = geometry::area(it->first);
|
||||
chosen_node = it->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chosen_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Empty the node
|
||||
*/
|
||||
virtual void empty_nodes()
|
||||
{
|
||||
m_nodes.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Projector for parent
|
||||
*/
|
||||
inline node_pointer get_parent() const
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Update the parent of all the childs
|
||||
*/
|
||||
void update_parent(node_pointer const& node)
|
||||
{
|
||||
for (typename node_map::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
||||
{
|
||||
it->second->set_parent(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set parent
|
||||
*/
|
||||
void set_parent(node_pointer const& node)
|
||||
{
|
||||
m_parent = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Value projector for leaf_node (not allowed for non-leaf nodes)
|
||||
*/
|
||||
virtual Value get_value(unsigned int) const
|
||||
{
|
||||
// TODO: mloskot - define & use GGL exception
|
||||
throw std::logic_error("No values in a non-leaf node.");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Box projector for node 'index'
|
||||
*/
|
||||
virtual Box get_box(unsigned int index) const
|
||||
{
|
||||
return m_nodes[index].first;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Box projector for node pointed by 'leaf'
|
||||
*/
|
||||
virtual Box get_box(node_pointer const& leaf) const
|
||||
{
|
||||
for (typename node_map::const_iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
if (it->second.get() == leaf.get())
|
||||
{
|
||||
return it->first;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: mloskot - define & use GGL exception
|
||||
throw std::logic_error("Node not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Children projector
|
||||
*/
|
||||
node_map get_nodes() const
|
||||
{
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get leaves for a node
|
||||
*/
|
||||
virtual std::vector<std::pair<Box, Value> > get_leaves() const
|
||||
{
|
||||
typedef std::vector<std::pair<Box, Value> > leaf_type;
|
||||
leaf_type leaf;
|
||||
|
||||
for (typename node_map::const_iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
leaf_type this_leaves = it->second->get_leaves();
|
||||
|
||||
for (typename leaf_type::iterator it_leaf = this_leaves.begin();
|
||||
it_leaf != this_leaves.end(); ++it_leaf)
|
||||
{
|
||||
leaf.push_back(*it_leaf);
|
||||
}
|
||||
}
|
||||
|
||||
return leaf;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Print Rtree subtree (mainly for debug)
|
||||
*/
|
||||
virtual void print() const
|
||||
{
|
||||
std::cerr << " --> Node --------" << std::endl;
|
||||
std::cerr << " Address: " << this << std::endl;
|
||||
std::cerr << " Level: " << m_level << std::endl;
|
||||
std::cerr << " Size: " << m_nodes.size() << std::endl;
|
||||
std::cerr << " | ";
|
||||
for(typename node_map::const_iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
|
||||
{
|
||||
if (this != it->second->get_parent().get())
|
||||
{
|
||||
std::cerr << "ERROR - " << this << " is not " << it->second->get_parent().get() << " ";
|
||||
}
|
||||
|
||||
std::cerr << "( " << geometry::get<min_corner, 0>(it->first) << " , "
|
||||
<< geometry::get<min_corner, 1>(it->first) << " ) x ";
|
||||
std::cerr << "( " << geometry::get<max_corner, 0>(it->first) << " , "
|
||||
<< geometry::get<max_corner, 1>(it->first) << " )";
|
||||
std::cerr << " | ";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
std::cerr << " --< Node --------" << std::endl;
|
||||
|
||||
// print child nodes
|
||||
std::cerr << " Children: " << std::endl;
|
||||
for (typename node_map::const_iterator it = m_nodes.begin();
|
||||
it != m_nodes.end(); ++it)
|
||||
{
|
||||
it->second->print();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// parent node
|
||||
node_pointer m_parent;
|
||||
|
||||
/// level of this node
|
||||
// TODO: mloskot - Why not std::size_t or node_map::size_type, same with member functions?
|
||||
unsigned int m_level;
|
||||
|
||||
/// child nodes
|
||||
node_map m_nodes;
|
||||
};
|
||||
|
||||
}}} // namespace boost::geometry::index
|
||||
|
||||
#endif // BOOST_GEOMETRY_EXTENSIONS_INDEX_RTREE_RTREE_NODE_HPP
|
272
boost/gil/extension/toolbox/hsl.hpp
Normal file
272
boost/gil/extension/toolbox/hsl.hpp
Normal file
|
@ -0,0 +1,272 @@
|
|||
// Copyright 2007 Christian Henning.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef GIL_HSL_H
|
||||
#define GIL_HSL_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file
|
||||
/// \brief Support for HSL color space
|
||||
/// \author Christian Henning \n
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/gil/gil_all.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
/// \addtogroup ColorNameModel
|
||||
/// \{
|
||||
namespace hsl_color_space
|
||||
{
|
||||
/// \brief Hue
|
||||
struct hue_t {};
|
||||
/// \brief Saturation
|
||||
struct saturation_t {};
|
||||
/// \brief Lightness
|
||||
struct lightness_t {};
|
||||
}
|
||||
/// \}
|
||||
|
||||
/// \ingroup ColorSpaceModel
|
||||
typedef mpl::vector3< hsl_color_space::hue_t
|
||||
, hsl_color_space::saturation_t
|
||||
, hsl_color_space::lightness_t
|
||||
> hsl_t;
|
||||
|
||||
/// \ingroup LayoutModel
|
||||
typedef layout<hsl_t> hsl_layout_t;
|
||||
|
||||
|
||||
GIL_DEFINE_ALL_TYPEDEFS( 32f, hsl );
|
||||
|
||||
/// \ingroup ColorConvert
|
||||
/// \brief RGB to HSL
|
||||
template <>
|
||||
struct default_color_converter_impl< rgb_t, hsl_t >
|
||||
{
|
||||
template <typename P1, typename P2>
|
||||
void operator()( const P1& src, P2& dst ) const
|
||||
{
|
||||
using namespace hsl_color_space;
|
||||
|
||||
// only bits32f for hsl is supported
|
||||
bits32f temp_red = channel_convert<bits32f>( get_color( src, red_t() ));
|
||||
bits32f temp_green = channel_convert<bits32f>( get_color( src, green_t() ));
|
||||
bits32f temp_blue = channel_convert<bits32f>( get_color( src, blue_t() ));
|
||||
|
||||
bits32f hue, saturation, lightness;
|
||||
bits32f min_color, max_color;
|
||||
|
||||
if( temp_red < temp_green )
|
||||
{
|
||||
min_color = std::min( temp_blue, temp_red );
|
||||
max_color = std::max( temp_blue, temp_green );
|
||||
}
|
||||
else
|
||||
{
|
||||
min_color = std::min( temp_blue, temp_green );
|
||||
max_color = std::max( temp_blue, temp_red );
|
||||
}
|
||||
|
||||
if ( max_color - min_color < 0.001 )
|
||||
{
|
||||
// rgb color is gray
|
||||
|
||||
hue = 0.f;
|
||||
saturation = 0.f;
|
||||
|
||||
// doesn't matter which rgb channel we use.
|
||||
lightness = temp_red;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
bits32f diff = max_color - min_color;
|
||||
|
||||
// lightness calculation
|
||||
|
||||
lightness = ( min_color + max_color ) / 2.f;
|
||||
|
||||
// saturation calculation
|
||||
|
||||
if( lightness < 0.5f )
|
||||
{
|
||||
saturation = diff
|
||||
/ ( min_color + max_color );
|
||||
}
|
||||
else
|
||||
{
|
||||
saturation = ( max_color - min_color )
|
||||
/ ( 2.f - diff );
|
||||
|
||||
}
|
||||
|
||||
// hue calculation
|
||||
if( std::abs( max_color - temp_red ) < 0.0001f )
|
||||
{
|
||||
// max_color is red
|
||||
hue = ( temp_green - temp_blue )
|
||||
/ diff;
|
||||
|
||||
}
|
||||
else if( std::abs( max_color - temp_green) < 0.0001f )
|
||||
{
|
||||
// max_color is green
|
||||
// 2.0 + (b - r) / (maxColor - minColor)
|
||||
hue = 2.f
|
||||
+ ( temp_blue - temp_red )
|
||||
/ diff;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// max_color is blue
|
||||
// 4.0 + (r - g) / (maxColor - minColor)
|
||||
hue = 4.f
|
||||
+ ( temp_red - temp_green )
|
||||
/ diff;
|
||||
}
|
||||
|
||||
hue /= 6.f;
|
||||
|
||||
if( hue < 0.f )
|
||||
{
|
||||
hue += 1.f;
|
||||
}
|
||||
}
|
||||
|
||||
get_color( dst,hue_t() ) = hue;
|
||||
get_color( dst,saturation_t() ) = saturation;
|
||||
get_color( dst,lightness_t() ) = lightness;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ColorConvert
|
||||
/// \brief HSL to RGB
|
||||
template <>
|
||||
struct default_color_converter_impl<hsl_t,rgb_t>
|
||||
{
|
||||
template <typename P1, typename P2>
|
||||
void operator()( const P1& src, P2& dst) const
|
||||
{
|
||||
using namespace hsl_color_space;
|
||||
|
||||
bits32f red, green, blue;
|
||||
|
||||
if( std::abs( get_color( src, saturation_t() )) < 0.0001 )
|
||||
{
|
||||
// If saturation is 0, the color is a shade of gray
|
||||
red = get_color( src, lightness_t() );
|
||||
green = get_color( src, lightness_t() );
|
||||
blue = get_color( src, lightness_t() );
|
||||
}
|
||||
else
|
||||
{
|
||||
float temp1, temp2;
|
||||
float tempr, tempg, tempb;
|
||||
|
||||
//Set the temporary values
|
||||
if( get_color( src, lightness_t() ) < 0.5 )
|
||||
{
|
||||
temp2 = get_color( src, lightness_t() )
|
||||
* ( 1.f + get_color( src, saturation_t() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
temp2 = ( get_color( src, lightness_t() ) + get_color( src, saturation_t() ))
|
||||
- ( get_color( src, lightness_t() ) * get_color( src, saturation_t() ));
|
||||
}
|
||||
|
||||
temp1 = 2.f
|
||||
* get_color( src, lightness_t() )
|
||||
- temp2;
|
||||
|
||||
tempr = get_color( src, hue_t() ) + 1.f / 3.f;
|
||||
|
||||
if( tempr > 1.f )
|
||||
{
|
||||
tempr--;
|
||||
}
|
||||
|
||||
tempg = get_color( src, hue_t() );
|
||||
tempb = get_color( src, hue_t() ) - 1.f / 3.f;
|
||||
|
||||
if( tempb < 0.f )
|
||||
{
|
||||
tempb++;
|
||||
}
|
||||
|
||||
//Red
|
||||
if( tempr < 1.f / 6.f )
|
||||
{
|
||||
red = temp1 + ( temp2 - temp1 ) * 6.f * tempr;
|
||||
}
|
||||
else if( tempr < 0.5f )
|
||||
{
|
||||
red = temp2;
|
||||
}
|
||||
else if( tempr < 2.f / 3.f )
|
||||
{
|
||||
red = temp1 + (temp2 - temp1)
|
||||
* (( 2.f / 3.f ) - tempr) * 6.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
red = temp1;
|
||||
}
|
||||
|
||||
//Green
|
||||
if( tempg < 1.f / 6.f )
|
||||
{
|
||||
green = temp1 + ( temp2 - temp1 ) * 6.f * tempg;
|
||||
}
|
||||
else if( tempg < 0.5f )
|
||||
{
|
||||
green = temp2;
|
||||
}
|
||||
else if( tempg < 2.f / 3.f )
|
||||
{
|
||||
green = temp1 + ( temp2 - temp1 )
|
||||
* (( 2.f / 3.f ) - tempg) * 6.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
green = temp1;
|
||||
}
|
||||
|
||||
//Blue
|
||||
if( tempb < 1.f / 6.f )
|
||||
{
|
||||
blue = temp1 + (temp2 - temp1) * 6.f * tempb;
|
||||
}
|
||||
else if( tempb < 0.5f )
|
||||
{
|
||||
blue = temp2;
|
||||
}
|
||||
else if( tempb < 2.f / 3.f )
|
||||
{
|
||||
blue = temp1 + (temp2 - temp1)
|
||||
* (( 2.f / 3.f ) - tempb) * 6.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
blue = temp1;
|
||||
}
|
||||
}
|
||||
|
||||
get_color(dst,red_t()) =
|
||||
channel_convert<typename color_element_type< P2, red_t >::type>( red );
|
||||
get_color(dst,green_t())=
|
||||
channel_convert<typename color_element_type< P2, green_t >::type>( green );
|
||||
get_color(dst,blue_t()) =
|
||||
channel_convert<typename color_element_type< P2, blue_t >::type>( blue );
|
||||
}
|
||||
};
|
||||
|
||||
} } // namespace boost::gil
|
||||
|
||||
#endif // GIL_HSL_H
|
245
boost/gil/extension/toolbox/hsv.hpp
Normal file
245
boost/gil/extension/toolbox/hsv.hpp
Normal file
|
@ -0,0 +1,245 @@
|
|||
// Copyright 2004 Christian Henning.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/*************************************************************************************************/
|
||||
|
||||
#ifndef GIL_HSV_H
|
||||
#define GIL_HSV_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// \file
|
||||
/// \brief Support for HSV color space
|
||||
/// \author Christian Henning \n
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/cast.hpp>
|
||||
#include <boost/gil/gil_all.hpp>
|
||||
|
||||
namespace boost { namespace gil {
|
||||
|
||||
/// \addtogroup ColorNameModel
|
||||
/// \{
|
||||
namespace hsv_color_space
|
||||
{
|
||||
/// \brief Hue
|
||||
struct hue_t {};
|
||||
/// \brief Saturation
|
||||
struct saturation_t{};
|
||||
/// \brief Value
|
||||
struct value_t {};
|
||||
}
|
||||
/// \}
|
||||
|
||||
/// \ingroup ColorSpaceModel
|
||||
typedef mpl::vector3< hsv_color_space::hue_t
|
||||
, hsv_color_space::saturation_t
|
||||
, hsv_color_space::value_t
|
||||
> hsv_t;
|
||||
|
||||
/// \ingroup LayoutModel
|
||||
typedef layout<hsv_t> hsv_layout_t;
|
||||
|
||||
|
||||
GIL_DEFINE_ALL_TYPEDEFS( 32f, hsv )
|
||||
|
||||
/// \ingroup ColorConvert
|
||||
/// \brief RGB to HSV
|
||||
template <>
|
||||
struct default_color_converter_impl< rgb_t, hsv_t >
|
||||
{
|
||||
template <typename P1, typename P2>
|
||||
void operator()( const P1& src, P2& dst ) const
|
||||
{
|
||||
using namespace hsv_color_space;
|
||||
|
||||
// only bits32f for hsv is supported
|
||||
bits32f temp_red = channel_convert<bits32f>( get_color( src, red_t() ));
|
||||
bits32f temp_green = channel_convert<bits32f>( get_color( src, green_t() ));
|
||||
bits32f temp_blue = channel_convert<bits32f>( get_color( src, blue_t() ));
|
||||
|
||||
bits32f hue, saturation, value;
|
||||
bits32f min_color, max_color;
|
||||
|
||||
if( temp_red < temp_green )
|
||||
{
|
||||
min_color = std::min( temp_blue, temp_red );
|
||||
max_color = std::max( temp_blue, temp_green );
|
||||
}
|
||||
else
|
||||
{
|
||||
min_color = std::min( temp_blue, temp_green );
|
||||
max_color = std::max( temp_blue, temp_red );
|
||||
}
|
||||
|
||||
value = max_color;
|
||||
|
||||
bits32f diff = max_color - min_color;
|
||||
|
||||
if( max_color < 0.0001f )
|
||||
{
|
||||
saturation = 0.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
saturation = diff / max_color;
|
||||
}
|
||||
|
||||
|
||||
if( saturation < 0.0001f )
|
||||
{
|
||||
//it doesn't matter what value it has
|
||||
hue = 0.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( temp_red == max_color )
|
||||
{
|
||||
hue = ( temp_green - temp_blue )
|
||||
/ diff;
|
||||
}
|
||||
else if( temp_green == max_color )
|
||||
{
|
||||
hue = 2.f + ( temp_blue - temp_red )
|
||||
/ diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
hue = 4.f + ( temp_red - temp_green )
|
||||
/ diff;
|
||||
}
|
||||
|
||||
//to bring it to a number between 0 and 1
|
||||
hue /= 6.f;
|
||||
|
||||
if( hue < 0.f )
|
||||
{
|
||||
hue++;
|
||||
}
|
||||
}
|
||||
|
||||
get_color( dst, hue_t() ) = hue;
|
||||
get_color( dst, saturation_t() ) = saturation;
|
||||
get_color( dst, value_t() ) = value;
|
||||
}
|
||||
};
|
||||
|
||||
/// \ingroup ColorConvert
|
||||
/// \brief HSV to RGB
|
||||
template <>
|
||||
struct default_color_converter_impl<hsv_t,rgb_t>
|
||||
{
|
||||
template <typename P1, typename P2>
|
||||
void operator()( const P1& src, P2& dst) const
|
||||
{
|
||||
using namespace hsv_color_space;
|
||||
|
||||
bits32f red, green, blue;
|
||||
|
||||
//If saturation is 0, the color is a shade of gray
|
||||
if( std::abs( get_color( src, saturation_t() )) < 0.0001f )
|
||||
{
|
||||
// If saturation is 0, the color is a shade of gray
|
||||
red = get_color( src, value_t() );
|
||||
green = get_color( src, value_t() );
|
||||
blue = get_color( src, value_t() );
|
||||
}
|
||||
else
|
||||
{
|
||||
bits32f frac, p, q, t, h;
|
||||
bits32 i;
|
||||
|
||||
//to bring hue to a number between 0 and 6, better for the calculations
|
||||
h = get_color( src, hue_t() );
|
||||
h *= 6.f;
|
||||
|
||||
i = static_cast<bits32>( floor( h ));
|
||||
|
||||
frac = h - i;
|
||||
|
||||
// p = value * (1 - saturation)
|
||||
p = get_color( src, value_t() )
|
||||
* ( 1.f - get_color( src, saturation_t() ));
|
||||
|
||||
// q = value * (1 - saturation * hue_frac)
|
||||
// it drops with increasing distance from floor(hue)
|
||||
q = get_color( src, value_t() )
|
||||
* ( 1.f - ( get_color( src, saturation_t() ) * frac ));
|
||||
|
||||
// t = value * (1 - (saturation * (1 - hue_frac))
|
||||
// it grows with increasing distance from floor(hue)
|
||||
t = get_color( src, value_t() )
|
||||
* ( 1.f - ( get_color( src, saturation_t() ) * ( 1.f - frac )));
|
||||
|
||||
switch( i % 6 )
|
||||
{
|
||||
case 0: // red to yellow
|
||||
{
|
||||
red = get_color( src, value_t() );
|
||||
green = t;
|
||||
blue = p;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: // yellow to green
|
||||
{
|
||||
red = q;
|
||||
green = get_color( src, value_t() );
|
||||
blue = p;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // green to cyan
|
||||
{
|
||||
red = p;
|
||||
green = get_color( src, value_t() );
|
||||
blue = t;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: // cyan to blue
|
||||
{
|
||||
red = p;
|
||||
green = q;
|
||||
blue = get_color( src, value_t() );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: // blue to magenta
|
||||
{
|
||||
red = t;
|
||||
green = p;
|
||||
blue = get_color( src, value_t() );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: // magenta to red
|
||||
{
|
||||
red = get_color( src, value_t() );
|
||||
green = p;
|
||||
blue = q;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
get_color(dst,red_t()) =
|
||||
channel_convert<typename color_element_type< P2, red_t >::type>( red );
|
||||
get_color(dst,green_t())=
|
||||
channel_convert<typename color_element_type< P2, green_t >::type>( green );
|
||||
get_color(dst,blue_t()) =
|
||||
channel_convert<typename color_element_type< P2, blue_t >::type>( blue );
|
||||
}
|
||||
};
|
||||
|
||||
} } // namespace boost::gil
|
||||
|
||||
#endif // GIL_HSV_H
|
2
configure
vendored
2
configure
vendored
|
@ -1,3 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
python scons/scons.py configure $@
|
||||
python scons/scons.py --implicit-deps-changed configure "$@"
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
import os
|
||||
from copy import copy
|
||||
|
@ -36,12 +36,11 @@ demo_env = env.Clone()
|
|||
demo_env['CXXFLAGS'] = copy(env['LIBMAPNIK_CXXFLAGS'])
|
||||
|
||||
if env['HAS_CAIRO']:
|
||||
demo_env.PrependUnique(CPPPATH=env['CAIROMM_CPPPATHS'])
|
||||
demo_env.PrependUnique(CPPPATH=env['CAIRO_CPPPATHS'])
|
||||
demo_env.Append(CXXFLAGS = '-DHAVE_CAIRO')
|
||||
|
||||
libraries = copy(env['LIBMAPNIK_LIBS'])
|
||||
boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
|
||||
libraries.extend([boost_program_options,'mapnik'])
|
||||
libraries.append('mapnik')
|
||||
|
||||
rundemo = demo_env.Program('rundemo', source, LIBS=libraries, LINKFLAGS=env["CUSTOM_LDFLAGS"])
|
||||
|
||||
|
|
|
@ -21,6 +21,13 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/rule.hpp>
|
||||
#include <mapnik/line_symbolizer.hpp>
|
||||
#include <mapnik/polygon_symbolizer.hpp>
|
||||
#include <mapnik/text_symbolizer.hpp>
|
||||
#include <mapnik/feature_type_style.hpp>
|
||||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/datasource_cache.hpp>
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
|
@ -30,9 +37,8 @@
|
|||
#include <mapnik/config_error.hpp>
|
||||
|
||||
#if defined(HAVE_CAIRO)
|
||||
// cairo
|
||||
#include <mapnik/cairo_renderer.hpp>
|
||||
#include <cairomm/surface.h>
|
||||
#include <mapnik/cairo_context.hpp>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
@ -42,23 +48,28 @@ int main ( int argc , char** argv)
|
|||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cout << "usage: ./rundemo <mapnik_install_dir>\nUsually /usr/local/lib/mapnik\n";
|
||||
std::cout << "usage: ./rundemo <mapnik_install_dir>\nUsually /usr/local\n";
|
||||
std::cout << "Warning: ./rundemo looks for data in ../data/,\nTherefore must be run from within the demo/c++ folder.\n";
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
using namespace mapnik;
|
||||
const std::string srs_lcc="+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 \
|
||||
+datum=NAD83 +units=m +no_defs";
|
||||
const std::string srs_merc="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 \
|
||||
+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";
|
||||
|
||||
try {
|
||||
std::cout << " running demo ... \n";
|
||||
std::string mapnik_dir(argv[1]);
|
||||
std::cout << " looking for 'shape.input' plugin in... " << mapnik_dir << "/input/" << "\n";
|
||||
datasource_cache::instance()->register_datasources(mapnik_dir + "/input/");
|
||||
std::cout << " looking for DejaVuSans font in... " << mapnik_dir << "/fonts/DejaVuSans.ttf" << "\n";
|
||||
freetype_engine::register_font(mapnik_dir + "/fonts/DejaVuSans.ttf");
|
||||
std::cout << " looking for 'shape.input' plugin in... " << mapnik_dir << "/lib/mapnik/input/" << "\n";
|
||||
datasource_cache::instance().register_datasources(mapnik_dir + "/lib/mapnik/input/");
|
||||
std::cout << " looking for DejaVuSans font in... " << mapnik_dir << "/lib/mapnik/fonts/DejaVuSans.ttf" << "\n";
|
||||
freetype_engine::register_font(mapnik_dir + "/lib/mapnik/fonts/DejaVuSans.ttf");
|
||||
|
||||
Map m(800,600);
|
||||
m.set_background(color_factory::from_string("white"));
|
||||
|
||||
m.set_background(parse_color("white"));
|
||||
m.set_srs(srs_merc);
|
||||
// create styles
|
||||
|
||||
// Provinces (polygon)
|
||||
|
@ -178,8 +189,9 @@ int main ( int argc , char** argv)
|
|||
p["encoding"]="latin1";
|
||||
|
||||
layer lyr("Provinces");
|
||||
lyr.set_datasource(datasource_cache::instance()->create(p));
|
||||
lyr.set_datasource(datasource_cache::instance().create(p));
|
||||
lyr.add_style("provinces");
|
||||
lyr.set_srs(srs_lcc);
|
||||
m.addLayer(lyr);
|
||||
}
|
||||
|
||||
|
@ -189,7 +201,8 @@ int main ( int argc , char** argv)
|
|||
p["type"]="shape";
|
||||
p["file"]="../data/qcdrainage";
|
||||
layer lyr("Quebec Hydrography");
|
||||
lyr.set_datasource(datasource_cache::instance()->create(p));
|
||||
lyr.set_datasource(datasource_cache::instance().create(p));
|
||||
lyr.set_srs(srs_lcc);
|
||||
lyr.add_style("drainage");
|
||||
m.addLayer(lyr);
|
||||
}
|
||||
|
@ -198,9 +211,9 @@ int main ( int argc , char** argv)
|
|||
parameters p;
|
||||
p["type"]="shape";
|
||||
p["file"]="../data/ontdrainage";
|
||||
|
||||
layer lyr("Ontario Hydrography");
|
||||
lyr.set_datasource(datasource_cache::instance()->create(p));
|
||||
lyr.set_datasource(datasource_cache::instance().create(p));
|
||||
lyr.set_srs(srs_lcc);
|
||||
lyr.add_style("drainage");
|
||||
m.addLayer(lyr);
|
||||
}
|
||||
|
@ -211,7 +224,8 @@ int main ( int argc , char** argv)
|
|||
p["type"]="shape";
|
||||
p["file"]="../data/boundaries_l";
|
||||
layer lyr("Provincial borders");
|
||||
lyr.set_datasource(datasource_cache::instance()->create(p));
|
||||
lyr.set_srs(srs_lcc);
|
||||
lyr.set_datasource(datasource_cache::instance().create(p));
|
||||
lyr.add_style("provlines");
|
||||
m.addLayer(lyr);
|
||||
}
|
||||
|
@ -222,7 +236,8 @@ int main ( int argc , char** argv)
|
|||
p["type"]="shape";
|
||||
p["file"]="../data/roads";
|
||||
layer lyr("Roads");
|
||||
lyr.set_datasource(datasource_cache::instance()->create(p));
|
||||
lyr.set_srs(srs_lcc);
|
||||
lyr.set_datasource(datasource_cache::instance().create(p));
|
||||
lyr.add_style("smallroads");
|
||||
lyr.add_style("road-border");
|
||||
lyr.add_style("road-fill");
|
||||
|
@ -238,22 +253,22 @@ int main ( int argc , char** argv)
|
|||
p["file"]="../data/popplaces";
|
||||
p["encoding"] = "latin1";
|
||||
layer lyr("Populated Places");
|
||||
lyr.set_datasource(datasource_cache::instance()->create(p));
|
||||
lyr.set_srs(srs_lcc);
|
||||
lyr.set_datasource(datasource_cache::instance().create(p));
|
||||
lyr.add_style("popplaces");
|
||||
m.addLayer(lyr);
|
||||
}
|
||||
|
||||
m.zoom_to_box(box2d<double>(1405120.04127408,-247003.813399447,
|
||||
1706357.31328276,-25098.593149577));
|
||||
m.zoom_to_box(box2d<double>(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855));
|
||||
|
||||
image_32 buf(m.width(),m.height());
|
||||
agg_renderer<image_32> ren(m,buf);
|
||||
ren.apply();
|
||||
|
||||
save_to_file<image_data_32>(buf.data(),"demo.jpg","jpeg");
|
||||
save_to_file<image_data_32>(buf.data(),"demo.png","png");
|
||||
save_to_file<image_data_32>(buf.data(),"demo256.png","png256");
|
||||
save_to_file<image_data_32>(buf.data(),"demo.tif","tiff");
|
||||
save_to_file(buf,"demo.jpg","jpeg");
|
||||
save_to_file(buf,"demo.png","png");
|
||||
save_to_file(buf,"demo256.png","png8");
|
||||
save_to_file(buf,"demo.tif","tiff");
|
||||
|
||||
std::cout << "Three maps have been rendered using AGG in the current directory:\n"
|
||||
"- demo.jpg\n"
|
||||
|
@ -263,24 +278,31 @@ int main ( int argc , char** argv)
|
|||
"Have a look!\n";
|
||||
|
||||
#if defined(HAVE_CAIRO)
|
||||
Cairo::RefPtr<Cairo::ImageSurface> image_surface;
|
||||
// save to pdf/svg files
|
||||
save_to_cairo_file(m,"cairo-demo.pdf");
|
||||
save_to_cairo_file(m,"cairo-demo.svg");
|
||||
|
||||
image_surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, m.width(),m.height());
|
||||
cairo_renderer<Cairo::Surface> png_render(m, image_surface);
|
||||
/* we could also do:
|
||||
|
||||
save_to_cairo_file(m,"cairo-demo.png");
|
||||
|
||||
but instead let's build up a surface for more flexibility
|
||||
*/
|
||||
|
||||
cairo_surface_ptr image_surface(
|
||||
cairo_image_surface_create(CAIRO_FORMAT_ARGB32,m.width(),m.height()),
|
||||
cairo_surface_closer());
|
||||
double scale_factor = 1.0;
|
||||
cairo_ptr image_context = (create_context(image_surface));
|
||||
mapnik::cairo_renderer<cairo_ptr> png_render(m,image_context,scale_factor);
|
||||
png_render.apply();
|
||||
image_surface->write_to_png("cairo-demo.png");
|
||||
|
||||
// we can now write to png with cairo functionality
|
||||
cairo_surface_write_to_png(&*image_surface, "cairo-demo.png");
|
||||
// but we can also benefit from quantization by converting
|
||||
// to a mapnik image object and then saving that
|
||||
image_32 im(image_surface);
|
||||
save_to_file(im, "cairo-demo256.png","png256");
|
||||
|
||||
Cairo::RefPtr<Cairo::Surface> surface;
|
||||
surface = Cairo::PdfSurface::create("cairo-demo.pdf", m.width(),m.height());
|
||||
cairo_renderer<Cairo::Surface> pdf_render(m, surface);
|
||||
pdf_render.apply();
|
||||
|
||||
surface = Cairo::SvgSurface::create("cairo-demo.svg", m.width(),m.height());
|
||||
cairo_renderer<Cairo::Surface> svg_render(m, surface);
|
||||
svg_render.apply();
|
||||
save_to_file(im, "cairo-demo256.png","png8");
|
||||
cairo_surface_finish(&*image_surface);
|
||||
|
||||
std::cout << "Three maps have been rendered using Cairo in the current directory:\n"
|
||||
"- cairo-demo.png\n"
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
# $Id$
|
||||
|
||||
This directory contains a sample python script implementing the Mapnik API.
|
||||
|
||||
The script is thoroughly commented and also acts as a mini tutorial. Reading
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
#
|
||||
# This file is part of Mapnik (c++ mapping toolkit)
|
||||
# Copyright (C) 2005 Jean-Francois Doyon
|
||||
|
@ -186,7 +186,7 @@ m.layers.append(provlines_lyr)
|
|||
|
||||
roads34_lyr = mapnik.Layer('Roads')
|
||||
roads34_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
|
||||
# create roads datasource (we're going to re-use it later)
|
||||
# create roads datasource (we're going to re-use it later)
|
||||
|
||||
roads34_lyr.datasource = mapnik.Shapefile(file='../data/roads')
|
||||
|
||||
|
@ -221,7 +221,7 @@ m.layers.append(roads34_lyr)
|
|||
roads2_lyr = mapnik.Layer('Roads')
|
||||
roads2_lyr.srs = "+proj=lcc +ellps=GRS80 +lat_0=49 +lon_0=-95 +lat+1=49 +lat_2=77 +datum=NAD83 +units=m +no_defs"
|
||||
# Just get a copy from roads34_lyr
|
||||
roads2_lyr.datasource = roads34_lyr.datasource
|
||||
roads2_lyr.datasource = roads34_lyr.datasource
|
||||
|
||||
roads2_style_1 = mapnik.Style()
|
||||
roads2_rule_1 = mapnik.Rule()
|
||||
|
@ -306,7 +306,7 @@ popplaces_text_symbolizer = mapnik.TextSymbolizer(mapnik.Expression("[GEONAME]")
|
|||
# We set a "halo" around the text, which looks like an outline if thin enough,
|
||||
# or an outright background if large enough.
|
||||
popplaces_text_symbolizer.label_placement= mapnik.label_placement.POINT_PLACEMENT
|
||||
popplaces_text_symbolizer.halo_fill = mapnik.Color('white')
|
||||
popplaces_text_symbolizer.halo_fill = mapnik.Color(255,255,200)
|
||||
popplaces_text_symbolizer.halo_radius = 1
|
||||
popplaces_text_symbolizer.avoid_edges = True
|
||||
#popplaces_text_symbolizer.minimum_padding = 30
|
||||
|
@ -322,7 +322,7 @@ m.layers.append(popplaces_lyr)
|
|||
# Draw map
|
||||
|
||||
# Set the initial extent of the map in 'master' spherical Mercator projection
|
||||
m.zoom_to_box(mapnik.Box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855))
|
||||
m.zoom_to_box(mapnik.Box2d(-8024477.28459,5445190.38849,-7381388.20071,5662941.44855))
|
||||
|
||||
# Render map
|
||||
im = mapnik.Image(m.width,m.height)
|
||||
|
@ -354,7 +354,7 @@ images_.append('demo.tif')
|
|||
|
||||
# Render cairo examples
|
||||
if HAS_PYCAIRO_MODULE and mapnik.has_pycairo():
|
||||
|
||||
|
||||
svg_surface = cairo.SVGSurface('demo.svg', m.width,m.height)
|
||||
mapnik.render(m, svg_surface)
|
||||
svg_surface.finish()
|
||||
|
@ -368,7 +368,7 @@ if HAS_PYCAIRO_MODULE and mapnik.has_pycairo():
|
|||
postscript_surface = cairo.PSSurface('demo.ps', m.width,m.height)
|
||||
mapnik.render(m, postscript_surface)
|
||||
images_.append('demo.ps')
|
||||
postscript_surface.finish()
|
||||
postscript_surface.finish()
|
||||
|
||||
image_surface = cairo.ImageSurface(cairo.FORMAT_RGB24, m.width, m.height)
|
||||
mapnik.render(m, image_surface)
|
||||
|
@ -381,12 +381,12 @@ if HAS_PYCAIRO_MODULE and mapnik.has_pycairo():
|
|||
image_surface.write_to_png('demo_cairo_argb32.png')
|
||||
images_.append('demo_cairo_argb32.png')
|
||||
image_surface.finish()
|
||||
|
||||
|
||||
else:
|
||||
print '\n\nPycairo not available...',
|
||||
if mapnik.has_cairo():
|
||||
print ' will render Cairo formats using alternative method'
|
||||
|
||||
|
||||
mapnik.render_to_file(m,'demo.pdf')
|
||||
images_.append('demo.pdf')
|
||||
mapnik.render_to_file(m,'demo.ps')
|
||||
|
@ -399,7 +399,7 @@ else:
|
|||
images_.append('demo_cairo_argb.png')
|
||||
|
||||
print "\n\n", len(images_), "maps have been rendered in the current directory:"
|
||||
|
||||
|
||||
for im_ in images_:
|
||||
print "-", im_
|
||||
|
||||
|
|
23
demo/simple-renderer/render.py
Executable file
23
demo/simple-renderer/render.py
Executable file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import mapnik
|
||||
|
||||
def render(input_file, output_file, width=800, height=800, bbox=None):
|
||||
m = mapnik.Map(width, height)
|
||||
mapnik.load_map(m, input_file, False)
|
||||
if bbox is not None:
|
||||
m.zoom_to_box(bbox)
|
||||
else:
|
||||
m.zoom_all()
|
||||
mapnik.render_to_file(m, output_file)
|
||||
|
||||
if len(sys.argv) == 2:
|
||||
render(sys.argv[1], "output.png")
|
||||
elif len(sys.argv) == 3:
|
||||
render(sys.argv[1], sys.argv[2])
|
||||
elif len(sys.argv) == 5:
|
||||
render(sys.argv[1], sys.argv[2], int(sys.argv[3]), int(sys.argv[4]))
|
||||
else:
|
||||
print "usage: %s style_file [output_file] [width height]" % sys.argv[0]
|
||||
sys.exit(1)
|
|
@ -42,7 +42,7 @@ road_rule.symbols.append(LineSymbolizer(road_stroke))
|
|||
road_style.rules.append(road_rule);
|
||||
|
||||
#Road text
|
||||
text_symbolizer = TextSymbolizer('NAME', 'DejaVu Sans Book', 20, Color('black'))
|
||||
text_symbolizer = TextSymbolizer(Expression('[NAME]'), 'DejaVu Sans Book', 20, Color('black'))
|
||||
text_symbolizer.label_placement=label_placement.LINE_PLACEMENT
|
||||
text_symbolizer.minimum_distance = 0
|
||||
#text_symbolizer.max_char_angle_delta = 40
|
||||
|
@ -77,6 +77,6 @@ im = Image(m.width,m.height)
|
|||
render(m, im)
|
||||
|
||||
# Save image to file
|
||||
save_to_file('output.png', 'png',im) # true-colour RGBA
|
||||
im.save('output.png') # true-colour RGBA
|
||||
|
||||
print "Done\n"
|
||||
|
|
|
@ -43,7 +43,7 @@ road_rule.symbols.append(LineSymbolizer(road_stroke))
|
|||
road_style.rules.append(road_rule);
|
||||
|
||||
#Road text
|
||||
text_symbolizer = TextSymbolizer('NAME', 'DejaVu Sans Book', 10, Color('black'))
|
||||
text_symbolizer = TextSymbolizer(Expression('[NAME]'), 'DejaVu Sans Book', 10, Color('black'))
|
||||
text_symbolizer.label_placement=label_placement.LINE_PLACEMENT
|
||||
text_symbolizer.minimum_distance = 0
|
||||
#text_symbolizer.max_char_angle_delta = 40
|
||||
|
@ -78,6 +78,6 @@ im = Image(m.width,m.height)
|
|||
render(m, im)
|
||||
|
||||
# Save image to file
|
||||
save_to_file('output.png', 'png',im) # true-colour RGBA
|
||||
im.save('output.png') # true-colour RGBA
|
||||
|
||||
print "Done\n"
|
||||
|
|
|
@ -44,7 +44,7 @@ road_rule.symbols.append(LineSymbolizer(road_stroke))
|
|||
road_style.rules.append(road_rule);
|
||||
|
||||
#Road text
|
||||
text_symbolizer = TextSymbolizer('NAME', 'DejaVu Sans Book', 10, Color('black'))
|
||||
text_symbolizer = TextSymbolizer(Expression('[NAME]'), 'DejaVu Sans Book', 10, Color('black'))
|
||||
text_symbolizer.label_placement=label_placement.LINE_PLACEMENT
|
||||
text_symbolizer.minimum_distance = 0
|
||||
#text_symbolizer.max_char_angle_delta = 40
|
||||
|
@ -79,6 +79,6 @@ im = Image(m.width,m.height)
|
|||
render(m, im)
|
||||
|
||||
# Save image to file
|
||||
save_to_file('output.png', 'png',im) # true-colour RGBA
|
||||
im.save('output.png') # true-colour RGBA
|
||||
|
||||
print "Done\n"
|
||||
|
|
|
@ -43,7 +43,7 @@ road_rule.symbols.append(LineSymbolizer(road_stroke))
|
|||
road_style.rules.append(road_rule);
|
||||
|
||||
#Road text
|
||||
text_symbolizer = TextSymbolizer('NAME', 'DejaVu Sans Book', 10, Color('black'))
|
||||
text_symbolizer = TextSymbolizer(Expression('[NAME]'), 'DejaVu Sans Book', 10, Color('black'))
|
||||
text_symbolizer.label_placement=label_placement.LINE_PLACEMENT
|
||||
text_symbolizer.minimum_distance = 0
|
||||
#text_symbolizer.max_char_angle_delta = 40
|
||||
|
@ -77,6 +77,6 @@ im = Image(m.width,m.height)
|
|||
render(m, im)
|
||||
|
||||
# Save image to file
|
||||
save_to_file('output.png', 'png',im) # true-colour RGBA
|
||||
im.save('output.png') # true-colour RGBA
|
||||
|
||||
print "Done\n"
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#include "about_dialog.hpp"
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
|
||||
#if !defined ABOUT_DIALOG_HPP
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
Import ('env')
|
||||
import os
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#include "info_dialog.hpp"
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
|
||||
#ifndef INFO_DIALOG_HPP
|
||||
|
|
|
@ -17,11 +17,12 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#include "layer_info_dialog.hpp"
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/params.hpp>
|
||||
#include <mapnik/params_impl.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
|
||||
#ifndef LAYER_INFO_DIALOG_HPP
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#include <QtGui>
|
||||
#include "layerdelegate.hpp"
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
#ifndef LAYER_DELEGATE_HPP
|
||||
#define LAYER_DELEGATE_HPP
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
|
||||
#include "layerlistmodel.hpp"
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
|
||||
#ifndef LAYER_LIST_MODEL_HPP
|
||||
|
@ -26,7 +25,9 @@
|
|||
#include <QAbstractListModel>
|
||||
#include <QModelIndex>
|
||||
#include <QVariant>
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <mapnik/map.hpp>
|
||||
#endif
|
||||
#include <boost/optional/optional.hpp>
|
||||
|
||||
class LayerListModel : public QAbstractListModel
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#include "layerwidget.hpp"
|
||||
#include <qabstractitemdelegate.h>
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#ifndef LAYERWIDGET_HPP
|
||||
#define LAYERWIDGET_HPP
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
// qt
|
||||
#include <QApplication>
|
||||
|
@ -36,52 +35,59 @@ int main( int argc, char **argv )
|
|||
using mapnik::datasource_cache;
|
||||
using mapnik::freetype_engine;
|
||||
|
||||
QCoreApplication::setOrganizationName("Mapnik");
|
||||
QCoreApplication::setOrganizationDomain("mapnik.org");
|
||||
QCoreApplication::setApplicationName("Viewer");
|
||||
|
||||
QSettings settings("viewer.ini",QSettings::IniFormat);
|
||||
|
||||
// register input plug-ins
|
||||
QString plugins_dir = settings.value("mapnik/plugins_dir",
|
||||
QVariant("/usr/local/lib/mapnik/input/")).toString();
|
||||
datasource_cache::instance()->register_datasources(plugins_dir.toStdString());
|
||||
// register fonts
|
||||
int count = settings.beginReadArray("mapnik/fonts");
|
||||
for (int index=0; index < count; ++index)
|
||||
try
|
||||
{
|
||||
settings.setArrayIndex(index);
|
||||
QString font_dir = settings.value("dir").toString();
|
||||
freetype_engine::register_fonts(font_dir.toStdString());
|
||||
}
|
||||
settings.endArray();
|
||||
QCoreApplication::setOrganizationName("Mapnik");
|
||||
QCoreApplication::setOrganizationDomain("mapnik.org");
|
||||
QCoreApplication::setApplicationName("Viewer");
|
||||
QSettings settings("viewer.ini",QSettings::IniFormat);
|
||||
|
||||
QApplication app( argc, argv );
|
||||
MainWindow window;
|
||||
window.show();
|
||||
if (argc > 1) window.open(argv[1]);
|
||||
if (argc >= 3)
|
||||
{
|
||||
QStringList list = QString(argv[2]).split(",");
|
||||
if (list.size()==4)
|
||||
// register input plug-ins
|
||||
QString plugins_dir = settings.value("mapnik/plugins_dir",
|
||||
QVariant("/usr/local/lib/mapnik/input/")).toString();
|
||||
datasource_cache::instance().register_datasources(plugins_dir.toStdString());
|
||||
// register fonts
|
||||
int count = settings.beginReadArray("mapnik/fonts");
|
||||
for (int index=0; index < count; ++index)
|
||||
{
|
||||
settings.setArrayIndex(index);
|
||||
QString font_dir = settings.value("dir").toString();
|
||||
freetype_engine::register_fonts(font_dir.toStdString());
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
QApplication app( argc, argv );
|
||||
MainWindow window;
|
||||
window.show();
|
||||
if (argc > 1) window.open(argv[1]);
|
||||
if (argc >= 3)
|
||||
{
|
||||
QStringList list = QString(argv[2]).split(",");
|
||||
if (list.size()==4)
|
||||
{
|
||||
bool ok;
|
||||
double x0 = list[0].toDouble(&ok);
|
||||
double y0 = list[1].toDouble(&ok);
|
||||
double x1 = list[2].toDouble(&ok);
|
||||
double y1 = list[3].toDouble(&ok);
|
||||
if (ok) window.set_default_extent(x0,y0,x1,y1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
window.zoom_all();
|
||||
}
|
||||
if (argc == 4)
|
||||
{
|
||||
bool ok;
|
||||
double x0 = list[0].toDouble(&ok);
|
||||
double y0 = list[1].toDouble(&ok);
|
||||
double x1 = list[2].toDouble(&ok);
|
||||
double y1 = list[3].toDouble(&ok);
|
||||
if (ok) window.set_default_extent(x0,y0,x1,y1);
|
||||
double scaling_factor = QString(argv[3]).toDouble(&ok);
|
||||
if (ok) window.set_scaling_factor(scaling_factor);
|
||||
}
|
||||
return app.exec();
|
||||
}
|
||||
else
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
window.zoom_all();
|
||||
std::cerr << "Could not start viewer: '" << ex.what() << "'\n";
|
||||
return 1;
|
||||
}
|
||||
if (argc == 4)
|
||||
{
|
||||
bool ok;
|
||||
double scaling_factor = QString(argv[3]).toDouble(&ok);
|
||||
if (ok) window.set_scaling_factor(scaling_factor);
|
||||
}
|
||||
return app.exec();
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
// stl
|
||||
#include <iostream>
|
||||
|
@ -31,11 +30,17 @@
|
|||
#include <QList>
|
||||
#include <QItemDelegate>
|
||||
#include <QSlider>
|
||||
#include <QComboBox>
|
||||
#include <QDoubleSpinBox>
|
||||
|
||||
// mapnik
|
||||
|
||||
#ifndef Q_MOC_RUN // QT moc chokes on BOOST_JOIN
|
||||
#include <mapnik/config_error.hpp>
|
||||
#include <mapnik/load_map.hpp>
|
||||
#include <mapnik/save_map.hpp>
|
||||
#include <mapnik/projection.hpp>
|
||||
#endif
|
||||
|
||||
// qt
|
||||
#include "mainwindow.hpp"
|
||||
|
@ -94,6 +99,13 @@ MainWindow::MainWindow()
|
|||
connect(mapWidget_, SIGNAL(mapViewChanged()),layerTab_, SLOT(update()));
|
||||
// slider
|
||||
connect(slider_,SIGNAL(valueChanged(int)),mapWidget_,SLOT(zoomToLevel(int)));
|
||||
// renderer selector
|
||||
connect(renderer_selector_,SIGNAL(currentIndexChanged(QString const&)),
|
||||
mapWidget_, SLOT(updateRenderer(QString const&)));
|
||||
|
||||
// scale factor
|
||||
connect(scale_factor_,SIGNAL(valueChanged(double)),
|
||||
mapWidget_, SLOT(updateScaleFactor(double)));
|
||||
//
|
||||
connect(layerTab_,SIGNAL(update_mapwidget()),mapWidget_,SLOT(updateMap()));
|
||||
connect(layerTab_,SIGNAL(layerSelected(int)),
|
||||
|
@ -365,6 +377,23 @@ void MainWindow::createToolBars()
|
|||
fileToolBar->addAction(infoAct);
|
||||
fileToolBar->addAction(reloadAct);
|
||||
fileToolBar->addAction(printAct);
|
||||
|
||||
renderer_selector_ = new QComboBox(fileToolBar);
|
||||
renderer_selector_->setFocusPolicy(Qt::NoFocus);
|
||||
renderer_selector_->addItem("AGG");
|
||||
#ifdef HAVE_CAIRO
|
||||
renderer_selector_->addItem("Cairo");
|
||||
#endif
|
||||
renderer_selector_->addItem("Grid");
|
||||
fileToolBar->addWidget(renderer_selector_);
|
||||
|
||||
scale_factor_ = new QDoubleSpinBox(fileToolBar);
|
||||
scale_factor_->setMinimum(0.1);
|
||||
scale_factor_->setMaximum(5.0);
|
||||
scale_factor_->setSingleStep(0.1);
|
||||
scale_factor_->setValue(1.0);
|
||||
|
||||
fileToolBar->addWidget(scale_factor_);
|
||||
slider_ = new QSlider(Qt::Horizontal,fileToolBar);
|
||||
slider_->setRange(1,18);
|
||||
slider_->setTickPosition(QSlider::TicksBelow);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#ifndef MAINWINDOW_HPP
|
||||
#define MAINWINDOW_HPP
|
||||
|
@ -28,6 +27,7 @@
|
|||
#include <QActionGroup>
|
||||
#include <QStatusBar>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QDoubleSpinBox>
|
||||
|
||||
#include "mapwidget.hpp"
|
||||
|
||||
|
@ -36,6 +36,8 @@
|
|||
class LayerTab;
|
||||
class StyleTab;
|
||||
class QSlider;
|
||||
class QComboBox;
|
||||
class QDoubleSpinBox;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
|
@ -106,6 +108,8 @@ private:
|
|||
//status bar
|
||||
QStatusBar *status;
|
||||
QSlider * slider_;
|
||||
QComboBox * renderer_selector_;
|
||||
QDoubleSpinBox * scale_factor_;
|
||||
mapnik::box2d<double> default_extent_;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,13 +17,14 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#include <QtGui>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/graphics.hpp>
|
||||
#include <mapnik/grid/grid_renderer.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/projection.hpp>
|
||||
#include <mapnik/scale_denominator.hpp>
|
||||
|
@ -31,6 +32,13 @@
|
|||
#include <mapnik/memory_datasource.hpp>
|
||||
#include <mapnik/feature_kv_iterator.hpp>
|
||||
#include <mapnik/config_error.hpp>
|
||||
#include <mapnik/image_util.hpp>
|
||||
|
||||
#ifdef HAVE_CAIRO
|
||||
// cairo
|
||||
#include <mapnik/cairo_renderer.hpp>
|
||||
#endif
|
||||
|
||||
#include "mapwidget.hpp"
|
||||
#include "info_dialog.hpp"
|
||||
|
||||
|
@ -81,7 +89,8 @@ MapWidget::MapWidget(QWidget *parent)
|
|||
first_(true),
|
||||
pen_(QColor(0,0,255,96)),
|
||||
selectedLayer_(-1),
|
||||
scaling_factor_(1.0)
|
||||
scaling_factor_(1.0),
|
||||
cur_renderer_(AGG)
|
||||
{
|
||||
pen_.setWidth(3);
|
||||
pen_.setCapStyle(Qt::RoundCap);
|
||||
|
@ -173,29 +182,29 @@ void MapWidget::mousePressEvent(QMouseEvent* e)
|
|||
feature_ptr feat = fs->next();
|
||||
if (feat)
|
||||
{
|
||||
|
||||
|
||||
feature_kv_iterator itr(*feat,true);
|
||||
feature_kv_iterator end(*feat);
|
||||
|
||||
|
||||
for ( ;itr!=end; ++itr)
|
||||
{
|
||||
info.push_back(QPair<QString,QString>(QString(boost::get<0>(*itr).c_str()),
|
||||
boost::get<1>(*itr).to_string().c_str()));
|
||||
}
|
||||
|
||||
typedef mapnik::coord_transform2<mapnik::CoordTransform,mapnik::geometry_type> path_type;
|
||||
|
||||
typedef mapnik::coord_transform<mapnik::CoordTransform,mapnik::geometry_type> path_type;
|
||||
|
||||
for (unsigned i=0; i<feat->num_geometries();++i)
|
||||
{
|
||||
mapnik::geometry_type & geom = feat->get_geometry(i);
|
||||
path_type path(t,geom,prj_trans);
|
||||
if (geom.num_points() > 0)
|
||||
if (geom.size() > 0)
|
||||
{
|
||||
QPainterPath qpath;
|
||||
double x,y;
|
||||
path.vertex(&x,&y);
|
||||
qpath.moveTo(x,y);
|
||||
for (unsigned j = 1; j < geom.num_points(); ++j)
|
||||
for (unsigned j = 1; j < geom.size(); ++j)
|
||||
{
|
||||
path.vertex(&x,&y);
|
||||
qpath.lineTo(x,y);
|
||||
|
@ -278,6 +287,32 @@ void MapWidget::mouseReleaseEvent(QMouseEvent* e)
|
|||
}
|
||||
}
|
||||
|
||||
void MapWidget::wheelEvent(QWheelEvent* e)
|
||||
{
|
||||
if (!map_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QPoint corner(map_->width(), map_->height());
|
||||
QPoint zoomCoords;
|
||||
double zoom;
|
||||
if (e->delta() > 0)
|
||||
{
|
||||
zoom = 0.5;
|
||||
QPoint center = corner / 2;
|
||||
QPoint delta = e->pos() - center;
|
||||
zoomCoords = zoom * delta + center;
|
||||
}
|
||||
else
|
||||
{
|
||||
zoom = 2.0;
|
||||
zoomCoords = corner - e->pos();
|
||||
}
|
||||
|
||||
map_->pan_and_zoom(zoomCoords.x(), zoomCoords.y(), zoom);
|
||||
updateMap();
|
||||
}
|
||||
|
||||
void MapWidget::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
|
@ -449,6 +484,7 @@ void MapWidget::export_to_file(unsigned ,unsigned ,std::string const&,std::strin
|
|||
//agg_renderer renderer(map,image);
|
||||
//renderer.apply();
|
||||
//image.saveToFile(filename,type);
|
||||
std::cout << "Export to file .." << std::endl;
|
||||
}
|
||||
|
||||
void MapWidget::set_scaling_factor(double scaling_factor)
|
||||
|
@ -456,24 +492,129 @@ void MapWidget::set_scaling_factor(double scaling_factor)
|
|||
scaling_factor_ = scaling_factor;
|
||||
}
|
||||
|
||||
void render_agg(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
|
||||
{
|
||||
unsigned width=map.width();
|
||||
unsigned height=map.height();
|
||||
|
||||
image_32 buf(width,height);
|
||||
mapnik::agg_renderer<image_32> ren(map,buf,scaling_factor);
|
||||
|
||||
try
|
||||
{
|
||||
ren.apply();
|
||||
QImage image((uchar*)buf.raw_data(),width,height,QImage::Format_ARGB32);
|
||||
pix = QPixmap::fromImage(image.rgbSwapped());
|
||||
}
|
||||
catch (mapnik::config_error & ex)
|
||||
{
|
||||
std::cerr << ex.what() << std::endl;
|
||||
}
|
||||
catch (const std::exception & ex)
|
||||
{
|
||||
std::cerr << "exception: " << ex.what() << std::endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unknown exception caught!\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void render_grid(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
|
||||
{
|
||||
unsigned width=map.width();
|
||||
unsigned height=map.height();
|
||||
|
||||
mapnik::grid buf(width,height,"F_CODE", 1);
|
||||
mapnik::grid_renderer<mapnik::grid> ren(map,buf,scaling_factor);
|
||||
|
||||
try
|
||||
{
|
||||
ren.apply();
|
||||
mapnik::value_integer * imdata = static_cast<mapnik::value_integer*>(buf.raw_data());
|
||||
|
||||
// Not sure how to display long long values ??
|
||||
//QImage image(width,height,QImage::Format_RGB32);
|
||||
//for (unsigned i = 0 ; i < height ; ++i)
|
||||
//{
|
||||
// for (unsigned j = 0 ; j < width ; ++j)
|
||||
// {
|
||||
// image.setPixel(j,i,qRgb((uint8_t)(imdata[i*width+j]>>8),
|
||||
// (uint8_t)(imdata[i*width+j+1]>>8),
|
||||
// (uint8_t)(imdata[i*width+j+2]>>8)));
|
||||
// }
|
||||
//}
|
||||
//pix = QPixmap::fromImage(image);
|
||||
}
|
||||
catch (mapnik::config_error & ex)
|
||||
{
|
||||
std::cerr << ex.what() << std::endl;
|
||||
}
|
||||
catch (const std::exception & ex)
|
||||
{
|
||||
std::cerr << "exception: " << ex.what() << std::endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unknown exception caught!\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
|
||||
{
|
||||
|
||||
#ifdef HAVE_CAIRO
|
||||
mapnik::cairo_surface_ptr image_surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,map.width(),map.height()),
|
||||
mapnik::cairo_surface_closer());
|
||||
mapnik::cairo_renderer<mapnik::cairo_surface_ptr> renderer(map, image_surface, scaling_factor);
|
||||
renderer.apply();
|
||||
image_32 buf(image_surface);
|
||||
QImage image((uchar*)buf.raw_data(),buf.width(),buf.height(),QImage::Format_ARGB32);
|
||||
pix = QPixmap::fromImage(image.rgbSwapped());
|
||||
#endif
|
||||
}
|
||||
|
||||
void MapWidget::updateRenderer(QString const& txt)
|
||||
{
|
||||
if (txt == "AGG") cur_renderer_ = AGG;
|
||||
else if (txt == "Cairo") cur_renderer_ = Cairo;
|
||||
else if (txt == "Grid") cur_renderer_ = Grid;
|
||||
std::cerr << "Update renderer called" << std::endl;
|
||||
updateMap();
|
||||
}
|
||||
|
||||
void MapWidget::updateScaleFactor(double scale_factor)
|
||||
{
|
||||
set_scaling_factor(scale_factor);
|
||||
updateMap();
|
||||
}
|
||||
|
||||
void MapWidget::updateMap()
|
||||
{
|
||||
if (map_)
|
||||
{
|
||||
unsigned width=map_->width();
|
||||
unsigned height=map_->height();
|
||||
if (cur_renderer_== AGG)
|
||||
{
|
||||
render_agg(*map_, scaling_factor_, pix_);
|
||||
}
|
||||
else if (cur_renderer_ == Cairo)
|
||||
{
|
||||
render_cairo(*map_, scaling_factor_, pix_);
|
||||
}
|
||||
else if (cur_renderer_ == Grid)
|
||||
{
|
||||
render_grid(*map_, scaling_factor_, pix_);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Unknown renderer..." << std::endl;
|
||||
}
|
||||
|
||||
image_32 buf(width,height);
|
||||
|
||||
try
|
||||
{
|
||||
mapnik::agg_renderer<image_32> ren(*map_,buf,scaling_factor_);
|
||||
ren.apply();
|
||||
|
||||
QImage image((uchar*)buf.raw_data(),width,height,QImage::Format_ARGB32);
|
||||
pix_=QPixmap::fromImage(image.rgbSwapped());
|
||||
try
|
||||
{
|
||||
projection prj(map_->srs()); // map projection
|
||||
|
||||
box2d<double> ext = map_->get_current_extent();
|
||||
double x0 = ext.minx();
|
||||
double y0 = ext.miny();
|
||||
|
@ -486,10 +627,6 @@ void MapWidget::updateMap()
|
|||
// emit signal to interested widgets
|
||||
emit mapViewChanged();
|
||||
}
|
||||
catch (mapnik::config_error & ex)
|
||||
{
|
||||
std::cerr << ex.what() << std::endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unknown exception caught!\n";
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#ifndef MAP_WIDGET_HPP
|
||||
#define MAP_WIDGET_HPP
|
||||
|
@ -31,13 +30,16 @@
|
|||
#include <string>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <mapnik/map.hpp>
|
||||
#endif
|
||||
|
||||
class MapWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
public:
|
||||
enum eTool
|
||||
{
|
||||
ZoomToBox = 1,
|
||||
|
@ -45,6 +47,13 @@ class MapWidget : public QWidget
|
|||
Info,
|
||||
};
|
||||
|
||||
enum eRenderer
|
||||
{
|
||||
AGG,
|
||||
Cairo,
|
||||
Grid
|
||||
};
|
||||
|
||||
private:
|
||||
boost::shared_ptr<mapnik::Map> map_;
|
||||
int selected_;
|
||||
|
@ -60,6 +69,7 @@ private:
|
|||
QPen pen_;
|
||||
int selectedLayer_;
|
||||
double scaling_factor_;
|
||||
eRenderer cur_renderer_;
|
||||
public:
|
||||
MapWidget(QWidget *parent=0);
|
||||
void setTool(eTool tool);
|
||||
|
@ -79,6 +89,8 @@ public slots:
|
|||
void zoomToLevel(int level);
|
||||
void updateMap();
|
||||
void layerSelected(int);
|
||||
void updateRenderer(QString const& txt);
|
||||
void updateScaleFactor(double scale_factor);
|
||||
signals:
|
||||
void mapViewChanged();
|
||||
protected:
|
||||
|
@ -87,6 +99,7 @@ protected:
|
|||
void mousePressEvent(QMouseEvent* e);
|
||||
void mouseMoveEvent(QMouseEvent* e);
|
||||
void mouseReleaseEvent(QMouseEvent* e);
|
||||
void wheelEvent(QWheelEvent* e);
|
||||
void keyPressEvent(QKeyEvent *e);
|
||||
void export_to_file(unsigned width,
|
||||
unsigned height,
|
||||
|
|
|
@ -17,21 +17,23 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#include "styles_model.hpp"
|
||||
#include <mapnik/expression_string.hpp>
|
||||
#include <mapnik/noncopyable.hpp>
|
||||
#include <mapnik/rule.hpp>
|
||||
#include <mapnik/feature_type_style.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
// qt
|
||||
#include <QList>
|
||||
#include <QIcon>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
|
||||
class node : private boost::noncopyable
|
||||
class node : private mapnik::noncopyable
|
||||
{
|
||||
struct node_base
|
||||
{
|
||||
|
@ -162,6 +164,18 @@ struct symbolizer_info : public boost::static_visitor<QString>
|
|||
return QString("ShieldSymbolizer");
|
||||
}
|
||||
|
||||
QString operator() (mapnik::markers_symbolizer const& sym) const
|
||||
{
|
||||
boost::ignore_unused_variable_warning(sym);
|
||||
return QString("MarkersSymbolizer");
|
||||
}
|
||||
|
||||
QString operator() (mapnik::building_symbolizer const& sym) const
|
||||
{
|
||||
boost::ignore_unused_variable_warning(sym);
|
||||
return QString("BuildingSymbolizer");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QString operator() (T const& ) const
|
||||
{
|
||||
|
@ -223,7 +237,7 @@ class symbolizer_node
|
|||
{
|
||||
public:
|
||||
symbolizer_node(mapnik::symbolizer const & sym)
|
||||
: sym_(sym) {}
|
||||
: sym_(sym) {}
|
||||
~symbolizer_node(){}
|
||||
|
||||
QString name() const
|
||||
|
|
|
@ -17,13 +17,16 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
//$Id$
|
||||
|
||||
#ifndef STYLE_MODEL_HPP
|
||||
#define STYLE_MODEL_HPP
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#ifndef Q_MOC_RUN
|
||||
#include <mapnik/map.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
class node;
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
######################################################################
|
||||
# Mapnik viewer - Copyright (C) 2007 Artem Pavlenko
|
||||
######################################################################
|
||||
CC = g++
|
||||
TEMPLATE = app
|
||||
|
||||
INCLUDEPATH += /usr/local/include/
|
||||
INCLUDEPATH += /usr/boost/include/
|
||||
INCLUDEPATH += /usr/X11/include/
|
||||
INCLUDEPATH += /usr/X11/include/freetype2
|
||||
INCLUDEPATH += .
|
||||
|
||||
QMAKE_CXXFLAGS +=' -DDARWIN -Wno-missing-field-initializers -ansi'
|
||||
unix:LIBS = -L/usr/local/lib -L/usr/X11/lib -lmapnik -lfreetype
|
||||
unix:LIBS += -lboost_system -licuuc -lboost_filesystem -lboost_regex
|
||||
QMAKE_CXX = clang++
|
||||
QMAKE_CXXFLAGS += $$system(mapnik-config --cflags)
|
||||
QMAKE_LFLAGS += $$system(mapnik-config --libs)
|
||||
QMAKE_LFLAGS += $$system(mapnik-config --ldflags --dep-libs)
|
||||
|
||||
# Input
|
||||
|
||||
|
|
14
deps/agg/build.py
vendored
14
deps/agg/build.py
vendored
|
@ -15,9 +15,10 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
import glob
|
||||
import os
|
||||
from glob import glob
|
||||
|
||||
Import('env')
|
||||
|
||||
|
@ -28,4 +29,11 @@ if env['SUNCC']:
|
|||
else:
|
||||
cxxflags = env['CUSTOM_CXXFLAGS'] + ' -O%s -fPIC -DNDEBUG' % env['OPTIMIZATION']
|
||||
|
||||
agg_env.StaticLibrary('agg', glob.glob('./src/' + '*.cpp'), LIBS=[], CPPPATH='./include', CXXFLAGS=cxxflags, LINKFLAGS=env['CUSTOM_LDFLAGS'])
|
||||
agg_env.StaticLibrary('agg', glob('./src/' + '*.cpp'), LIBS=[], CXXFLAGS=cxxflags, LINKFLAGS=env['CUSTOM_LDFLAGS'])
|
||||
|
||||
if 'install' in COMMAND_LINE_TARGETS:
|
||||
inc_target = os.path.normpath(env['INSTALL_PREFIX']+'/include/mapnik/agg')
|
||||
# TODO - restrict to just agg headers used in mapnik includes?
|
||||
includes = glob('./include/*.h')
|
||||
target = env.Install(inc_target, includes)
|
||||
env.Alias(target='install', source=target)
|
||||
|
|
6
deps/agg/include/agg_basics.h
vendored
6
deps/agg/include/agg_basics.h
vendored
|
@ -35,10 +35,12 @@ namespace agg
|
|||
//------------------------------------------------------------pod_allocator
|
||||
template<class T> struct pod_allocator
|
||||
{
|
||||
//static T* allocate(unsigned num) { return static_cast<T*>(::operator new(sizeof(T)*num));}
|
||||
//static void deallocate(T* ptr, unsigned) { ::operator delete(ptr) ;}
|
||||
static T* allocate(unsigned num) { return new T [num]; }
|
||||
static void deallocate(T* ptr, unsigned) { delete [] ptr; }
|
||||
static void deallocate(T* ptr, unsigned) { delete [] ptr; }
|
||||
};
|
||||
|
||||
|
||||
// Single object allocator. It's also can be replaced with your custom
|
||||
// allocator. The difference is that it can only allocate a single
|
||||
// object and the constructor and destructor must be called.
|
||||
|
|
2
deps/agg/include/agg_conv_adaptor_vcgen.h
vendored
2
deps/agg/include/agg_conv_adaptor_vcgen.h
vendored
|
@ -29,6 +29,7 @@ namespace agg
|
|||
|
||||
void rewind(unsigned) {}
|
||||
unsigned vertex(double*, double*) { return path_cmd_stop; }
|
||||
unsigned type() const { return 0; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -64,6 +65,7 @@ namespace agg
|
|||
}
|
||||
|
||||
unsigned vertex(double* x, double* y);
|
||||
unsigned type() const { return m_source->type(); }
|
||||
|
||||
private:
|
||||
// Prohibit copying
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue