Merge branch 'master' into conv_simplify

Conflicts:
	bindings/python/mapnik_line_symbolizer.cpp
	bindings/python/mapnik_polygon_symbolizer.cpp
This commit is contained in:
Konstantin Käfer 2012-08-24 23:29:43 +02:00
commit 13c46b6cc6
117 changed files with 2037 additions and 989 deletions

1
.gitignore vendored
View file

@ -39,6 +39,7 @@ 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

View file

@ -9,42 +9,76 @@ For a complete change history, see the git log.
## Mapnik 2.1.0
Not yet released
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 overriding fill, stroke, and opacity for svg markers using marker properties
- 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`,
- 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)
- Added style-level 'opacity' (#314)
- PostGIS: Added 'simplify_geometries' option - will trigger ST_Simplify on geometries before returning to Mapnik (#1179)
- 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 (#937 and partially #986, #467)
- 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)
@ -108,7 +142,7 @@ Released April 10, 2012
- 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
@ -158,13 +192,13 @@ Released September 26, 2011
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.
@ -177,9 +211,9 @@ Released September 26, 2011
- 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)
@ -187,8 +221,8 @@ Released September 26, 2011
- 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)
@ -196,7 +230,7 @@ Released September 26, 2011
- 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)
@ -258,7 +292,7 @@ Released Oct 18, 2011
- 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
@ -277,13 +311,13 @@ Released March 23, 2010
- 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)
- 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.
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
@ -323,26 +357,26 @@ Released January, 19 2010
* 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)
@ -358,7 +392,7 @@ Released January, 19 2010
(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!
@ -366,7 +400,7 @@ Released January, 19 2010
- 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)
@ -387,19 +421,19 @@ Released January, 19 2010
- 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
@ -407,42 +441,42 @@ Released January, 19 2010
- 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 &lt;&gt;) (r1326) (#427)
- Filters: Added support for `!=` as an alias to `<>` for not-equals filters (avoids &lt;&gt;) (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)
@ -457,7 +491,7 @@ Released July 14, 2009
(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)
@ -497,13 +531,13 @@ Released July 14, 2009
- 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)
@ -515,13 +549,13 @@ Released July 14, 2009
- 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)
@ -546,7 +580,7 @@ Released April 1, 2009
- 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)
@ -567,7 +601,7 @@ Released April 1, 2009
- 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)
@ -589,7 +623,7 @@ Released April 1, 2009
- 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)

View file

@ -309,7 +309,9 @@ opts.AddVariables(
PathVariable('ICU_LIBS','Search path for ICU include files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept),
('ICU_LIB_NAME', 'The library name for icu (such as icuuc, sicuuc, or icucore)', 'icuuc'),
PathVariable('PNG_INCLUDES', 'Search path for libpng include files', '/usr/include', PathVariable.PathAccept),
PathVariable('PNG_LIBS','Search path for libpng include files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept),
PathVariable('PNG_LIBS','Search path for libpng library files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept),
PathVariable('LTDL_INCLUDES', 'Search path for libltdl (part of libtool) include files', '/usr/include', PathVariable.PathAccept),
PathVariable('LTDL_LIBS','Search path for libltdl (ltdl.h) library files','/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept),
BoolVariable('JPEG', 'Build Mapnik with JPEG read and write support', 'True'),
PathVariable('JPEG_INCLUDES', 'Search path for libjpeg include files', '/usr/include', PathVariable.PathAccept),
PathVariable('JPEG_LIBS', 'Search path for libjpeg library files', '/usr/' + LIBDIR_SCHEMA_DEFAULT, PathVariable.PathAccept),
@ -323,7 +325,7 @@ opts.AddVariables(
BoolVariable('RENDERING_STATS', 'Output rendering statistics during style processing', 'False'),
BoolVariable('SVG_RENDERER', 'build support for native svg renderer', 'False'),
#BoolVariable('SVG_RENDERER', 'build support for native svg renderer', 'False'),
# Variables for optional dependencies
('GEOS_CONFIG', 'The path to the geos-config executable.', 'geos-config'),
@ -424,7 +426,7 @@ pickle_store = [# Scons internal variables
'CAIROMM_LIBPATHS',
'CAIROMM_LINKFLAGS',
'CAIROMM_CPPPATHS',
'SVG_RENDERER',
#'SVG_RENDERER',
'SQLITE_LINKFLAGS',
'BOOST_LIB_VERSION_FROM_HEADER'
]
@ -1055,7 +1057,7 @@ if not preconfigured:
# Adding the required prerequisite library directories to the include path for
# compiling and the library path for linking, respectively.
for required in ('PNG', 'JPEG', 'TIFF','PROJ','ICU', 'SQLITE'):
for required in ('PNG', 'JPEG', 'TIFF','PROJ','ICU', 'SQLITE', 'LTDL'):
inc_path = env['%s_INCLUDES' % required]
lib_path = env['%s_LIBS' % required]
env.AppendUnique(CPPPATH = os.path.realpath(inc_path))
@ -1442,7 +1444,7 @@ if not preconfigured:
# fetch the mapnik version header in order to set the
# ABI version used to build libmapnik.so on linux in src/build.py
abi = conf.GetMapnikLibVersion()
abi_fallback = "2.0.1-pre"
abi_fallback = "2.2.0-pre"
if not abi:
color_print(1,'Problem encountered parsing mapnik version, falling back to %s' % abi_fallback)
abi = abi_fallback
@ -1738,7 +1740,8 @@ if not HELP_REQUESTED:
# not ready for release
SConscript('tests/cpp_tests/build.py')
# not ready for release
# not currently maintained
# https://github.com/mapnik/mapnik/issues/1438
#if env['SVG_RENDERER']:
# SConscript('tests/cpp_tests/svg_renderer_tests/build.py')

View file

@ -664,6 +664,39 @@ class PythonDatasource(object):
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 text_size(self):
@ -760,6 +793,18 @@ class _TextSymbolizer(TextSymbolizer,_injector):
self.format.wrap_char = wrap_char
@property
def wrap_character(self):
warnings.warn("'wrap_character' is deprecated, use format.wrap_character",
DeprecationWarning, 2)
return self.format.wrap_character
@wrap_char.setter
def wrap_character(self, wrap_character):
warnings.warn("'wrap_char' is deprecated, use format.wrap_character",
DeprecationWarning, 2)
self.format.wrap_character = wrap_character
@property
def wrap_before(self):

View file

@ -0,0 +1,50 @@
/*****************************************************************************
*
* 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/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")
;
}

View file

@ -38,6 +38,7 @@
#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 {
@ -224,6 +225,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;
@ -248,6 +284,7 @@ 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
;
@ -259,6 +296,7 @@ void export_geometry()
.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)

View file

@ -161,7 +161,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"
@ -173,6 +173,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,
@ -304,6 +319,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"

View file

@ -62,5 +62,17 @@ void export_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)")
;
}

View file

@ -48,17 +48,25 @@ void export_line_symbolizer()
(&line_symbolizer::get_stroke,
return_value_policy<reference_existing_object>()),
&line_symbolizer::set_stroke)
.add_property("smooth",
&line_symbolizer::smooth,
&line_symbolizer::set_smooth,
"smooth value (0..1.0)")
.add_property("simplify_tolerance",
&line_symbolizer::simplify_tolerance,
&line_symbolizer::set_simplify_tolerance,
"simplfication tolerance measure")
"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,
"smooth value (0..1.0)")
;
}

View file

@ -370,12 +370,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,

View file

@ -23,11 +23,13 @@
#include <boost/python.hpp>
#include <mapnik/graphics.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;
@ -47,8 +49,27 @@ 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::known_svg_prefix_ + "ellipse";
}
else if (marker_type == "arrow")
{
filename = mapnik::marker_cache::known_svg_prefix_ + "arrow";
}
else
{
throw mapnik::value_error("Unknown marker-type: '" + marker_type + "'");
}
symbolizer.set_filename(parse_path(filename));
}
}
// https://github.com/mapnik/mapnik/issues/1367
PyObject* get_fill_opacity_impl(markers_symbolizer & sym)
{
@ -74,6 +95,9 @@ void export_markers_symbolizer()
.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)
@ -119,5 +143,17 @@ void export_markers_symbolizer()
&markers_symbolizer::get_marker_placement,
&markers_symbolizer::set_marker_placement,
"Set/get the marker placement")
.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")
;
}

View file

@ -81,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")
;
}

View file

@ -70,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)
@ -77,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")
;
}

View file

@ -21,7 +21,6 @@
*****************************************************************************/
#include <boost/python.hpp>
#include "mapnik_enumeration.hpp"
#include <mapnik/polygon_symbolizer.hpp>
using namespace mapnik;
@ -49,10 +48,18 @@ 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,

View file

@ -57,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();
@ -395,6 +396,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();
@ -617,6 +619,7 @@ BOOST_PYTHON_MODULE(_mapnik)
python_optional<mapnik::stroke>();
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>();

View file

@ -39,18 +39,13 @@ void export_raster_symbolizer()
.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",
&raster_symbolizer::get_scaling_method,
&raster_symbolizer::set_scaling_method,

View file

@ -205,5 +205,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")
;
}

View file

@ -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,9 +43,23 @@ 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);
}
}
}
}
void export_stroke ()
@ -101,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")

View file

@ -25,13 +25,40 @@
#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;
std::string get_image_filters(feature_type_style & style)
{
std::string filters_str;
std::back_insert_iterator<std::string> sink(filters_str);
generate_image_filters(sink, style.image_filters());
return filters_str;
}
void set_image_filters(feature_type_style & style, std::string const& filters)
{
std::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;
bool result = boost::spirit::qi::phrase_parse(itr,end,
filter_grammar,
boost::spirit::qi::ascii::space,
style.image_filters());
if (!result || itr!=end)
{
throw mapnik::value_error("failed to parse image-filters: '" + std::string(itr,end) + "'");
}
}
void export_style()
{
using namespace boost::python;
@ -61,6 +88,18 @@ void export_style()
&feature_type_style::get_filter_mode,
&feature_type_style::set_filter_mode,
"Set/get the filter mode of the style")
.add_property("opacity",
&feature_type_style::get_opacity,
&feature_type_style::set_opacity,
"Set/get the opacity of the style")
.add_property("comp_op",
&feature_type_style::comp_op,
&feature_type_style::set_comp_op,
"Set/get the comp-op (composite operation) of the style")
.add_property("image_filters",
get_image_filters,
set_image_filters,
"Set/get the comp-op (composite operation) of the style")
;
}

View file

@ -354,6 +354,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")
;
@ -390,8 +398,10 @@ 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(init<char_properties const&>()) //Copy constructor
.def_readwrite("face_name", &char_properties::face_name)
.def_readwrite("fontset", &char_properties::fontset)
@ -400,8 +410,8 @@ void export_text_placement()
.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)
@ -488,6 +498,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)
@ -527,6 +538,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)

View file

@ -34,11 +34,11 @@ namespace mapnik
struct MAPNIK_DECL building_symbolizer : public symbolizer_base
{
building_symbolizer();
building_symbolizer(color const& fill, expression_ptr height);
building_symbolizer(color const& fill, expression_ptr const& height);
color const& get_fill() const;
void set_fill(color const& fill);
expression_ptr height() const;
void set_height(expression_ptr height);
expression_ptr const& height() const;
void set_height(expression_ptr const& height);
void set_opacity(double opacity);
double get_opacity() const;

View file

@ -276,10 +276,10 @@ bool middle_point(PathType & path, double & x, double & y)
template <typename PathType>
bool centroid(PathType & path, double & x, double & y)
{
double x0 = 0;
double y0 = 0;
double x1 = 0;
double y1 = 0;
double x0 = 0.0;
double y0 = 0.0;
double x1 = 0.0;
double y1 = 0.0;
double start_x;
double start_y;
@ -290,9 +290,9 @@ bool centroid(PathType & path, double & x, double & y)
start_x = x0;
start_y = y0;
double atmp = 0;
double xtmp = 0;
double ytmp = 0;
double atmp = 0.0;
double xtmp = 0.0;
double ytmp = 0.0;
unsigned count = 1;
while (SEG_END != (command = path.vertex(&x1, &y1)))
{
@ -310,10 +310,9 @@ bool centroid(PathType & path, double & x, double & y)
++count;
}
if (count == 1)
{
x = start_x;
y = start_y;
if (count <= 2) {
x = (start_x + x0) * 0.5;
y = (start_y + y0) * 0.5;
return true;
}
@ -368,14 +367,15 @@ bool hit_test(PathType & path, double x, double y, double tol)
}
template <typename PathType>
void interior_position(PathType & path, double & x, double & y)
bool interior_position(PathType & path, double & x, double & y)
{
// start with the centroid
label::centroid(path, x,y);
if (!label::centroid(path, x,y))
return false;
// if we are not a polygon, or the default is within the polygon we are done
if (hit_test(path,x,y,0.001))
return;
return true;
// otherwise we find a horizontal line across the polygon and then return the
// center of the widest intersection between the polygon and the line.
@ -422,7 +422,7 @@ void interior_position(PathType & path, double & x, double & y)
}
// no intersections we just return the default
if (intersections.empty())
return;
return true;
x0=intersections[0];
double max_width = 0;
for (unsigned ii = 1; ii < intersections.size(); ++ii)
@ -437,6 +437,7 @@ void interior_position(PathType & path, double & x, double & y)
break;
}
}
return true;
}
}}

View file

@ -25,7 +25,7 @@
// mapnik
#include <mapnik/vertex_vector.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/box2d.hpp>
// boost
#include <boost/shared_ptr.hpp>

View file

@ -26,6 +26,8 @@
// mapnik
#include <mapnik/markers_symbolizer.hpp>
#include <mapnik/markers_placement.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geom_util.hpp>
// agg
#include "agg_renderer_scanline.h"
@ -78,15 +80,17 @@ struct raster_markers_rasterizer_dispatch_grid
box2d<double> bbox_(0,0, src_.width(),src_.height());
if (placement_method != MARKER_LINE_PLACEMENT)
{
double x,y;
path.rewind(0);
double x = 0;
double y = 0;
if (placement_method == MARKER_INTERIOR_PLACEMENT)
{
label::interior_position(path, x, y);
if (!label::interior_position(path, x, y))
return;
}
else
{
label::centroid(path, x, y);
if (!label::centroid(path, x, y))
return;
}
agg::trans_affine matrix = marker_trans_;
matrix.translate(x,y);
@ -207,15 +211,17 @@ struct vector_markers_rasterizer_dispatch_grid
marker_placement_e placement_method = sym_.get_marker_placement();
if (placement_method != MARKER_LINE_PLACEMENT)
{
double x,y;
path.rewind(0);
double x = 0;
double y = 0;
if (placement_method == MARKER_INTERIOR_PLACEMENT)
{
label::interior_position(path, x, y);
if (!label::interior_position(path, x, y))
return;
}
else
{
label::centroid(path, x, y);
if (!label::centroid(path, x, y))
return;
}
agg::trans_affine matrix = marker_trans_;
matrix.translate(x,y);

View file

@ -0,0 +1,48 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_IMAGE_FILITER_GRAMMAR_HPP
#define MAPNIK_IMAGE_FILITER_GRAMMAR_HPP
// boost
#include <boost/spirit/include/qi.hpp>
// stl
#include <vector>
namespace mapnik {
namespace qi = boost::spirit::qi;
template <typename Iterator, typename ContType>
struct image_filter_grammar :
qi::grammar<Iterator, ContType(), qi::ascii::space_type>
{
image_filter_grammar();
qi::rule<Iterator, ContType(), qi::ascii::space_type> start;
qi::rule<Iterator, ContType(), qi::locals<int,int>, qi::ascii::space_type> filter;
qi::uint_parser< unsigned, 10, 1, 3 > radius_;
};
}
#endif // MAPNIK_IMAGE_FILITER_PARSER_HPP

View file

@ -1,97 +0,0 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_IMAGE_FILITER_PARSER_HPP
#define MAPNIK_IMAGE_FILITER_PARSER_HPP
#include <mapnik/image_filter.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <vector>
namespace mapnik {
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
template <typename Iterator, typename ContType>
struct image_filter_grammar :
qi::grammar<Iterator, ContType(), qi::ascii::space_type>
{
image_filter_grammar()
: image_filter_grammar::base_type(start)
{
using qi::lit;
using qi::_val;
using qi::_1;
using qi::_a;
using qi::_b;
using qi::eps;
using qi::char_;
using phoenix::push_back;
using phoenix::construct;
#if BOOST_VERSION >= 104700
using qi::no_skip;
start = -(filter % no_skip[*char_(", ")])
;
#else
start = -(filter)
;
#endif
filter =
lit("emboss")[push_back(_val,construct<mapnik::filter::emboss>())]
|
lit("blur")[push_back(_val,construct<mapnik::filter::blur>())]
|
lit("gray")[push_back(_val,construct<mapnik::filter::gray>())]
|
lit("edge-detect")[push_back(_val,construct<mapnik::filter::edge_detect>())]
|
lit("sobel")[push_back(_val,construct<mapnik::filter::sobel>())]
|
lit("sharpen")[push_back(_val,construct<mapnik::filter::sharpen>())]
|
lit("x-gradient")[push_back(_val,construct<mapnik::filter::x_gradient>())]
|
lit("y-gradient")[push_back(_val,construct<mapnik::filter::y_gradient>())]
|
(lit("agg-stack-blur")[_a = 1, _b = 1]
>> -( lit('(') >> radius_[_a = _1]
>> lit(',')
>> radius_[_b = _1]
>> lit(')'))
[push_back(_val,construct<mapnik::filter::agg_stack_blur>(_a,_b))])
|
lit("invert")[push_back(_val,construct<mapnik::filter::invert>())]
;
}
//
qi::rule<Iterator, ContType(), qi::ascii::space_type> start;
qi::rule<Iterator, ContType(), qi::locals<int,int>, qi::ascii::space_type> filter;
qi::uint_parser< unsigned, 10, 1, 3 > radius_;
};
}
#endif // MAPNIK_IMAGE_FILITER_PARSER_HPP

View file

@ -171,7 +171,7 @@ public:
/*!
* @return The field rendering of this layer is grouped by.
*/
std::string group_by() const;
std::string const& group_by() const;
/*!
* @brief Attach a datasource for this layer.

View file

@ -24,6 +24,8 @@
#define MAPNIK_MARKER_HELPERS_HPP
#include <mapnik/color.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/markers_symbolizer.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
@ -87,15 +89,17 @@ struct vector_markers_rasterizer_dispatch
if (placement_method != MARKER_LINE_PLACEMENT)
{
double x,y;
path.rewind(0);
double x = 0;
double y = 0;
if (placement_method == MARKER_INTERIOR_PLACEMENT)
{
label::interior_position(path, x, y);
if (!label::interior_position(path, x, y))
return;
}
else
{
label::centroid(path, x, y);
if (!label::centroid(path, x, y))
return;
}
agg::trans_affine matrix = marker_trans_;
matrix.translate(x,y);
@ -117,7 +121,9 @@ struct vector_markers_rasterizer_dispatch
sym_.get_spacing() * scale_factor_,
sym_.get_max_error(),
sym_.get_allow_overlap());
double x, y, angle;
double x = 0;
double y = 0;
double angle = 0;
while (placement.get_point(x, y, angle))
{
agg::trans_affine matrix = marker_trans_;
@ -179,15 +185,17 @@ struct raster_markers_rasterizer_dispatch
if (placement_method != MARKER_LINE_PLACEMENT)
{
double x,y;
path.rewind(0);
double x = 0;
double y = 0;
if (placement_method == MARKER_INTERIOR_PLACEMENT)
{
label::interior_position(path, x, y);
if (!label::interior_position(path, x, y))
return;
}
else
{
label::centroid(path, x, y);
if (!label::centroid(path, x, y))
return;
}
agg::trans_affine matrix = marker_trans_;
matrix.translate(x,y);

View file

@ -32,6 +32,9 @@
#include <mapnik/image_compositing.hpp>
#include <mapnik/image_scaling.hpp>
// boost
#include <boost/algorithm/string.hpp>
namespace mapnik
{
struct MAPNIK_DECL raster_symbolizer : public symbolizer_base
@ -66,15 +69,22 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base
mode_ = mode;
if (mode == "normal")
{
MAPNIK_LOG_ERROR(raster_symbolizer) << "converting 'mode=normal' to 'comp-op:src_over'";
this->set_comp_op(src_over);
}
else
{
boost::optional<composite_mode_e> comp_op = comp_op_from_string(mode);
std::string mode2 = boost::algorithm::replace_last_copy(mode,"2","");
boost::optional<composite_mode_e> comp_op = comp_op_from_string(mode2);
if (comp_op)
{
MAPNIK_LOG_ERROR(raster_symbolizer) << "converting 'mode:" << mode << "' to 'comp-op:" + *comp_op_to_string(*comp_op) + "'";
this->set_comp_op(*comp_op);
}
else
MAPNIK_LOG_ERROR(raster_symbolizer) << "could not convert mode into comp-op";
{
MAPNIK_LOG_ERROR(raster_symbolizer) << "could not convert mode '" << mode << "' into comp-op, defaulting to 'comp-op:src-over'";
}
}
}
scaling_method_e get_scaling_method() const

View file

@ -75,8 +75,8 @@ private:
class MAPNIK_DECL symbolizer_with_image
{
public:
path_expression_ptr get_filename() const;
void set_filename(path_expression_ptr filename);
path_expression_ptr const& get_filename() const;
void set_filename(path_expression_ptr const& filename);
void set_opacity(float opacity);
float get_opacity() const;
void set_image_transform(transform_type const& tr);

View file

@ -31,6 +31,10 @@
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
// fusion
#include <boost/fusion/include/at.hpp>
#include <boost/fusion/include/vector.hpp>
// stl
#include <vector>
@ -83,16 +87,36 @@ struct scale_node
struct rotate_node
{
typedef boost::fusion::vector2<expr_node, expr_node> coords_type;
expr_node angle_;
expr_node cx_;
expr_node cy_;
explicit rotate_node(expr_node const& angle)
: angle_(angle) {}
rotate_node(expr_node const& angle,
expr_node const& cx, expr_node const& cy)
: angle_(angle), cx_(cx), cy_(cy) {}
rotate_node(expr_node const& angle,
boost::optional<expr_node> const& cx,
boost::optional<expr_node> const& cy)
: angle_(angle)
, cx_(cx ? *cx : value_null())
, cy_(cy ? *cy : value_null()) {}
rotate_node(expr_node const& angle,
boost::optional<coords_type> const& center)
: angle_(angle)
{
if (center)
{
cx_ = boost::fusion::at_c<0>(*center);
cy_ = boost::fusion::at_c<1>(*center);
}
}
};
struct skewX_node

View file

@ -28,7 +28,6 @@
#include <mapnik/transform_expression.hpp>
// spirit
#include <boost/spirit/home/phoenix/object/construct.hpp>
#include <boost/spirit/home/qi.hpp>
namespace mapnik {
@ -40,20 +39,22 @@ namespace mapnik {
: qi::grammar<Iterator, transform_list(), space_type>
{
explicit transform_expression_grammar(expression_grammar<Iterator> const& g);
typedef qi::locals<expr_node, boost::optional<expr_node>,
boost::optional<expr_node>
> rotate_locals;
typedef qi::rule<Iterator, transform_node(), space_type> node_rule;
typedef qi::rule<Iterator, transform_list(), space_type> list_rule;
// rules
typename expression_grammar<Iterator>::rule_type expr;
qi::rule<Iterator, std::string(), space_type> attr;
qi::rule<Iterator, expr_node(), space_type> atom;
qi::rule<Iterator, expr_node(), space_type> expr;
qi::rule<Iterator, expr_node(), space_type> sep_atom;
qi::rule<Iterator, expr_node(), space_type> sep_expr;
qi::rule<Iterator, transform_list(), space_type> start;
qi::rule<Iterator, transform_node(), space_type> transform_;
qi::rule<Iterator, transform_node(), space_type> matrix;
qi::rule<Iterator, transform_node(), space_type> translate;
qi::rule<Iterator, transform_node(), space_type> scale;
qi::rule<Iterator, transform_node(), space_type, rotate_locals> rotate;
qi::rule<Iterator, transform_node(), space_type> rotate;
qi::rule<Iterator, transform_node(), space_type> skewX;
qi::rule<Iterator, transform_node(), space_type> skewY;
};

View file

@ -46,7 +46,7 @@ namespace mapnik { namespace util {
namespace karma = boost::spirit::karma;
namespace phoenix = boost::phoenix;
namespace detail {
namespace svg_detail {
struct get_type
{
template <typename T>
@ -133,10 +133,10 @@ namespace mapnik { namespace util {
karma::rule<OutputIterator, karma::locals<unsigned>, geometry_type const& ()> svg_path;
// phoenix functions
phoenix::function<detail::get_type > _type;
phoenix::function<detail::get_first> _first;
phoenix::function<svg_detail::get_type > _type;
phoenix::function<svg_detail::get_first> _first;
//
karma::real_generator<double, detail::coordinate_policy<double> > coord_type;
karma::real_generator<double, svg_detail::coordinate_policy<double> > coord_type;
};

View file

@ -0,0 +1,64 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
#ifndef MAPNIK_GEOMETRY_TO_SVG_HPP
#define MAPNIK_GEOMETRY_TO_SVG_HPP
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/util/vertex_iterator.hpp>
#include <mapnik/util/geometry_svg_generator.hpp>
// boost
#include <boost/spirit/include/karma.hpp>
namespace mapnik { namespace util {
namespace karma = boost::spirit::karma;
bool to_svg(std::string & svg, mapnik::geometry_type const& geom)
{
typedef std::back_insert_iterator<std::string> sink_type;
sink_type sink(svg);
svg_generator<sink_type> generator;
bool result = karma::generate(sink, generator, geom);
return result;
}
// TODO
// https://github.com/mapnik/mapnik/issues/1437
/*
bool to_svg(std::string & svg, mapnik::geometry_container const& geom)
{
typedef std::back_insert_iterator<std::string> sink_type;
sink_type sink(svg);
svg_multi_generator<sink_type> generator;
bool result = karma::generate(sink, generator, geom);
return result;
}
*/
}}
#endif // MAPNIK_GEOMETRY_TO_SVG_HPP

View file

@ -56,7 +56,7 @@ namespace mapnik { namespace util {
namespace karma = boost::spirit::karma;
namespace phoenix = boost::phoenix;
namespace {
namespace detail {
struct get_type
{
@ -130,10 +130,10 @@ struct wkt_generator :
karma::rule<OutputIterator, geometry_type::value_type (unsigned& )> polygon_coord;
// phoenix functions
phoenix::function<get_type > _type;
phoenix::function<get_first> _first;
phoenix::function<detail::get_type > _type;
phoenix::function<detail::get_first> _first;
//
karma::real_generator<double, wkt_coordinate_policy<double> > coord_type;
karma::real_generator<double, detail::wkt_coordinate_policy<double> > coord_type;
};
@ -150,9 +150,9 @@ struct wkt_multi_generator :
karma::rule<OutputIterator, geometry_container const& ()> multi_geometry;
wkt_generator<OutputIterator> path;
// phoenix
phoenix::function<multi_geometry_> is_multi;
phoenix::function<multi_geometry_type> _multi_type;
phoenix::function<get_type > _type;
phoenix::function<detail::multi_geometry_> is_multi;
phoenix::function<detail::multi_geometry_type> _multi_type;
phoenix::function<detail::get_type > _type;
//
karma::symbols<unsigned, char const*> geometry_types;
};

View file

@ -26,9 +26,10 @@
#define MAPNIK_VERSION_IS_RELEASE 0
#define MAPNIK_MAJOR_VERSION 2
#define MAPNIK_MINOR_VERSION 1
#define MAPNIK_MINOR_VERSION 2
#define MAPNIK_PATCH_VERSION 0
// translates to 200200
#define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION)
#ifndef MAPNIK_STRINGIFY
@ -37,12 +38,12 @@
#endif
#if MAPNIK_VERSION_IS_RELEASE
# define MAPNIK_VERSION_STRING MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \
#define MAPNIK_VERSION_STRING MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \
MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \
MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION)
#else
# define MAPNIK_VERSION_STRING MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \
#define MAPNIK_VERSION_STRING MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \
MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \
MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION) "-pre"
#endif

View file

@ -26,6 +26,7 @@
// mapnik
#include <mapnik/config.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/wkt/wkt_grammar.hpp>
// boost
#include <boost/utility.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
@ -37,10 +38,6 @@
namespace mapnik {
namespace wkt {
template <typename Iterator> struct wkt_collection_grammar;
}
MAPNIK_DECL bool from_wkt(std::string const& wkt, boost::ptr_vector<geometry_type> & paths);
#if BOOST_VERSION >= 104700

View file

@ -97,6 +97,8 @@ namespace mapnik { namespace wkt {
: wkt_grammar::base_type(geometry_tagged_text)
{
using qi::no_case;
using qi::_1;
using qi::_2;
using boost::phoenix::push_back;
geometry_tagged_text = point_tagged_text

View file

@ -22,17 +22,19 @@
#ifndef MAPNIK_XML_TREE_H
#define MAPNIK_XML_TREE_H
//mapnik
// mapnik
#include <mapnik/xml_node.hpp>
#include <mapnik/expression_grammar.hpp>
#include <mapnik/path_expression_grammar.hpp>
#include <mapnik/transform_expression_grammar.hpp>
#include <mapnik/image_filter_grammar.hpp>
#include <mapnik/image_filter.hpp>
#include <mapnik/css_color_grammar.hpp>
// boost
#include <boost/format.hpp>
#include <mapnik/css_color_grammar.hpp>
//stl
#include <string>
@ -56,6 +58,8 @@ public:
mapnik::expression_grammar<std::string::const_iterator> expr_grammar;
path_expression_grammar<std::string::const_iterator> path_expr_grammar;
transform_expression_grammar<std::string::const_iterator> transform_expr_grammar;
image_filter_grammar<std::string::const_iterator,std::vector<filter::filter_type> > image_filters_grammar;
};
} //ns mapnik

View file

@ -21,6 +21,7 @@
*****************************************************************************/
#include "csv_datasource.hpp"
#include "csv_utils.hpp"
// boost
#include <boost/make_shared.hpp>
@ -36,6 +37,7 @@
#include <mapnik/geometry.hpp>
#include <mapnik/memory_featureset.hpp>
#include <mapnik/wkt/wkt_factory.hpp>
#include <mapnik/json/geometry_parser.hpp>
#include <mapnik/util/geometry_to_ds_type.hpp>
#include <mapnik/util/conversions.hpp>
#include <mapnik/boolean.hpp>
@ -82,7 +84,7 @@ csv_datasource::csv_datasource(parameters const& params, bool bind)
- build up csv line-by-line iterator
- creates opportunity to filter attributes by map query
speed:
- add properties for wkt/lon/lat at parse time
- add properties for wkt/json/lon/lat at parse time
- add ability to pass 'filter' keyword to drop attributes at layer init
- create quad tree on the fly for small/med size files
- memory map large files for reading
@ -264,7 +266,7 @@ void csv_datasource::parse_csv(T& stream,
// grammer = boost::escaped_list_separator<char>('\\', ',', '\"');
grammer = boost::escaped_list_separator<char>(esc, sep, quo);
}
catch(const std::exception & ex)
catch(std::exception const& ex)
{
std::ostringstream s;
s << "CSV Plugin: " << ex.what();
@ -275,9 +277,11 @@ void csv_datasource::parse_csv(T& stream,
int line_number(1);
bool has_wkt_field = false;
bool has_json_field = false;
bool has_lat_field = false;
bool has_lon_field = false;
unsigned wkt_idx(0);
unsigned json_idx(0);
unsigned lat_idx(0);
unsigned lon_idx(0);
@ -296,6 +300,11 @@ void csv_datasource::parse_csv(T& stream,
wkt_idx = idx;
has_wkt_field = true;
}
if (lower_val == "geojson")
{
json_idx = idx;
has_json_field = true;
}
if (lower_val == "x"
|| lower_val == "lon"
|| lower_val == "lng"
@ -369,6 +378,11 @@ void csv_datasource::parse_csv(T& stream,
wkt_idx = idx;
has_wkt_field = true;
}
if (lower_val == "geojson")
{
json_idx = idx;
has_json_field = true;
}
if (lower_val == "x"
|| lower_val == "lon"
|| lower_val == "lng"
@ -401,10 +415,10 @@ void csv_datasource::parse_csv(T& stream,
}
}
if (!has_wkt_field && (!has_lon_field || !has_lat_field) )
if (!has_wkt_field && !has_json_field && (!has_lon_field || !has_lat_field) )
{
std::ostringstream s;
s << "CSV Plugin: could not detect column headers with the name of wkt, x/y, or latitude/longitude - this is required for reading geometry data";
s << "CSV Plugin: could not detect column headers with the name of wkt, geojson, x/y, or latitude/longitude - this is required for reading geometry data";
throw mapnik::datasource_exception(s.str());
}
@ -418,6 +432,8 @@ void csv_datasource::parse_csv(T& stream,
}
mapnik::transcoder tr(desc_.get_encoding());
mapnik::wkt_parser parse_wkt;
mapnik::json::geometry_parser<std::string::const_iterator> parse_json;
while (std::getline(stream,csv_line,newline))
{
@ -444,19 +460,39 @@ void csv_datasource::parse_csv(T& stream,
try
{
// special handling for varieties of quoting that we will enounter with json
// TODO - test with custom "quo" option
if (has_json_field && (quo == "\"") && (std::count(csv_line.begin(), csv_line.end(), '"') >= 6))
{
csv_utils::fix_json_quoting(csv_line);
}
Tokenizer tok(csv_line, grammer);
Tokenizer::iterator beg = tok.begin();
// early return for strict mode
if (strict_)
unsigned num_fields = std::distance(beg,tok.end());
if (num_fields > num_headers)
{
unsigned num_fields = std::distance(beg,tok.end());
if (num_fields != num_headers)
std::ostringstream s;
s << "CSV Plugin: # of columns("
<< num_fields << ") > # of headers("
<< num_headers << ") parsed for row " << line_number << "\n";
throw mapnik::datasource_exception(s.str());
}
else if (num_fields < num_headers)
{
std::ostringstream s;
s << "CSV Plugin: # of headers("
<< num_headers << ") > # of columns("
<< num_fields << ") parsed for row " << line_number << "\n";
if (strict_)
{
std::ostringstream s;
s << "CSV Plugin: # of headers != # of values parsed for row " << line_number << "\n";
throw mapnik::datasource_exception(s.str());
}
else
{
MAPNIK_LOG_WARN(csv) << s.str();
}
}
mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_count));
@ -465,22 +501,24 @@ void csv_datasource::parse_csv(T& stream,
bool parsed_x = false;
bool parsed_y = false;
bool parsed_wkt = false;
bool null_geom = false;
bool parsed_json = false;
std::vector<std::string> collected;
for (unsigned i = 0; i < num_headers; ++i)
{
std::string fld_name(headers_.at(i));
collected.push_back(fld_name);
std::string value;
if (beg == tok.end())
if (beg == tok.end()) // there are more headers than column values for this row
{
// add an empty string here to represent a missing value
// not using null type here since nulls are not a csv thing
feature->put(fld_name,tr.transcode(value.c_str()));
null_geom = true;
if (feature_count == 1)
{
desc_.add_descriptor(mapnik::attribute_descriptor(fld_name,mapnik::String));
}
// continue here instead of break so that all missing values are
// encoded consistenly as empty strings
continue;
}
else
@ -499,77 +537,67 @@ void csv_datasource::parse_csv(T& stream,
// skip empty geoms
if (value.empty())
{
null_geom = true;
break;
}
// optimize simple "POINT (x y)"
// using this shaved 2 seconds off csv that took 8 seconds total to parse
if (value.find("POINT") == 0)
if (parse_wkt.parse(value, feature->paths()))
{
using boost::phoenix::ref;
using boost::spirit::qi::_1;
std::string::const_iterator str_beg = value.begin();
std::string::const_iterator str_end = value.end();
bool r = qi::phrase_parse(str_beg,str_end,
(
qi::lit("POINT") >> '('
>> double_[ref(x) = _1]
>> double_[ref(y) = _1] >> ')'
),
ascii::space);
if (r && (str_beg == str_end))
{
mapnik::geometry_type * pt = new mapnik::geometry_type(mapnik::Point);
pt->move_to(x,y);
feature->add_geometry(pt);
parsed_wkt = true;
}
else
{
std::ostringstream s;
s << "CSV Plugin: expected well known text geometry: could not parse row "
<< line_number
<< ",column "
<< i << " - found: '"
<< value << "'";
if (strict_)
{
throw mapnik::datasource_exception(s.str());
}
else
{
MAPNIK_LOG_ERROR(csv) << s.str();
}
}
parsed_wkt = true;
}
else
{
if (mapnik::from_wkt(value, feature->paths()))
std::ostringstream s;
s << "CSV Plugin: expected well known text geometry: could not parse row "
<< line_number
<< ",column "
<< i << " - found: '"
<< value << "'";
if (strict_)
{
parsed_wkt = true;
throw mapnik::datasource_exception(s.str());
}
else
{
std::ostringstream s;
s << "CSV Plugin: expected well known text geometry: could not parse row "
<< line_number
<< ",column "
<< i << " - found: '"
<< value << "'";
if (strict_)
{
throw mapnik::datasource_exception(s.str());
}
else
{
MAPNIK_LOG_ERROR(csv) << s.str();
}
MAPNIK_LOG_ERROR(csv) << s.str();
}
}
}
}
// TODO - support both wkt/geojson columns
// at once to create multi-geoms?
// parse as geojson
else if (has_json_field)
{
if (i == json_idx)
{
// skip empty geoms
if (value.empty())
{
break;
}
if (parse_json.parse(value.begin(),value.end(), feature->paths()))
{
parsed_json = true;
}
else
{
std::ostringstream s;
s << "CSV Plugin: expected geojson geometry: could not parse row "
<< line_number
<< ",column "
<< i << " - found: '"
<< value << "'";
if (strict_)
{
throw mapnik::datasource_exception(s.str());
}
else
{
MAPNIK_LOG_ERROR(csv) << s.str();
}
}
}
}
else
{
// longitude
@ -578,7 +606,6 @@ void csv_datasource::parse_csv(T& stream,
// skip empty geoms
if (value.empty())
{
null_geom = true;
break;
}
@ -610,7 +637,6 @@ void csv_datasource::parse_csv(T& stream,
// skip empty geoms
if (value.empty())
{
null_geom = true;
break;
}
@ -713,26 +739,10 @@ void csv_datasource::parse_csv(T& stream,
}
}
if (null_geom)
bool null_geom = true;
if (has_wkt_field || has_json_field)
{
++line_number;
std::ostringstream s;
s << "CSV Plugin: null geometry encountered for line "
<< line_number;
if (strict_)
{
throw mapnik::datasource_exception(s.str());
}
else
{
MAPNIK_LOG_ERROR(csv) << s.str();
continue;
}
}
if (has_wkt_field)
{
if (parsed_wkt)
if (parsed_wkt || parsed_json)
{
if (!extent_initialized)
{
@ -745,11 +755,12 @@ void csv_datasource::parse_csv(T& stream,
}
features_.push_back(feature);
++feature_count;
null_geom = false;
}
else
{
std::ostringstream s;
s << "CSV Plugin: could not read WKT geometry "
s << "CSV Plugin: could not read WKT or GeoJSON geometry "
<< "for line " << line_number << " - found " << headers_.size()
<< " with values like: " << csv_line << "\n";
if (strict_)
@ -763,7 +774,7 @@ void csv_datasource::parse_csv(T& stream,
}
}
}
else
else if (has_lat_field || has_lon_field)
{
if (parsed_x && parsed_y)
{
@ -772,33 +783,31 @@ void csv_datasource::parse_csv(T& stream,
feature->add_geometry(pt);
features_.push_back(feature);
++feature_count;
null_geom = false;
if (!extent_initialized)
{
extent_initialized = true;
extent_ = feature->envelope();
}
else
{
extent_.expand_to_include(feature->envelope());
}
}
else
else if (parsed_x || parsed_y)
{
std::ostringstream s;
s << "CSV Plugin: does your csv have valid headers?\n";
if (!parsed_x)
{
s << "CSV Plugin: does your csv have valid headers?\n"
<< "Could not detect or parse any rows named 'x' or 'longitude' "
s << "Could not detect or parse any rows named 'x' or 'longitude' "
<< "for line " << line_number << " but found " << headers_.size()
<< " with values like: " << csv_line << "\n"
<< "for: " << boost::algorithm::join(collected, ",") << "\n";
}
if (!parsed_y)
{
s << "CSV Plugin: does your csv have valid headers?\n"
<< "Could not detect or parse any rows named 'y' or 'latitude' "
s << "Could not detect or parse any rows named 'y' or 'latitude' "
<< "for line " << line_number << " but found " << headers_.size()
<< " with values like: " << csv_line << "\n"
<< "for: " << boost::algorithm::join(collected, ",") << "\n";
@ -814,9 +823,26 @@ void csv_datasource::parse_csv(T& stream,
}
}
}
if (null_geom)
{
std::ostringstream s;
s << "CSV Plugin: could not detect and parse valid lat/lon fields or wkt/json geometry for line "
<< line_number;
if (strict_)
{
throw mapnik::datasource_exception(s.str());
}
else
{
MAPNIK_LOG_ERROR(csv) << s.str();
continue;
}
}
++line_number;
}
catch(const mapnik::datasource_exception & ex )
catch(mapnik::datasource_exception const& ex )
{
if (strict_)
{
@ -827,7 +853,7 @@ void csv_datasource::parse_csv(T& stream,
MAPNIK_LOG_ERROR(csv) << ex.what();
}
}
catch(const std::exception & ex)
catch(std::exception const& ex)
{
std::ostringstream s;
s << "CSV Plugin: unexpected error parsing line: " << line_number

View file

@ -0,0 +1,86 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_CSV_UTILS_DATASOURCE_HPP
#define MAPNIK_CSV_UTILS_DATASOURCE_HPP
#include <string>
#include <boost/algorithm/string.hpp>
namespace csv_utils
{
static void fix_json_quoting(std::string & csv_line)
{
std::string wrapping_char;
std::string::size_type j_idx = std::string::npos;
std::string::size_type post_idx = std::string::npos;
std::string::size_type j_idx_double = csv_line.find("\"{");
std::string::size_type j_idx_single = csv_line.find("'{");
if (j_idx_double != std::string::npos)
{
wrapping_char = "\"";
j_idx = j_idx_double;
post_idx = csv_line.find("}\"");
}
else if (j_idx_single != std::string::npos)
{
wrapping_char = "'";
j_idx = j_idx_single;
post_idx = csv_line.find("}'");
}
// we are positive it is valid json
if (!wrapping_char.empty())
{
// grab the json chunk
std::string json_chunk = csv_line.substr(j_idx,post_idx+wrapping_char.size());
bool does_not_have_escaped_double_quotes = (json_chunk.find("\\\"") == std::string::npos);
// ignore properly escaped quotes like \" which need no special handling
if (does_not_have_escaped_double_quotes)
{
std::string pre_json = csv_line.substr(0,j_idx);
std::string post_json = csv_line.substr(post_idx+wrapping_char.size());
// handle "" in a string wrapped in "
// http://tools.ietf.org/html/rfc4180#section-2 item 7.
// e.g. "{""type"":""Point"",""coordinates"":[30.0,10.0]}"
if (json_chunk.find("\"\"") != std::string::npos)
{
boost::algorithm::replace_all(json_chunk,"\"\"","\\\"");
csv_line = pre_json + json_chunk + post_json;
}
// handle " in a string wrapped in '
// e.g. '{"type":"Point","coordinates":[30.0,10.0]}'
else
{
// escape " because we cannot exchange for single quotes
// https://github.com/mapnik/mapnik/issues/1408
boost::algorithm::replace_all(json_chunk,"\"","\\\"");
boost::algorithm::replace_all(json_chunk,"'","\"");
csv_line = pre_json + json_chunk + post_json;
}
}
}
}
}
#endif // MAPNIK_CSV_UTILS_DATASOURCE_HPP

View file

@ -21,7 +21,11 @@ plugin_sources = Split(
boost_system = 'boost_system%s' % env['BOOST_APPEND']
libraries = ['mapnik',env['BOOST_PYTHON_LIB'],boost_system,env['ICU_LIB_NAME']]
python_link_flag = ''
# NOTE: explicit linking to libpython is uneeded on most linux version if the
# python plugin is used by a app in python using mapnik's python bindings
# we explicitly link to libpython here so that this plugin
# can be used from a pure C++ calling application or a different binding language
python_link_flag = '-lpython%s' % env['PYTHON_VERSION']
if env['PLATFORM'] == 'Darwin':
if env['PYTHON_DYNAMIC_LOOKUP']:
@ -37,8 +41,6 @@ if env['PLATFORM'] == 'Darwin':
python_link_flag = '-F/System/Library/Frameworks/ -framework Python -Z'
else:
python_link_flag = '-F/ -framework Python'
else:
python_link_flag = '-lpython%s' % env['PYTHON_VERSION']
if env['CUSTOM_LDFLAGS']:
linkflags = '%s %s' % (env['CUSTOM_LDFLAGS'], python_link_flag)

View file

@ -129,8 +129,9 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
eGeomType type = feature.paths()[0].type();
if (type == Polygon)
converter.template set<clip_poly_tag>();
else if (type == LineString)
converter.template set<clip_line_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
@ -164,8 +165,9 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
eGeomType type = feature.paths()[0].type();
if (type == Polygon)
converter.template set<clip_poly_tag>();
else if (type == LineString)
converter.template set<clip_line_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
@ -198,8 +200,9 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
eGeomType type = feature.paths()[0].type();
if (type == Polygon)
converter.template set<clip_poly_tag>();
else if (type == LineString)
converter.template set<clip_line_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform

View file

@ -77,9 +77,15 @@ void agg_renderer<T>::process(point_symbolizer const& sym,
double y;
double z=0;
if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT)
label::centroid(geom, x, y);
{
if (!label::centroid(geom, x, y))
return;
}
else
label::interior_position(geom ,x, y);
{
if (!label::interior_position(geom ,x, y))
return;
}
prj_trans.backward(x,y,z);
t_.forward(&x,&y);

View file

@ -144,7 +144,7 @@ void agg_renderer<T>::process(polygon_pattern_symbolizer const& sym,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter

View file

@ -56,7 +56,7 @@ void agg_renderer<T>::process(polygon_symbolizer const& sym,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
converter.set<affine_transform_tag>();
if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter

View file

@ -104,6 +104,7 @@ source = Split(
css_color_grammar.cpp
conversions.cpp
image_compositing.cpp
image_filter_grammar.cpp
image_scaling.cpp
box2d.cpp
building_symbolizer.cpp
@ -280,26 +281,27 @@ source += Split(
grid/process_text_symbolizer.cpp
""")
if env['SVG_RENDERER']: # svg backend
source += Split(
"""
svg/svg_renderer.cpp
svg/svg_generator.cpp
svg/svg_output_attributes.cpp
svg/process_symbolizers.cpp
svg/process_building_symbolizer.cpp
svg/process_line_pattern_symbolizer.cpp
svg/process_line_symbolizer.cpp
svg/process_markers_symbolizer.cpp
svg/process_point_symbolizer.cpp
svg/process_polygon_pattern_symbolizer.cpp
svg/process_polygon_symbolizer.cpp
svg/process_raster_symbolizer.cpp
svg/process_shield_symbolizer.cpp
svg/process_text_symbolizer.cpp
""")
lib_env.Append(CXXFLAGS = '-DSVG_RENDERER')
libmapnik_cxxflags.append('-DSVG_RENDERER')
# https://github.com/mapnik/mapnik/issues/1438
#if env['SVG_RENDERER']: # svg backend
# source += Split(
# """
# svg/svg_renderer.cpp
# svg/svg_generator.cpp
# svg/svg_output_attributes.cpp
# svg/process_symbolizers.cpp
# svg/process_building_symbolizer.cpp
# svg/process_line_pattern_symbolizer.cpp
# svg/process_line_symbolizer.cpp
# svg/process_markers_symbolizer.cpp
# svg/process_point_symbolizer.cpp
# svg/process_polygon_pattern_symbolizer.cpp
# svg/process_polygon_symbolizer.cpp
# svg/process_raster_symbolizer.cpp
# svg/process_shield_symbolizer.cpp
# svg/process_text_symbolizer.cpp
# """)
# lib_env.Append(CXXFLAGS = '-DSVG_RENDERER')
# libmapnik_cxxflags.append('-DSVG_RENDERER')
if env['XMLPARSER'] == 'libxml2' and env['HAS_LIBXML2']:
source += Split(

View file

@ -32,7 +32,7 @@ building_symbolizer::building_symbolizer()
opacity_(1.0)
{}
building_symbolizer::building_symbolizer(color const& fill, expression_ptr height)
building_symbolizer::building_symbolizer(color const& fill, expression_ptr const& height)
: symbolizer_base(),
fill_(fill),
height_(height),
@ -47,12 +47,12 @@ void building_symbolizer::set_fill(color const& fill)
{
fill_ = fill;
}
expression_ptr building_symbolizer::height() const
expression_ptr const& building_symbolizer::height() const
{
return height_;
}
void building_symbolizer::set_height(expression_ptr height)
void building_symbolizer::set_height(expression_ptr const& height)
{
height_=height;
}

View file

@ -870,7 +870,7 @@ void cairo_renderer_base::process(polygon_symbolizer const& sym,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,context,sym,t_,prj_trans,tr,1.0);
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
converter.set<affine_transform_tag>();
if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
@ -1205,9 +1205,15 @@ void cairo_renderer_base::process(point_symbolizer const& sym,
double z = 0;
if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT)
label::centroid(geom, x, y);
{
if (!label::centroid(geom, x, y))
return;
}
else
label::interior_position(geom, x, y);
{
if (!label::interior_position(geom ,x, y))
return;
}
prj_trans.backward(x, y, z);
t_.forward(&x, &y);
@ -1387,7 +1393,7 @@ void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,context,sym,t_,prj_trans,tr, scale_factor_);
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
converter.set<affine_transform_tag>();
if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
@ -1493,15 +1499,17 @@ struct markers_dispatch
if (placement_method != MARKER_LINE_PLACEMENT)
{
double x,y;
path.rewind(0);
double x = 0;
double y = 0;
if (placement_method == MARKER_INTERIOR_PLACEMENT)
{
label::interior_position(path, x, y);
if (!label::interior_position(path, x, y))
return;
}
else
{
label::centroid(path, x, y);
if (!label::centroid(path, x, y))
return;
}
coord2d center = bbox_.center();
agg::trans_affine matrix = agg::trans_affine_translation(-center.x, -center.y);
@ -1574,15 +1582,17 @@ struct markers_dispatch_2
if (placement_method != MARKER_LINE_PLACEMENT)
{
double x,y;
path.rewind(0);
double x = 0;
double y = 0;
if (placement_method == MARKER_INTERIOR_PLACEMENT)
{
label::interior_position(path, x, y);
if (!label::interior_position(path, x, y))
return;
}
else
{
label::centroid(path, x, y);
if (!label::centroid(path, x, y))
return;
}
coord2d center = bbox_.center();
agg::trans_affine matrix = agg::trans_affine_translation(-center.x, -center.y);
@ -1692,8 +1702,9 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
eGeomType type = feature.paths()[0].type();
if (type == Polygon)
converter.set<clip_poly_tag>();
else if (type == LineString)
converter.set<clip_line_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.set<transform_tag>(); //always transform
@ -1719,8 +1730,9 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
eGeomType type = feature.paths()[0].type();
if (type == Polygon)
converter.set<clip_poly_tag>();
else if (type == LineString)
converter.set<clip_line_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.set<transform_tag>(); //always transform
@ -1751,8 +1763,9 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
eGeomType type = feature.paths()[0].type();
if (type == Polygon)
converter.set<clip_poly_tag>();
else if (type == LineString)
converter.set<clip_line_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.set<transform_tag>(); //always transform

View file

@ -25,11 +25,10 @@ config_error::config_error(std::string const& what, unsigned line_number, std::s
char const* config_error::what() const throw()
{
std::stringstream s;
s << file_;
if (line_number_ > 0) s << " line " << line_number_;
if (!node_name_.empty()) s << " in node "<< node_name_;
if (line_number_ > 0 || !file_.empty()) s << ": ";
s << what_;
if (!node_name_.empty()) s << " in " << node_name_;
if (line_number_ > 0) s << " at line " << line_number_;
if (!file_.empty()) s << " of '" << file_ << "'";
msg_ = s.str(); //Avoid returning pointer to dead object
return msg_.c_str();
}

View file

@ -156,8 +156,9 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
eGeomType type = feature.paths()[0].type();
if (type == Polygon)
converter.template set<clip_poly_tag>();
else if (type == LineString)
converter.template set<clip_line_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
@ -200,8 +201,9 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
eGeomType type = feature.paths()[0].type();
if (type == Polygon)
converter.template set<clip_poly_tag>();
else if (type == LineString)
converter.template set<clip_line_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform
@ -247,8 +249,9 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
eGeomType type = feature.paths()[0].type();
if (type == Polygon)
converter.template set<clip_poly_tag>();
else if (type == LineString)
converter.template set<clip_line_tag>();
// line clipping disabled due to https://github.com/mapnik/mapnik/issues/1426
//else if (type == LineString)
// converter.template set<clip_line_tag>();
// don't clip if type==Point
}
converter.template set<transform_tag>(); //always transform

View file

@ -81,9 +81,15 @@ void grid_renderer<T>::process(point_symbolizer const& sym,
double y;
double z=0;
if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT)
label::centroid(geom, x, y);
{
if (!label::centroid(geom, x, y))
return;
}
else
label::interior_position(geom, x, y);
{
if (!label::interior_position(geom ,x, y))
return;
}
prj_trans.backward(x,y,z);
t_.forward(&x,&y);

View file

@ -20,6 +20,9 @@
*
*****************************************************************************/
// boost
#include <boost/foreach.hpp>
// mapnik
#include <mapnik/grid/grid_rasterizer.hpp>
#include <mapnik/grid/grid_renderer.hpp>
@ -27,6 +30,7 @@
#include <mapnik/grid/grid_pixel.hpp>
#include <mapnik/grid/grid.hpp>
#include <mapnik/polygon_pattern_symbolizer.hpp>
#include <mapnik/vertex_converters.hpp>
// agg
#include "agg_rasterizer_scanline_aa.h"
@ -44,10 +48,32 @@ void grid_renderer<T>::process(polygon_pattern_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
typedef coord_transform<CoordTransform,geometry_type> path_type;
ras_ptr->reset();
agg::trans_affine tr;
evaluate_transform(tr, feature, sym.get_transform());
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, grid_rasterizer, polygon_pattern_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
converter.set<affine_transform_tag>();
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH( geometry_type & geom, feature.paths())
{
if (geom.size() > 2)
{
converter.apply(geom);
}
}
typedef agg::renderer_base<mapnik::pixfmt_gray32> ren_base;
typedef agg::renderer_scanline_bin_solid<ren_base> renderer;
agg::scanline_bin sl;
grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_);
mapnik::pixfmt_gray32 pixf(buf);
@ -55,20 +81,9 @@ void grid_renderer<T>::process(polygon_pattern_symbolizer const& sym,
ren_base renb(pixf);
renderer ren(renb);
ras_ptr->reset();
for (unsigned i=0;i<feature.num_geometries();++i)
{
geometry_type & geom = feature.get_geometry(i);
if (geom.size() > 2)
{
path_type path(t_,geom,prj_trans);
ras_ptr->add_path(path);
}
}
// render id
ren.color(mapnik::gray32(feature.id()));
agg::scanline_bin sl;
agg::render_scanlines(*ras_ptr, sl, ren);
// add feature properties to grid cache

View file

@ -50,17 +50,15 @@ void grid_renderer<T>::process(polygon_symbolizer const& sym,
{
ras_ptr->reset();
box2d<double> inflated_extent = query_extent_ * 1.0;
agg::trans_affine tr;
evaluate_transform(tr, feature, sym.get_transform());
typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, grid_rasterizer, polygon_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
if (sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
converter.set<affine_transform_tag>();
if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter

View file

@ -0,0 +1,91 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// mapnik
#include <mapnik/image_filter_grammar.hpp>
#include <mapnik/image_filter.hpp>
// boost
#include <boost/version.hpp>
// spirit
#include <boost/spirit/include/phoenix.hpp>
namespace mapnik {
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
template <typename Iterator, typename ContType>
image_filter_grammar<Iterator,ContType>::image_filter_grammar()
: image_filter_grammar::base_type(start)
{
using qi::lit;
using qi::_val;
using qi::_1;
using qi::_a;
using qi::_b;
using qi::eps;
using qi::char_;
using phoenix::push_back;
using phoenix::construct;
#if BOOST_VERSION >= 104700
using qi::no_skip;
start = -(filter % no_skip[*char_(", ")])
;
#else
start = -(filter)
;
#endif
filter =
lit("emboss")[push_back(_val,construct<mapnik::filter::emboss>())]
|
lit("blur")[push_back(_val,construct<mapnik::filter::blur>())]
|
lit("gray")[push_back(_val,construct<mapnik::filter::gray>())]
|
lit("edge-detect")[push_back(_val,construct<mapnik::filter::edge_detect>())]
|
lit("sobel")[push_back(_val,construct<mapnik::filter::sobel>())]
|
lit("sharpen")[push_back(_val,construct<mapnik::filter::sharpen>())]
|
lit("x-gradient")[push_back(_val,construct<mapnik::filter::x_gradient>())]
|
lit("y-gradient")[push_back(_val,construct<mapnik::filter::y_gradient>())]
|
(lit("agg-stack-blur")[_a = 1, _b = 1]
>> -( lit('(') >> radius_[_a = _1]
>> lit(',')
>> radius_[_b = _1]
>> lit(')'))
[push_back(_val,construct<mapnik::filter::agg_stack_blur>(_a,_b))])
|
lit("invert")[push_back(_val,construct<mapnik::filter::invert>())]
;
}
template struct mapnik::image_filter_grammar<std::string::const_iterator,std::vector<mapnik::filter::filter_type> >;
}

View file

@ -237,7 +237,7 @@ void layer::set_group_by(std::string column)
group_by_ = column;
}
std::string layer::group_by() const
std::string const& layer::group_by() const
{
return group_by_;
}

View file

@ -31,7 +31,6 @@
#include <mapnik/color_factory.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/feature_type_style.hpp>
#include <mapnik/image_filter_parser.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/font_engine_freetype.hpp>
@ -117,6 +116,7 @@ private:
std::string ensure_relative_to_xml(boost::optional<std::string> opt_path);
void ensure_exists(std::string const& file_path);
boost::optional<color> get_opt_color_attr(boost::property_tree::ptree const& node,
std::string const& name);
@ -427,19 +427,14 @@ void map_parser::parse_style(Map & map, xml_node const& sty)
}
// image filters
mapnik::image_filter_grammar<std::string::const_iterator,
std::vector<mapnik::filter::filter_type> > filter_grammar;
optional<std::string> filters = sty.get_opt_attr<std::string>("image-filters");
if (filters)
{
std::string filter_mode = *filters;
std::string::const_iterator itr = filter_mode.begin();
std::string::const_iterator end = filter_mode.end();
bool result = boost::spirit::qi::phrase_parse(itr,end,
filter_grammar,
sty.get_tree().image_filters_grammar,
boost::spirit::qi::ascii::space,
style.image_filters());
if (!result || itr!=end)
@ -459,7 +454,7 @@ void map_parser::parse_style(Map & map, xml_node const& sty)
std::string::const_iterator itr = filter_mode.begin();
std::string::const_iterator end = filter_mode.end();
bool result = boost::spirit::qi::phrase_parse(itr,end,
filter_grammar,
sty.get_tree().image_filters_grammar,
boost::spirit::qi::ascii::space,
style.direct_image_filters());
if (!result || itr!=end)
@ -921,11 +916,12 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym)
}
*file = ensure_relative_to_xml(file);
std::string filename = *file;
ensure_exists(filename);
path_expression_ptr expr(boost::make_shared<path_expression>());
if (!parse_path_from_string(expr, *file, sym.get_tree().path_expr_grammar))
if (!parse_path_from_string(expr, filename, sym.get_tree().path_expr_grammar))
{
throw mapnik::config_error("Failed to parse path_expression '" + *file + "'");
throw mapnik::config_error("Failed to parse path_expression '" + filename + "'");
}
symbol.set_filename(expr);
@ -946,7 +942,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym)
}
catch (const config_error & ex)
{
ex.append_context("in PointSymbolizer", sym);
ex.append_context(sym);
throw;
}
}
@ -977,8 +973,9 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
optional<std::string> marker_type = node.get_opt_attr<std::string>("marker-type");
if (marker_type)
{
// TODO - before Mapnik 2.1 release change this from WARN TO ERROR
MAPNIK_LOG_WARN(markers_symbolizer) << "'marker-type' is deprecated and will be removed in Mapnik 3.x, use file='shape://<type>' to specify known svg shapes";
// TODO - revisit whether to officially deprecate marker-type
// https://github.com/mapnik/mapnik/issues/1427
//MAPNIK_LOG_WARN(markers_symbolizer) << "'marker-type' is deprecated and will be removed in Mapnik 3.x, use file='shape://<type>' to specify known svg shapes";
// back compatibility with Mapnik 2.0.0
if (!marker_type->empty() && filename.empty())
{
@ -997,6 +994,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
if (!filename.empty())
{
ensure_exists(filename);
path_expression_ptr expr(boost::make_shared<path_expression>());
if (!parse_path_from_string(expr, filename, node.get_tree().path_expr_grammar))
{
@ -1053,7 +1051,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
}
catch (config_error const& ex)
{
ex.append_context("in MarkersSymbolizer", node);
ex.append_context(node);
throw;
}
}
@ -1080,6 +1078,7 @@ void map_parser::parse_line_pattern_symbolizer(rule & rule, xml_node const & sym
}
file = ensure_relative_to_xml(file);
ensure_exists(file);
path_expression_ptr expr(boost::make_shared<path_expression>());
if (!parse_path_from_string(expr, file, sym.get_tree().path_expr_grammar))
{
@ -1092,7 +1091,7 @@ void map_parser::parse_line_pattern_symbolizer(rule & rule, xml_node const & sym
}
catch (const config_error & ex)
{
ex.append_context("in LinePatternSymbolizer", sym);
ex.append_context(sym);
throw;
}
}
@ -1121,7 +1120,7 @@ void map_parser::parse_polygon_pattern_symbolizer(rule & rule,
}
file = ensure_relative_to_xml(file);
ensure_exists(file);
path_expression_ptr expr(boost::make_shared<path_expression>());
if (!parse_path_from_string(expr, file, sym.get_tree().path_expr_grammar))
{
@ -1150,7 +1149,7 @@ void map_parser::parse_polygon_pattern_symbolizer(rule & rule,
}
catch (const config_error & ex)
{
ex.append_context("in PolygonPatternSymbolizer", sym);
ex.append_context(sym);
throw;
}
}
@ -1179,7 +1178,7 @@ void map_parser::parse_text_symbolizer(rule & rule, xml_node const& sym)
}
catch (const config_error & ex)
{
ex.append_context("in TextSymbolizer", sym);
ex.append_context(sym);
throw;
}
}
@ -1273,6 +1272,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym)
}
file = ensure_relative_to_xml(file);
ensure_exists(file);
path_expression_ptr expr(boost::make_shared<path_expression>());
if (!parse_path_from_string(expr, file, sym.get_tree().path_expr_grammar))
{
@ -1284,7 +1284,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym)
}
catch (const config_error & ex)
{
ex.append_context("in ShieldSymbolizer", sym);
ex.append_context(sym);
throw;
}
}
@ -1393,7 +1393,7 @@ void map_parser::parse_line_symbolizer(rule & rule, xml_node const & sym)
}
catch (const config_error & ex)
{
ex.append_context("in LineSymbolizer", sym);
ex.append_context(sym);
throw;
}
}
@ -1422,7 +1422,7 @@ void map_parser::parse_polygon_symbolizer(rule & rule, xml_node const & sym)
}
catch (const config_error & ex)
{
ex.append_context("in PolygonSymbolizer", sym);
ex.append_context(sym);
throw;
}
}
@ -1448,7 +1448,7 @@ void map_parser::parse_building_symbolizer(rule & rule, xml_node const & sym)
}
catch (const config_error & ex)
{
ex.append_context("in BuildingSymbolizer", sym);
ex.append_context(sym);
throw;
}
}
@ -1526,7 +1526,7 @@ void map_parser::parse_raster_symbolizer(rule & rule, xml_node const & sym)
}
catch (const config_error & ex)
{
ex.append_context("in RasterSymbolizer", sym);
ex.append_context(sym);
throw;
}
}
@ -1612,7 +1612,7 @@ void map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc,
}
catch (const config_error & ex)
{
ex.append_context("in RasterColorizer", node);
ex.append_context(node);
throw;
}
}
@ -1654,20 +1654,34 @@ std::string map_parser::ensure_relative_to_xml(boost::optional<std::string> opt_
return *opt_path;
}
void map_parser::ensure_exists(std::string const& file_path)
{
if (marker_cache::is_uri(file_path))
return;
// validate that the filename exists if it is not a dynamic PathExpression
if (!boost::algorithm::find_first(file_path,"[") && !boost::algorithm::find_first(file_path,"]"))
{
if (!boost::filesystem::exists(file_path))
{
throw mapnik::config_error("point-file could not be found: '" + file_path + "'");
}
}
}
void map_parser::find_unused_nodes(xml_node const& root)
{
std::stringstream error_message;
find_unused_nodes_recursive(root, error_message);
if (!error_message.str().empty())
{
std::string msg("The following nodes or attributes were not processed while parsing the xml file:" + error_message.str());
std::string msg("Unable to process some data while parsing '" + filename_ + "':" + error_message.str());
if (strict_)
{
throw config_error(msg);
}
else
{
MAPNIK_LOG_ERROR(load_map) << "map_parser: " << msg;
MAPNIK_LOG_ERROR(load_map) << msg;
}
}
}
@ -1679,7 +1693,7 @@ void map_parser::find_unused_nodes_recursive(xml_node const& node, std::stringst
if (node.is_text()) {
error_message << "\n* text '" << node.text() << "'";
} else {
error_message << "\n* node '" << node.name() << "' in line " << node.line();
error_message << "\n* node '" << node.name() << "' at line " << node.line();
}
return; //All attributes and children are automatically unprocessed, too.
}
@ -1692,7 +1706,7 @@ void map_parser::find_unused_nodes_recursive(xml_node const& node, std::stringst
{
error_message << "\n* attribute '" << aitr->first <<
"' with value '" << aitr->second.value <<
"' in line " << node.line();
"' at line " << node.line();
}
}
xml_node::const_iterator itr = node.begin();

View file

@ -132,7 +132,7 @@ void placement_finder<DetectorT>::find_point_placements(T & shape_path)
double total_distance = get_total_distance<T>(shape_path);
shape_path.rewind(0);
if (distance == 0) //Point data, not a line
if (total_distance == 0) //Point data, not a line
{
double x, y;
shape_path.vertex(&x,&y);

View file

@ -67,10 +67,28 @@ string_info &processed_text::get_string_info()
{
if (!p.fontset.get_name().empty())
{
throw config_error("Unable to find specified font set '" + p.fontset.get_name() + "'");
} else if (!p.face_name.empty()) {
if (p.fontset.size())
{
if (!p.face_name.empty())
{
throw config_error("Unable to find specified font face '" + p.face_name + "' in font set: '" + p.fontset.get_name() + "'");
}
else
{
throw config_error("No valid font face could be loaded for font set: '" + p.fontset.get_name() + "'");
}
}
else
{
throw config_error("Font set '" + p.fontset.get_name() + "' does not contain any Font face-name entries");
}
}
else if (!p.face_name.empty())
{
throw config_error("Unable to find specified font face '" + p.face_name + "'");
} else {
}
else
{
throw config_error("Both font set and face name are empty!");
}
}

View file

@ -151,12 +151,12 @@ symbolizer_with_image::symbolizer_with_image( symbolizer_with_image const& rhs)
{
}
path_expression_ptr symbolizer_with_image::get_filename() const
path_expression_ptr const& symbolizer_with_image::get_filename() const
{
return image_filename_;
}
void symbolizer_with_image::set_filename(path_expression_ptr image_filename)
void symbolizer_with_image::set_filename(path_expression_ptr const& image_filename)
{
image_filename_ = image_filename;
}

View file

@ -24,6 +24,9 @@
#include <mapnik/symbolizer_helpers.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/geom_util.hpp>
// agg
#include "agg_conv_clip_polyline.h"
namespace mapnik {
@ -233,25 +236,31 @@ void text_symbolizer_helper<FaceManagerT, DetectorT>::initialize_points()
}
else
{
// https://github.com/mapnik/mapnik/issues/1423
bool success = false;
// https://github.com/mapnik/mapnik/issues/1350
if (geom.type() == LineString)
{
label::middle_point(geom, label_x,label_y);
success = label::middle_point(geom, label_x,label_y);
}
else if (how_placed == POINT_PLACEMENT)
{
label::centroid(geom, label_x, label_y);
success = label::centroid(geom, label_x, label_y);
}
else if (how_placed == INTERIOR_PLACEMENT)
{
label::interior_position(geom, label_x, label_y);
success = label::interior_position(geom, label_x, label_y);
}
else
{
MAPNIK_LOG_ERROR(symbolizer_helpers) << "ERROR: Unknown placement type in initialize_points()";
}
prj_trans_.backward(label_x, label_y, z);
t_.forward(&label_x, &label_y);
points_.push_back(std::make_pair(label_x, label_y));
if (success)
{
prj_trans_.backward(label_x, label_y, z);
t_.forward(&label_x, &label_y);
points_.push_back(std::make_pair(label_x, label_y));
}
}
}
point_itr_ = points_.begin();

View file

@ -94,6 +94,11 @@ void text_symbolizer_properties::from_xml(xml_node const &sym, fontset_map const
if (label_position_tolerance_) label_position_tolerance = *label_position_tolerance_;
optional<unsigned> spacing_ = sym.get_opt_attr<unsigned>("spacing");
if (spacing_) label_spacing = *spacing_;
else {
// https://github.com/mapnik/mapnik/issues/1427
spacing_ = sym.get_opt_attr<unsigned>("label-spacing");
if (spacing_) label_spacing = *spacing_;
}
optional<unsigned> minimum_distance_ = sym.get_opt_attr<unsigned>("minimum-distance");
if (minimum_distance_) minimum_distance = *minimum_distance_;
optional<unsigned> min_padding_ = sym.get_opt_attr<unsigned>("minimum-padding");

View file

@ -19,12 +19,16 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// mapnik
#include <mapnik/transform_expression_grammar.hpp>
// boost
#include <boost/version.hpp>
// spirit
#include <boost/spirit/home/phoenix/object/construct.hpp>
namespace mapnik {
namespace qi = boost::spirit::qi;
@ -39,8 +43,17 @@ transform_expression_grammar<Iterator>::transform_expression_grammar(expression_
using qi::_c; using qi::_3; using qi::_6;
using qi::_val;
using qi::char_;
using qi::double_;
using qi::lit;
using qi::no_case;
// [http://www.w3.org/TR/SVG/coords.html#TransformAttribute]
// The value of the transform attribute is a <transform-list>, which
// is defined as a list of transform definitions, which are applied in
// the order provided. The individual transform definitions are
// separated by whitespace and/or a comma.
#if BOOST_VERSION > 104200
using qi::no_skip;
start = transform_ % no_skip[char_(", ")] ;
@ -51,48 +64,71 @@ transform_expression_grammar<Iterator>::transform_expression_grammar(expression_
transform_ = matrix | translate | scale | rotate | skewX | skewY ;
// matrix(<a> <b> <c> <d> <e> <f>)
matrix = no_case[lit("matrix")]
>> (lit('(')
>> expr >> -lit(',')
>> expr >> -lit(',')
>> expr >> -lit(',')
>> expr >> -lit(',')
>> expr >> -lit(',')
>> expr >> lit(')'))
>> ( atom >> sep_atom >> sep_atom >> sep_atom >> sep_atom
>> sep_atom >> lit(')')
| expr >> sep_expr >> sep_expr >> sep_expr >> sep_expr
>> sep_expr >> lit(')')
))
[ _val = construct<matrix_node>(_1,_2,_3,_4,_5,_6) ];
// translate(<tx> [<ty>])
translate = no_case[lit("translate")]
>> (lit('(')
>> expr >> -lit(',')
>> -expr >> lit(')'))
[ _val = construct<translate_node>(_1,_2) ];
>> lit('(')
>> ( ( atom >> -sep_atom >> lit(')') )
[ _val = construct<translate_node>(_1,_2) ]
| ( expr >> -sep_expr >> lit(')') )
[ _val = construct<translate_node>(_1,_2) ]
);
// scale(<sx> [<sy>])
scale = no_case[lit("scale")]
>> (lit('(')
>> expr >> -lit(',')
>> -expr >> lit(')'))
[ _val = construct<scale_node>(_1,_2) ];
>> lit('(')
>> ( ( atom >> -sep_atom >> lit(')') )
[ _val = construct<scale_node>(_1,_2) ]
| ( expr >> -sep_expr >> lit(')') )
[ _val = construct<scale_node>(_1,_2) ]
);
// rotate(<rotate-angle> [<cx> <cy>])
rotate = no_case[lit("rotate")]
>> lit('(')
>> expr[_a = _1] >> -lit(',')
>> -(expr [_b = _1] >> -lit(',') >> expr[_c = _1])
>> lit(')')
[ _val = construct<rotate_node>(_a,_b,_c) ];
>> ( ( atom >> -( sep_atom >> sep_atom ) >> lit(')') )
[ _val = construct<rotate_node>(_1,_2) ]
| ( expr >> -( sep_expr >> sep_expr ) >> lit(')') )
[ _val = construct<rotate_node>(_1,_2) ]
);
// skewX(<skew-angle>)
skewX = no_case[lit("skewX")]
>> lit('(')
>> expr [ _val = construct<skewX_node>(_1) ]
>> lit(')');
// skewY(<skew-angle>)
skewY = no_case[lit("skewY")]
>> lit('(')
>> expr [ _val = construct<skewY_node>(_1) ]
>> lit(')');
// number or attribute
atom = double_ [ _val = _1 ]
| attr [ _val = construct<mapnik::attribute>(_1) ];
// Individual arguments in lists consiting solely of numbers and/or
// attributes are separated by whitespace and/or a comma.
sep_atom = -lit(',') >> atom [ _val = _1 ];
// Individual arguments in lists containing one or more compound
// expressions are separated by a comma.
sep_expr = lit(',') >> expr [ _val = _1 ];
attr = g.attr.alias();
expr = g.expr.alias();
}
template struct mapnik::transform_expression_grammar<std::string::const_iterator>;
}
}

View file

@ -30,7 +30,7 @@
namespace mapnik { namespace util {
boost::tuple<unsigned,bool> multi_geometry_type::operator() (geometry_container const& geom) const
boost::tuple<unsigned,bool> detail::multi_geometry_type::operator() (geometry_container const& geom) const
{
unsigned type = 0u;
bool collection = false;

View file

@ -173,7 +173,8 @@ xml_tree::xml_tree(std::string const& encoding)
color_grammar(),
expr_grammar(tr_),
path_expr_grammar(),
transform_expr_grammar(expr_grammar)
transform_expr_grammar(expr_grammar),
image_filters_grammar()
{
node_.set_processed(true); //root node is always processed
}

View file

@ -6,16 +6,18 @@ Import ('env')
test_env = env.Clone()
headers = env['CPPPATH']
libraries = copy(env['LIBMAPNIK_LIBS'])
libraries.append('mapnik')
libraries.append('sqlite3')
test_env.Append(CXXFLAGS='-g')
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('*_test.cpp'):
test_program = test_env.Program(cpp_test.replace('.cpp','-bin'), [cpp_test], CPPPATH=headers, LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
test_env_local = test_env.Clone()
name = cpp_test.replace('.cpp','-bin')
source_files = [cpp_test]
if 'csv_parse' in cpp_test:
source_files += glob.glob('../../plugins/input/csv/' + '*.cpp')
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:

View file

@ -0,0 +1,30 @@
#include <boost/version.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
#include "plugins/input/csv/csv_datasource.hpp"
#include <mapnik/params.hpp>
int main( int, char*[] )
{
// test of directly instanciating a datasource
try {
mapnik::parameters params;
params["type"]="csv";
params["file"]="./tests/data/csv/wkt.csv";
csv_datasource ds(params);
BOOST_TEST(true);
} catch (std::exception const& ex) {
BOOST_TEST(false);
std::clog << "threw: " << ex.what() << "\n";
}
if (!::boost::detail::test_errors()) {
std::clog << "C++ CSV parse: \x1b[1;32m✓ \x1b[0m\n";
#if BOOST_VERSION >= 104600
::boost::detail::report_errors_remind().called_report_errors_function = true;
#endif
} else {
return ::boost::report_errors();
}
}

View file

@ -0,0 +1,42 @@
#include <boost/version.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
#include <mapnik/geometry.hpp>
#include <mapnik/geom_util.hpp>
int main( int, char*[] )
{
// reused these for simplicity
double x,y;
// single point
mapnik::geometry_type pt(mapnik::Point);
pt.move_to(10,10);
BOOST_TEST( mapnik::label::centroid(pt, x, y) );
BOOST_TEST( x == 10 );
BOOST_TEST( y == 10 );
// two points
pt.move_to(20,20);
BOOST_TEST( mapnik::label::centroid(pt, x, y) );
BOOST_TEST_EQ( x, 15 );
BOOST_TEST_EQ( y, 15 );
// line with two verticies
mapnik::geometry_type line(mapnik::LineString);
line.move_to(0,0);
line.move_to(50,50);
BOOST_TEST( mapnik::label::centroid(line, x, y) );
BOOST_TEST( x == 25 );
BOOST_TEST( y == 25 );
if (!::boost::detail::test_errors()) {
std::clog << "C++ label algorithms: \x1b[1;32m✓ \x1b[0m\n";
#if BOOST_VERSION >= 104600
::boost::detail::report_errors_remind().called_report_errors_function = true;
#endif
} else {
return ::boost::report_errors();
}
}

View file

@ -0,0 +1,2 @@
x,y,one,two
0,0,one,two,three
1 x,y,one,two
2 0,0,one,two,three

View file

@ -0,0 +1,10 @@
type,GeoJSON
point, "{""type"":""Point"",""coordinates"":[30.0,10.0]}"
linestring, "{""type"":""LineString"",""coordinates"":[[30.0,10.0],[10.0,30.0],[40.0,40.0]]}"
polygon, "{""type"":""Polygon"",""coordinates"":[[[30.0,10.0],[10.0,20.0],[20.0,40.0],[40.0,40.0],[30.0,10.0]]]}"
polygon, "{""type"":""Polygon"",""coordinates"":[[[35.0,10.0],[10.0,20.0],[15.0,40.0],[45.0,45.0],[35.0,10.0]],[[20.0,30.0],[35.0,35.0],[30.0,20.0],[20.0,30.0]]]}"
multipoint, "{""type"":""MultiPoint"",""coordinates"":[[10.0,40.0],[40.0,30.0],[20.0,20.0],[30.0,10.0]]}"
multilinestring, "{""type"":""MultiLineString"",""coordinates"":[[[10.0,10.0],[20.0,20.0],[10.0,40.0]],[[40.0,40.0],[30.0,30.0],[40.0,20.0],[30.0,10.0]]]}"
multipolygon, "{""type"":""MultiPolygon"",""coordinates"":[[[[30.0,20.0],[10.0,40.0],[45.0,40.0],[30.0,20.0]]],[[[15.0,5.0],[40.0,10.0],[10.0,20.0],[5.0,10.0],[15.0,5.0]]]]}"
multipolygon, "{""type"":""MultiPolygon"",""coordinates"":[[[[40.0,40.0],[20.0,45.0],[45.0,30.0],[40.0,40.0]]],[[[20.0,35.0],[45.0,20.0],[30.0,5.0],[10.0,10.0],[10.0,30.0],[20.0,35.0]],[[30.0,20.0],[20.0,25.0],[20.0,15.0],[30.0,20.0]]]]}"
collection, "{""type"":""GeometryCollection"",""geometries"":[{""type"":""Polygon"",""coordinates"":[[[1.0,1.0],[2.0,1.0],[2.0,2.0],[1.0,2.0],[1.0,1.0]]]},{""type"":""Point"",""coordinates"":[2.0,3.0]},{""type"":""LineString"",""coordinates"":[[2.0,3.0],[3.0,4.0]]}]}"
1 type GeoJSON
2 point {"type":"Point","coordinates":[30.0,10.0]}
3 linestring {"type":"LineString","coordinates":[[30.0,10.0],[10.0,30.0],[40.0,40.0]]}
4 polygon {"type":"Polygon","coordinates":[[[30.0,10.0],[10.0,20.0],[20.0,40.0],[40.0,40.0],[30.0,10.0]]]}
5 polygon {"type":"Polygon","coordinates":[[[35.0,10.0],[10.0,20.0],[15.0,40.0],[45.0,45.0],[35.0,10.0]],[[20.0,30.0],[35.0,35.0],[30.0,20.0],[20.0,30.0]]]}
6 multipoint {"type":"MultiPoint","coordinates":[[10.0,40.0],[40.0,30.0],[20.0,20.0],[30.0,10.0]]}
7 multilinestring {"type":"MultiLineString","coordinates":[[[10.0,10.0],[20.0,20.0],[10.0,40.0]],[[40.0,40.0],[30.0,30.0],[40.0,20.0],[30.0,10.0]]]}
8 multipolygon {"type":"MultiPolygon","coordinates":[[[[30.0,20.0],[10.0,40.0],[45.0,40.0],[30.0,20.0]]],[[[15.0,5.0],[40.0,10.0],[10.0,20.0],[5.0,10.0],[15.0,5.0]]]]}
9 multipolygon {"type":"MultiPolygon","coordinates":[[[[40.0,40.0],[20.0,45.0],[45.0,30.0],[40.0,40.0]]],[[[20.0,35.0],[45.0,20.0],[30.0,5.0],[10.0,10.0],[10.0,30.0],[20.0,35.0]],[[30.0,20.0],[20.0,25.0],[20.0,15.0],[30.0,20.0]]]]}
10 collection {"type":"GeometryCollection","geometries":[{"type":"Polygon","coordinates":[[[1.0,1.0],[2.0,1.0],[2.0,2.0],[1.0,2.0],[1.0,1.0]]]},{"type":"Point","coordinates":[2.0,3.0]},{"type":"LineString","coordinates":[[2.0,3.0],[3.0,4.0]]}]}

View file

@ -0,0 +1,10 @@
type,GeoJSON
point, "{\"type\":\"Point\",\"coordinates\":[30.0,10.0]}"
linestring, "{\"type\":\"LineString\",\"coordinates\":[[30.0,10.0],[10.0,30.0],[40.0,40.0]]}"
polygon, "{\"type\":\"Polygon\",\"coordinates\":[[[30.0,10.0],[10.0,20.0],[20.0,40.0],[40.0,40.0],[30.0,10.0]]]}"
polygon, "{\"type\":\"Polygon\",\"coordinates\":[[[35.0,10.0],[10.0,20.0],[15.0,40.0],[45.0,45.0],[35.0,10.0]],[[20.0,30.0],[35.0,35.0],[30.0,20.0],[20.0,30.0]]]}"
multipoint, "{\"type\":\"MultiPoint\",\"coordinates\":[[10.0,40.0],[40.0,30.0],[20.0,20.0],[30.0,10.0]]}"
multilinestring, "{\"type\":\"MultiLineString\",\"coordinates\":[[[10.0,10.0],[20.0,20.0],[10.0,40.0]],[[40.0,40.0],[30.0,30.0],[40.0,20.0],[30.0,10.0]]]}"
multipolygon, "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[30.0,20.0],[10.0,40.0],[45.0,40.0],[30.0,20.0]]],[[[15.0,5.0],[40.0,10.0],[10.0,20.0],[5.0,10.0],[15.0,5.0]]]]}"
multipolygon, "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[40.0,40.0],[20.0,45.0],[45.0,30.0],[40.0,40.0]]],[[[20.0,35.0],[45.0,20.0],[30.0,5.0],[10.0,10.0],[10.0,30.0],[20.0,35.0]],[[30.0,20.0],[20.0,25.0],[20.0,15.0],[30.0,20.0]]]]}"
collection, "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Polygon\",\"coordinates\":[[[1.0,1.0],[2.0,1.0],[2.0,2.0],[1.0,2.0],[1.0,1.0]]]},{\"type\":\"Point\",\"coordinates\":[2.0,3.0]},{\"type\":\"LineString\",\"coordinates\":[[2.0,3.0],[3.0,4.0]]}]}"
Can't render this file because it contains an unexpected character in line 2 and column 21.

View file

@ -0,0 +1,10 @@
type,GeoJSON
point, '{"type":"Point","coordinates":[30.0,10.0]}'
linestring, '{"type":"LineString","coordinates":[[30.0,10.0],[10.0,30.0],[40.0,40.0]]}'
polygon, '{"type":"Polygon","coordinates":[[[30.0,10.0],[10.0,20.0],[20.0,40.0],[40.0,40.0],[30.0,10.0]]]}'
polygon, '{"type":"Polygon","coordinates":[[[35.0,10.0],[10.0,20.0],[15.0,40.0],[45.0,45.0],[35.0,10.0]],[[20.0,30.0],[35.0,35.0],[30.0,20.0],[20.0,30.0]]]}'
multipoint, '{"type":"MultiPoint","coordinates":[[10.0,40.0],[40.0,30.0],[20.0,20.0],[30.0,10.0]]}'
multilinestring, '{"type":"MultiLineString","coordinates":[[[10.0,10.0],[20.0,20.0],[10.0,40.0]],[[40.0,40.0],[30.0,30.0],[40.0,20.0],[30.0,10.0]]]}'
multipolygon, '{"type":"MultiPolygon","coordinates":[[[[30.0,20.0],[10.0,40.0],[45.0,40.0],[30.0,20.0]]],[[[15.0,5.0],[40.0,10.0],[10.0,20.0],[5.0,10.0],[15.0,5.0]]]]}'
multipolygon, '{"type":"MultiPolygon","coordinates":[[[[40.0,40.0],[20.0,45.0],[45.0,30.0],[40.0,40.0]]],[[[20.0,35.0],[45.0,20.0],[30.0,5.0],[10.0,10.0],[10.0,30.0],[20.0,35.0]],[[30.0,20.0],[20.0,25.0],[20.0,15.0],[30.0,20.0]]]]}'
collection, '{"type":"GeometryCollection","geometries":[{"type":"Polygon","coordinates":[[[1.0,1.0],[2.0,1.0],[2.0,2.0],[1.0,2.0],[1.0,1.0]]]},{"type":"Point","coordinates":[2.0,3.0]},{"type":"LineString","coordinates":[[2.0,3.0],[3.0,4.0]]}]}'
Can't render this file because it contains an unexpected character in line 2 and column 20.

View file

@ -0,0 +1,2 @@
x,y,one,two,three
0,0
1 x,y,one,two,three
2 0,0

View file

@ -3,15 +3,15 @@
<Style name="test 1">
<Rule>
<Filter>[foo]='bar'</Filter>
<PointSymbolizer file="../data/images/foobar.png"/>
<PointSymbolizer file="../data/images/dummy.png"/>
</Rule>
<Rule>
<ElseFilter/>
<PointSymbolizer file="../data/images/else.png"/>
<PointSymbolizer file="../data/images/dummy.png"/>
</Rule>
<Rule>
<AlsoFilter/>
<PointSymbolizer file="../data/images/also.png"/>
<PointSymbolizer file="../data/images/dummy.png"/>
</Rule>
</Style>
</Map>

View file

@ -0,0 +1,20 @@
<Map>
<Style name="test">
<Rule>
<Filter>[filename]='dummy.png'</Filter>
<PointSymbolizer file="../../[path1]/[path2]/[filename]"/>
</Rule>
</Style>
<Layer name="layer">
<StyleName>test</StyleName>
<Datasource>
<Parameter name="inline">
x,y,path1,path2,filename
0,0,data,images,dummy.png
1,1,data,images,dummy.png
</Parameter>
<Parameter name="type">csv</Parameter>
</Datasource>
</Layer>
</Map>

View file

@ -32,11 +32,6 @@
<TextSymbolizer size="10" dy="20" face-name="DejaVu Sans Book" halo-radius="1">[name] + ' (jpg)'</TextSymbolizer>
<PointSymbolizer file="../images/dummy.jpg"/>
</Rule>
<Rule>
<ElseFilter/>
<TextSymbolizer size="10" dy="20" face-name="DejaVu Sans Book" halo-radius="1">[name]</TextSymbolizer>
<PointSymbolizer file="../images/bogus_will_fail.png"/>
</Rule>
</Style>
<Layer name="point" srs="+init=epsg:4326">

View file

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

View file

@ -141,7 +141,6 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(ds.fields(),['type','WKT'])
eq_(ds.field_types(),['str','str'])
fs = ds.all_features()
#import pdb;pdb.set_trace()
eq_(len(fs[0].geometries()),1)
eq_(fs[0].geometries()[0].type(),mapnik.DataGeometryType.Point)
eq_(len(fs[1].geometries()),1)
@ -150,9 +149,6 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
eq_(fs[2].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
eq_(len(fs[3].geometries()),1) # one geometry, two parts
eq_(fs[3].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
# tests assuming we want to flatten geometries
# ideally we should not have to:
# https://github.com/mapnik/mapnik/issues?labels=multigeom+robustness&sort=created&direction=desc&state=open&page=1
eq_(len(fs[4].geometries()),4)
eq_(fs[4].geometries()[0].type(),mapnik.DataGeometryType.Point)
eq_(len(fs[5].geometries()),2)
@ -363,6 +359,64 @@ if 'csv' in mapnik.DatasourceCache.instance().plugin_names():
feat = fs.next()
eq_(feat['Name'],u"Winthrop, WA")
def validate_geojson_datasource(ds):
eq_(len(ds.fields()),2)
eq_(ds.fields(),['type','GeoJSON'])
eq_(ds.field_types(),['str','str'])
fs = ds.all_features()
eq_(len(fs[0].geometries()),1)
eq_(fs[0].geometries()[0].type(),mapnik.DataGeometryType.Point)
eq_(len(fs[1].geometries()),1)
eq_(fs[1].geometries()[0].type(),mapnik.DataGeometryType.LineString)
eq_(len(fs[2].geometries()),1)
eq_(fs[2].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
eq_(len(fs[3].geometries()),1) # one geometry, two parts
eq_(fs[3].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
eq_(len(fs[4].geometries()),4)
eq_(fs[4].geometries()[0].type(),mapnik.DataGeometryType.Point)
eq_(len(fs[5].geometries()),2)
eq_(fs[5].geometries()[0].type(),mapnik.DataGeometryType.LineString)
eq_(len(fs[6].geometries()),2)
eq_(fs[6].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
eq_(len(fs[7].geometries()),2)
eq_(fs[7].geometries()[0].type(),mapnik.DataGeometryType.Polygon)
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Collection)
eq_(desc['name'],'csv')
eq_(desc['type'],mapnik.DataType.Vector)
eq_(desc['encoding'],'utf-8')
def test_json_field1(**kwargs):
ds = get_csv_ds('geojson_double_quote_escape.csv')
validate_geojson_datasource(ds)
def test_json_field2(**kwargs):
ds = get_csv_ds('geojson_single_quote.csv')
validate_geojson_datasource(ds)
def test_json_field3(**kwargs):
ds = get_csv_ds('geojson_2x_double_quote_filebakery_style.csv')
validate_geojson_datasource(ds)
def test_that_blank_undelimited_rows_are_still_parsed(**kwargs):
ds = get_csv_ds('more_headers_than_column_values.csv')
eq_(len(ds.fields()),5)
eq_(ds.fields(),['x','y','one', 'two','three'])
eq_(ds.field_types(),['int','int','str','str','str'])
fs = ds.featureset()
feat = fs.next()
eq_(feat['x'],0)
eq_(feat['y'],0)
eq_(feat['one'],'')
eq_(feat['two'],'')
eq_(feat['three'],'')
desc = ds.describe()
eq_(desc['geometry_type'],mapnik.DataGeometryType.Point)
@raises(RuntimeError)
def test_that_fewer_headers_than_rows_throws(**kwargs):
# this has invalid header # so throw
ds = get_csv_ds('more_column_values_than_headers.csv')
if __name__ == "__main__":
setup()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -0,0 +1,27 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from nose.tools import *
import mapnik
# Map initialization
def test_layer_init():
l = mapnik.Layer('test')
eq_(l.name,'test')
eq_(l.srs,'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
eq_(l.envelope(),mapnik.Box2d())
eq_(l.clear_label_cache,False)
eq_(l.cache_features,False)
eq_(l.visible(1),True)
eq_(l.active,True)
eq_(l.datasource,None)
eq_(l.queryable,False)
eq_(l.minzoom,0.0)
eq_(l.maxzoom > 1e+6,True)
eq_(l.group_by,"")
eq_(l.maximum_extent,None)
eq_(l.buffer_size,0.0)
eq_(len(l.styles),0)
if __name__ == "__main__":
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -29,77 +29,78 @@ def test_map_query_throw3():
m = mapnik.Map(256,256)
m.query_point(0,0,0)
# map has never been zoomed (even with data)
@raises(RuntimeError)
def test_map_query_throw4():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/agg_poly_gamma_map.xml')
m.query_point(0,0,0)
# invalid coords in general (do not intersect)
@raises(RuntimeError)
def test_map_query_throw5():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/agg_poly_gamma_map.xml')
m.zoom_all()
m.query_point(0,9999999999999999,9999999999999999)
# invalid coords for back projecting
@raises(RuntimeError)
def test_map_query_throw6():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
wgs84_bounds = mapnik.Box2d(-180,-90,180,90)
m.maximum_extent = wgs84_bounds
m.zoom_all()
m.query_point(0,-180,-90)
def test_map_query_works1():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
fs = m.query_point(0,-11012435.5376, 4599674.6134) # somewhere in kansas
feat = fs.next()
eq_(feat.attributes['NAME_FORMA'],u'United States of America')
def test_map_query_works2():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
wgs84_bounds = mapnik.Box2d(-179.999999975,-85.0511287776,179.999999975,85.0511287776)
m.maximum_extent = wgs84_bounds
# caution - will go square due to evil aspect_fix_mode backhandedness
m.zoom_all()
#mapnik.render_to_file(m,'works2.png')
# valid that aspec_fix_mode modified the bbox
eq_(m.envelope(),mapnik.Box2d(-179.999999975,-179.999999975,179.999999975,179.999999975))
fs = m.query_point(0,-98.9264, 38.1432) # somewhere in kansas
feat = fs.next()
eq_(feat.attributes['NAME'],u'United States')
def test_map_query_in_pixels_works1():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
fs = m.query_map_point(0,55,100) # somewhere in middle of us
feat = fs.next()
eq_(feat.attributes['NAME_FORMA'],u'United States of America')
def test_map_query_in_pixels_works2():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
wgs84_bounds = mapnik.Box2d(-179.999999975,-85.0511287776,179.999999975,85.0511287776)
m.maximum_extent = wgs84_bounds
# caution - will go square due to evil aspect_fix_mode backhandedness
m.zoom_all()
# valid that aspec_fix_mode modified the bbox
eq_(m.envelope(),mapnik.Box2d(-179.999999975,-179.999999975,179.999999975,179.999999975))
fs = m.query_map_point(0,55,100) # somewhere in middle of us
feat = fs.next()
eq_(feat.attributes['NAME'],u'United States')
if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
# map has never been zoomed (even with data)
@raises(RuntimeError)
def test_map_query_throw4():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/agg_poly_gamma_map.xml')
m.query_point(0,0,0)
# invalid coords in general (do not intersect)
@raises(RuntimeError)
def test_map_query_throw5():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/agg_poly_gamma_map.xml')
m.zoom_all()
m.query_point(0,9999999999999999,9999999999999999)
# invalid coords for back projecting
@raises(RuntimeError)
def test_map_query_throw6():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
wgs84_bounds = mapnik.Box2d(-180,-90,180,90)
m.maximum_extent = wgs84_bounds
m.zoom_all()
m.query_point(0,-180,-90)
def test_map_query_works1():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
fs = m.query_point(0,-11012435.5376, 4599674.6134) # somewhere in kansas
feat = fs.next()
eq_(feat.attributes['NAME_FORMA'],u'United States of America')
def test_map_query_works2():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
wgs84_bounds = mapnik.Box2d(-179.999999975,-85.0511287776,179.999999975,85.0511287776)
m.maximum_extent = wgs84_bounds
# caution - will go square due to evil aspect_fix_mode backhandedness
m.zoom_all()
#mapnik.render_to_file(m,'works2.png')
# valid that aspec_fix_mode modified the bbox
eq_(m.envelope(),mapnik.Box2d(-179.999999975,-179.999999975,179.999999975,179.999999975))
fs = m.query_point(0,-98.9264, 38.1432) # somewhere in kansas
feat = fs.next()
eq_(feat.attributes['NAME'],u'United States')
def test_map_query_in_pixels_works1():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
fs = m.query_map_point(0,55,100) # somewhere in middle of us
feat = fs.next()
eq_(feat.attributes['NAME_FORMA'],u'United States of America')
def test_map_query_in_pixels_works2():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
wgs84_bounds = mapnik.Box2d(-179.999999975,-85.0511287776,179.999999975,85.0511287776)
m.maximum_extent = wgs84_bounds
# caution - will go square due to evil aspect_fix_mode backhandedness
m.zoom_all()
# valid that aspec_fix_mode modified the bbox
eq_(m.envelope(),mapnik.Box2d(-179.999999975,-179.999999975,179.999999975,179.999999975))
fs = m.query_map_point(0,55,100) # somewhere in middle of us
feat = fs.next()
eq_(feat.attributes['NAME'],u'United States')
if __name__ == "__main__":
setup()

View file

@ -14,12 +14,42 @@ def setup():
# from another directory we need to chdir()
os.chdir(execution_path('.'))
# Tests that exercise the functionality of Mapnik classes.
def test_line_pattern():
s = mapnik.LinePatternSymbolizer(mapnik.PathExpression('../data/images/dummy.png'))
eq_(s.filename, '../data/images/dummy.png')
eq_(s.smooth,0.0)
eq_(s.transform,'')
eq_(s.comp_op,mapnik.CompositeOp.src_over)
eq_(s.clip,True)
# LineSymbolizer initialization
def test_line_symbolizer_init():
def test_line_symbolizer():
s = mapnik.LineSymbolizer()
eq_(s.rasterizer, mapnik.line_rasterizer.FULL)
eq_(s.smooth,0.0)
eq_(s.comp_op,mapnik.CompositeOp.src_over)
eq_(s.clip,True)
eq_(s.stroke.width, 1)
eq_(s.stroke.opacity, 1)
eq_(s.stroke.color, mapnik.Color('black'))
eq_(s.stroke.line_cap, mapnik.line_cap.BUTT_CAP)
eq_(s.stroke.line_join, mapnik.line_join.MITER_JOIN)
l = mapnik.LineSymbolizer(mapnik.Color('blue'), 5.0)
eq_(l.stroke.width, 5)
eq_(l.stroke.opacity, 1)
eq_(l.stroke.color, mapnik.Color('blue'))
eq_(l.stroke.line_cap, mapnik.line_cap.BUTT_CAP)
eq_(l.stroke.line_join, mapnik.line_join.MITER_JOIN)
s = mapnik.Stroke(mapnik.Color('blue'), 5.0)
l = mapnik.LineSymbolizer(s)
eq_(l.stroke.width, 5)
eq_(l.stroke.opacity, 1)
eq_(l.stroke.color, mapnik.Color('blue'))
eq_(l.stroke.line_cap, mapnik.line_cap.BUTT_CAP)
eq_(l.stroke.line_join, mapnik.line_join.MITER_JOIN)
def test_line_symbolizer_stroke_reference():
l = mapnik.LineSymbolizer(mapnik.Color('green'),0.1)
@ -30,9 +60,54 @@ def test_line_symbolizer_stroke_reference():
eq_(l.stroke.opacity,1.0)
assert_almost_equal(l.stroke.width,0.1)
# ShieldSymbolizer initialization
def test_shieldsymbolizer_init():
# https://github.com/mapnik/mapnik/issues/1427
def test_stroke_dash_api():
stroke = mapnik.Stroke()
dashes = [(1.0,1.0)]
stroke.dasharray = dashes
eq_(stroke.dasharray, dashes)
stroke.add_dash(.1,.1)
dashes.append((.1,.1))
eq_(stroke.dasharray, dashes)
def test_text_symbolizer():
s = mapnik.TextSymbolizer()
eq_(s.comp_op,mapnik.CompositeOp.src_over)
eq_(s.clip,True)
# https://github.com/mapnik/mapnik/issues/1420
eq_(s.text_transform, mapnik.text_transform.NONE)
# https://github.com/mapnik/mapnik/issues/1427
eq_(s.wrap_char,ord(' '))
eq_(s.wrap_character,ord(' '))
s.wrap_char = ord('\n')
eq_(s.wrap_char,ord('\n'))
eq_(s.wrap_character,ord('\n'))
eq_(s.format.wrap_character,ord('\n'))
s.wrap_character = ord('\r')
eq_(s.wrap_char,ord('\r'))
eq_(s.wrap_character,ord('\r'))
eq_(s.format.wrap_character,ord('\r'))
s.format.wrap_character = ord(' ')
eq_(s.wrap_char,ord(' '))
eq_(s.wrap_character,ord(' '))
eq_(s.format.wrap_character,ord(' '))
# old args required method
ts = mapnik.TextSymbolizer(mapnik.Expression('[Field_Name]'), 'Font Name', 8, mapnik.Color('black'))
# eq_(str(ts.name), str(mapnik2.Expression('[Field_Name]'))) name field is no longer supported
eq_(ts.format.face_name, 'Font Name')
eq_(ts.format.text_size, 8)
eq_(ts.format.fill, mapnik.Color('black'))
eq_(ts.properties.label_placement, mapnik.label_placement.POINT_PLACEMENT)
eq_(ts.properties.horizontal_alignment, mapnik.horizontal_alignment.AUTO)
def test_shield_symbolizer_init():
s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../data/images/dummy.png'))
eq_(s.comp_op,mapnik.CompositeOp.src_over)
eq_(s.clip,True)
eq_(s.displacement, (0.0,0.0))
eq_(s.allow_overlap, False)
eq_(s.avoid_edges, False)
@ -89,34 +164,31 @@ def test_shieldsymbolizer_init():
#def test_shieldsymbolizer_missing_image():
# s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../#data/images/broken.png'))
# ShieldSymbolizer modification
def test_shieldsymbolizer_modify():
def test_shield_symbolizer_modify():
s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../data/images/dummy.png'))
# transform expression
s.transform = "rotate(30+[a]) scale(2*[sx] [sy])"
eq_(s.transform, "rotate((30+[a])) scale(2*[sx], [sy])")
def check_transform(expr, expect_str=None):
s.transform = expr
eq_(s.transform, expr if expect_str is None else expect_str)
check_transform("matrix(1 2 3 4 5 6)", "matrix(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)")
check_transform("matrix(1, 2, 3, 4, 5, 6 +7)", "matrix(1, 2, 3, 4, 5, (6+7))")
check_transform("rotate([a])")
check_transform("rotate([a] -2)", "rotate(([a]-2))")
check_transform("rotate([a] -2 -3)", "rotate([a], -2.0, -3.0)")
check_transform("rotate([a] -2 -3 -4)", "rotate(((([a]-2)-3)-4))")
check_transform("rotate([a] -2, 3, 4)", "rotate(([a]-2), 3, 4)")
check_transform("translate([tx]) rotate([a])")
check_transform("scale([sx], [sy]/2)")
# TODO check expected failures
def test_polygonsymbolizer_init():
p = mapnik.PolygonSymbolizer()
eq_(p.fill, mapnik.Color('gray'))
eq_(p.fill_opacity, 1)
eq_(p.placement, mapnik.point_placement.CENTROID)
p = mapnik.PolygonSymbolizer(mapnik.Color('blue'))
p.placement = mapnik.point_placement.INTERIOR
eq_(p.fill, mapnik.Color('blue'))
eq_(p.fill_opacity, 1)
eq_(p.placement, mapnik.point_placement.INTERIOR)
# PointSymbolizer initialization
def test_pointsymbolizer_init():
def test_point_symbolizer():
p = mapnik.PointSymbolizer()
eq_(p.allow_overlap, False)
eq_(p.opacity,1)
eq_(p.filename,'')
eq_(p.transform,'')
eq_(p.opacity,1.0)
eq_(p.allow_overlap,False)
eq_(p.ignore_placement,False)
eq_(p.comp_op,mapnik.CompositeOp.src_over)
eq_(p.placement, mapnik.point_placement.CENTROID)
p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/dummy.png"))
@ -130,9 +202,7 @@ def test_pointsymbolizer_init():
eq_(p.ignore_placement,True)
eq_(p.placement, mapnik.point_placement.INTERIOR)
# MarkersSymbolizer initialization
def test_markersymbolizer_init():
def test_markers_symbolizer():
p = mapnik.MarkersSymbolizer()
eq_(p.allow_overlap, False)
eq_(p.opacity,1.0)
@ -145,6 +215,10 @@ def test_markersymbolizer_init():
eq_(p.max_error,0.2)
eq_(p.width,None)
eq_(p.height,None)
eq_(p.transform,'')
eq_(p.clip,True)
eq_(p.comp_op,mapnik.CompositeOp.src_over)
p.width = mapnik.Expression('12')
p.height = mapnik.Expression('12')
@ -170,6 +244,12 @@ def test_markersymbolizer_init():
eq_(p.opacity, 0.5)
eq_(p.fill_opacity, 0.5)
#https://github.com/mapnik/mapnik/issues/1285
#https://github.com/mapnik/mapnik/issues/1427
p.marker_type = 'arrow'
eq_(p.marker_type,'shape://arrow')
eq_(p.filename,'shape://arrow')
# PointSymbolizer missing image file
# images paths are now PathExpressions are evaluated at runtime
@ -178,10 +258,11 @@ def test_markersymbolizer_init():
#def test_pointsymbolizer_missing_image():
# p = mapnik.PointSymbolizer(mapnik.PathExpression("../data/images/broken.png"))
# PolygonSymbolizer initialization
def test_polygonsymbolizer_init():
def test_polygon_symbolizer():
p = mapnik.PolygonSymbolizer()
eq_(p.smooth,0.0)
eq_(p.comp_op,mapnik.CompositeOp.src_over)
eq_(p.clip,True)
eq_(p.fill, mapnik.Color('gray'))
eq_(p.fill_opacity, 1)
@ -190,7 +271,13 @@ def test_polygonsymbolizer_init():
eq_(p.fill, mapnik.Color('blue'))
eq_(p.fill_opacity, 1)
# Stroke initialization
def test_building_symbolizer_init():
p = mapnik.BuildingSymbolizer()
eq_(p.fill, mapnik.Color('gray'))
eq_(p.fill_opacity, 1)
eq_(p.height,None)
def test_stroke_init():
s = mapnik.Stroke()
@ -211,7 +298,6 @@ def test_stroke_init():
eq_(s.line_cap, mapnik.line_cap.BUTT_CAP)
eq_(s.line_join, mapnik.line_join.MITER_JOIN)
# Stroke dashes
def test_stroke_dash_arrays():
s = mapnik.Stroke()
s.add_dash(1,2)
@ -220,58 +306,6 @@ def test_stroke_dash_arrays():
eq_(s.get_dashes(), [(1,2),(3,4),(5,6)])
# LineSymbolizer initialization
def test_linesymbolizer_init():
l = mapnik.LineSymbolizer()
eq_(l.stroke.width, 1)
eq_(l.stroke.opacity, 1)
eq_(l.stroke.color, mapnik.Color('black'))
eq_(l.stroke.line_cap, mapnik.line_cap.BUTT_CAP)
eq_(l.stroke.line_join, mapnik.line_join.MITER_JOIN)
l = mapnik.LineSymbolizer(mapnik.Color('blue'), 5.0)
eq_(l.stroke.width, 5)
eq_(l.stroke.opacity, 1)
eq_(l.stroke.color, mapnik.Color('blue'))
eq_(l.stroke.line_cap, mapnik.line_cap.BUTT_CAP)
eq_(l.stroke.line_join, mapnik.line_join.MITER_JOIN)
s = mapnik.Stroke(mapnik.Color('blue'), 5.0)
l = mapnik.LineSymbolizer(s)
eq_(l.stroke.width, 5)
eq_(l.stroke.opacity, 1)
eq_(l.stroke.color, mapnik.Color('blue'))
eq_(l.stroke.line_cap, mapnik.line_cap.BUTT_CAP)
eq_(l.stroke.line_join, mapnik.line_join.MITER_JOIN)
# TextSymbolizer initialization
def test_textsymbolizer_init():
ts = mapnik.TextSymbolizer(mapnik.Expression('[Field_Name]'), 'Font Name', 8, mapnik.Color('black'))
# eq_(str(ts.name), str(mapnik2.Expression('[Field_Name]'))) name field is no longer supported
eq_(ts.format.face_name, 'Font Name')
eq_(ts.format.text_size, 8)
eq_(ts.format.fill, mapnik.Color('black'))
eq_(ts.properties.label_placement, mapnik.label_placement.POINT_PLACEMENT)
eq_(ts.properties.horizontal_alignment, mapnik.horizontal_alignment.AUTO)
# Map initialization
def test_layer_init():
l = mapnik.Layer('test')
eq_(l.name,'test')
eq_(l.envelope(),mapnik.Box2d())
eq_(l.clear_label_cache,False)
eq_(l.cache_features,False)
eq_(l.visible(1),True)
eq_(l.active,True)
eq_(l.datasource,None)
eq_(l.queryable,False)
eq_(l.srs,'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')
# Map initialization
def test_map_init():
m = mapnik.Map(256, 256)
@ -387,7 +421,6 @@ def test_color_init():
eq_(c.to_hex_string(), '#004080c0')
# Color equality
def test_color_equality():
c1 = mapnik.Color('blue')
@ -442,7 +475,6 @@ def test_color_equality():
eq_(c2, mapnik.Color('lime'))
eq_(c3, mapnik.Color(0,0,255,128))
# Rule initialization
def test_rule_init():
min_scale = 5
max_scale = 10
@ -499,153 +531,6 @@ def test_rule_init():
eq_(r.has_else(), False)
eq_(r.has_also(), False)
# Coordinate initialization
def test_coord_init():
c = mapnik.Coord(100, 100)
eq_(c.x, 100)
eq_(c.y, 100)
# Coordinate multiplication
def test_coord_multiplication():
c = mapnik.Coord(100, 100)
c *= 2
eq_(c.x, 200)
eq_(c.y, 200)
# Box2d initialization
def test_envelope_init():
e = mapnik.Box2d(100, 100, 200, 200)
assert_true(e.contains(100, 100))
assert_true(e.contains(100, 200))
assert_true(e.contains(200, 200))
assert_true(e.contains(200, 100))
assert_true(e.contains(e.center()))
assert_false(e.contains(99.9, 99.9))
assert_false(e.contains(99.9, 200.1))
assert_false(e.contains(200.1, 200.1))
assert_false(e.contains(200.1, 99.9))
eq_(e.width(), 100)
eq_(e.height(), 100)
eq_(e.minx, 100)
eq_(e.miny, 100)
eq_(e.maxx, 200)
eq_(e.maxy, 200)
eq_(e[0],100)
eq_(e[1],100)
eq_(e[2],200)
eq_(e[3],200)
eq_(e[0],e[-4])
eq_(e[1],e[-3])
eq_(e[2],e[-2])
eq_(e[3],e[-1])
c = e.center()
eq_(c.x, 150)
eq_(c.y, 150)
# Box2d static initialization
def test_envelope_static_init():
e = mapnik.Box2d.from_string('100 100 200 200')
e2 = mapnik.Box2d.from_string('100,100,200,200')
e3 = mapnik.Box2d.from_string('100 , 100 , 200 , 200')
eq_(e,e2)
eq_(e,e3)
assert_true(e.contains(100, 100))
assert_true(e.contains(100, 200))
assert_true(e.contains(200, 200))
assert_true(e.contains(200, 100))
assert_true(e.contains(e.center()))
assert_false(e.contains(99.9, 99.9))
assert_false(e.contains(99.9, 200.1))
assert_false(e.contains(200.1, 200.1))
assert_false(e.contains(200.1, 99.9))
eq_(e.width(), 100)
eq_(e.height(), 100)
eq_(e.minx, 100)
eq_(e.miny, 100)
eq_(e.maxx, 200)
eq_(e.maxy, 200)
eq_(e[0],100)
eq_(e[1],100)
eq_(e[2],200)
eq_(e[3],200)
eq_(e[0],e[-4])
eq_(e[1],e[-3])
eq_(e[2],e[-2])
eq_(e[3],e[-1])
c = e.center()
eq_(c.x, 150)
eq_(c.y, 150)
# Box2d multiplication
def test_envelope_multiplication():
e = mapnik.Box2d(100, 100, 200, 200)
e *= 2
assert_true(e.contains(50, 50))
assert_true(e.contains(50, 250))
assert_true(e.contains(250, 250))
assert_true(e.contains(250, 50))
assert_false(e.contains(49.9, 49.9))
assert_false(e.contains(49.9, 250.1))
assert_false(e.contains(250.1, 250.1))
assert_false(e.contains(250.1, 49.9))
assert_true(e.contains(e.center()))
eq_(e.width(), 200)
eq_(e.height(), 200)
eq_(e.minx, 50)
eq_(e.miny, 50)
eq_(e.maxx, 250)
eq_(e.maxy, 250)
c = e.center()
eq_(c.x, 150)
eq_(c.y, 150)
# Box2d clipping
def test_envelope_clipping():
e1 = mapnik.Box2d(-180,-90,180,90)
e2 = mapnik.Box2d(-120,40,-110,48)
e1.clip(e2)
eq_(e1,e2)
# madagascar in merc
e1 = mapnik.Box2d(4772116.5490, -2744395.0631, 5765186.4203, -1609458.0673)
e2 = mapnik.Box2d(5124338.3753, -2240522.1727, 5207501.8621, -2130452.8520)
e1.clip(e2)
eq_(e1,e2)
# nz in lon/lat
e1 = mapnik.Box2d(163.8062, -47.1897, 179.3628, -33.9069)
e2 = mapnik.Box2d(173.7378, -39.6395, 174.4849, -38.9252)
e1.clip(e2)
eq_(e1,e2)
if __name__ == "__main__":
setup()
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -28,6 +28,7 @@ if 'ogr' in mapnik.DatasourceCache.instance().plugin_names():
def test_shapefile_properties():
# NOTE: encoding is latin1 but gdal >= 1.9 should now expose utf8 encoded features
# See SHAPE_ENCODING for overriding: http://gdal.org/ogr/drv_shapefile.html
# So: failure for the NOM_FR field is expected for older gdal
ds = mapnik.Ogr(file='../../demo/data/boundaries.shp',layer_by_index=0)
f = ds.features_at_point(ds.envelope().center()).features[0]
eq_(ds.geometry_type(),mapnik.DataGeometryType.Polygon)

View file

@ -8,13 +8,6 @@ import sys
from utilities import execution_path
from nose.tools import *
try:
from shapely.geometry import Point
have_shapely = True
except ImportError:
print('Shapely is required for python data source test.')
have_shapely = False
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
@ -27,18 +20,14 @@ class PointDatasource(mapnik.PythonDatasource):
)
def features(self, query):
return mapnik.PythonDatasource.wkb_features(
return mapnik.PythonDatasource.wkt_features(
keys = ('label',),
features = (
( Point(5,6).wkb, { 'label': 'foo-bar'} ),
( Point(60,50).wkb, { 'label': 'buzz-quux'} ),
( 'POINT (5 6)', { 'label': 'foo-bar'} ),
( 'POINT (60 50)', { 'label': 'buzz-quux'} ),
)
)
def box2d_to_shapely(box):
import shapely.geometry
return shapely.geometry.box(box.minx, box.miny, box.maxx, box.maxy)
class ConcentricCircles(object):
def __init__(self, centre, bounds, step=1):
self.centre = centre
@ -53,20 +42,31 @@ class ConcentricCircles(object):
bounds = self.container.bounds
step = self.container.step
if centre.within(bounds):
self.radius = step
else:
self.radius = math.ceil(centre.distance(bounds) / float(step)) * step
self.radius = step
def next(self):
circle = self.container.centre.buffer(self.radius)
self.radius += self.container.step
points = []
for alpha in xrange(0, 361, 5):
x = math.sin(math.radians(alpha)) * self.radius + self.container.centre[0]
y = math.cos(math.radians(alpha)) * self.radius + self.container.centre[1]
points.append('%s %s' % (x,y))
circle = 'POLYGON ((' + ','.join(points) + '))'
# has the circle grown so large that the boundary is entirely within it?
if circle.contains(self.container.bounds):
tl = (self.container.bounds.maxx, self.container.bounds.maxy)
tr = (self.container.bounds.maxx, self.container.bounds.maxy)
bl = (self.container.bounds.minx, self.container.bounds.miny)
br = (self.container.bounds.minx, self.container.bounds.miny)
def within_circle(p):
delta_x = p[0] - self.container.centre[0]
delta_y = p[0] - self.container.centre[0]
return delta_x*delta_x + delta_y*delta_y < self.radius*self.radius
if all(within_circle(p) for p in (tl,tr,bl,br)):
raise StopIteration()
return ( circle.wkb, { } )
self.radius += self.container.step
return ( circle, { } )
def __iter__(self):
return ConcentricCircles.Iterator(self)
@ -87,16 +87,14 @@ class CirclesDatasource(mapnik.PythonDatasource):
self.step = step
def features(self, query):
# Get the query bounding-box as a shapely bounding box
bounding_box = box2d_to_shapely(query.bbox)
centre = Point(self.centre_x, self.centre_y)
centre = (self.centre_x, self.centre_y)
return mapnik.PythonDatasource.wkb_features(
return mapnik.PythonDatasource.wkt_features(
keys = (),
features = ConcentricCircles(centre, bounding_box, self.step)
features = ConcentricCircles(centre, query.bbox, self.step)
)
if 'python' in mapnik.DatasourceCache.instance().plugin_names() and have_shapely:
if 'python' in mapnik.DatasourceCache.instance().plugin_names():
# make sure we can load from ourself as a module
sys.path.append(execution_path('.'))
@ -129,7 +127,7 @@ if 'python' in mapnik.DatasourceCache.instance().plugin_names() and have_shapely
def test_python_point_rendering():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/python_point_datasource.xml')
mapnik.load_map(m,'../data/python_plugin/python_point_datasource.xml')
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
@ -142,7 +140,7 @@ if 'python' in mapnik.DatasourceCache.instance().plugin_names() and have_shapely
def test_python_circle_rendering():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/python_circle_datasource.xml')
mapnik.load_map(m,'../data/python_plugin/python_circle_datasource.xml')
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)

View file

@ -9,79 +9,80 @@ def setup():
# from another directory we need to chdir()
os.chdir(execution_path('.'))
@raises(RuntimeError)
def test_zoom_all_will_fail():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
m.zoom_all()
def test_zoom_all_will_work_with_max_extent():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
eq_(m.envelope(),merc_bounds)
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.zoom_to_box(merc_bounds)
eq_(m.envelope(),merc_bounds)
if 'shape' in mapnik.DatasourceCache.instance().plugin_names():
@raises(RuntimeError)
def test_zoom_all_will_fail():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
m.zoom_all()
def test_zoom_all_will_work_with_max_extent():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
eq_(m.envelope(),merc_bounds)
def test_visual_zoom_all_rendering1():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-wgs842merc-reprojection-render.png'
expected = 'images/support/mapnik-wgs842merc-reprojection-render.png'
im.save(actual)
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
def test_visual_zoom_all_rendering2():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-merc2wgs84-reprojection-render.png'
expected = 'images/support/mapnik-merc2wgs84-reprojection-render.png'
im.save(actual)
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
# maximum-extent read from map.xml
def test_visual_zoom_all_rendering3():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/bounds_clipping.xml')
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-merc2merc-reprojection-render1.png'
expected = 'images/support/mapnik-merc2merc-reprojection-render1.png'
im.save(actual)
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
# no maximum-extent
def test_visual_zoom_all_rendering4():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/bounds_clipping.xml')
m.maximum_extent = None
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-merc2merc-reprojection-render2.png'
expected = 'images/support/mapnik-merc2merc-reprojection-render2.png'
im.save(actual)
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.zoom_to_box(merc_bounds)
eq_(m.envelope(),merc_bounds)
def test_visual_zoom_all_rendering1():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-wgs842merc-reprojection-render.png'
expected = 'images/support/mapnik-wgs842merc-reprojection-render.png'
im.save(actual)
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
def test_visual_zoom_all_rendering2():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-merc2wgs84-reprojection-render.png'
expected = 'images/support/mapnik-merc2wgs84-reprojection-render.png'
im.save(actual)
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
# maximum-extent read from map.xml
def test_visual_zoom_all_rendering3():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/bounds_clipping.xml')
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-merc2merc-reprojection-render1.png'
expected = 'images/support/mapnik-merc2merc-reprojection-render1.png'
im.save(actual)
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
# no maximum-extent
def test_visual_zoom_all_rendering4():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/bounds_clipping.xml')
m.maximum_extent = None
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-merc2merc-reprojection-render2.png'
expected = 'images/support/mapnik-merc2merc-reprojection-render2.png'
im.save(actual)
expected_im = mapnik.Image.open(expected)
eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
if __name__ == "__main__":
setup()

View file

@ -0,0 +1,17 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
from nose.tools import *
import mapnik
def test_style_init():
s = mapnik.Style()
eq_(s.filter_mode,mapnik.filter_mode.ALL)
eq_(len(s.rules),0)
eq_(s.opacity,1)
eq_(s.comp_op,None)
eq_(s.image_filters,"")
if __name__ == "__main__":
[eval(run)() for run in dir() if 'test_' in run]

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -5,8 +5,8 @@
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
<StyleName>My Style</StyleName>
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">../data/points.shp</Parameter>
<Parameter name="type">osm</Parameter>
<Parameter name="file">../data/points.osm</Parameter>
</Datasource>
</Layer>

View file

@ -5,8 +5,8 @@
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
<StyleName>My Style</StyleName>
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">../data/points.shp</Parameter>
<Parameter name="type">osms</Parameter>
<Parameter name="file">../data/points.osm</Parameter>
</Datasource>
</Layer>

View file

@ -5,8 +5,8 @@
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
<StyleName>My Style</StyleName>
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">../data/points.shp</Parameter>
<Parameter name="type">osm</Parameter>
<Parameter name="file">../data/points.osm</Parameter>
</Datasource>
</Layer>

View file

@ -5,8 +5,8 @@
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
<StyleName>My Style</StyleName>
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">../data/points.shp</Parameter>
<Parameter name="type">osm</Parameter>
<Parameter name="file">../data/points.osm</Parameter>
</Datasource>
</Layer>

View file

@ -5,8 +5,8 @@
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
<StyleName>My Style</StyleName>
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">../data/points.shp</Parameter>
<Parameter name="type">osm</Parameter>
<Parameter name="file">../data/points.osm</Parameter>
</Datasource>
</Layer>

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